动态代理

JDK 原生动态代理

java原生支持,不需要外部依赖,但必须基于接口实现动态代理
Proxy :所有动态代理的父类,提供静态方法创建动态代理的class对象和实例
InvocationHandler: 业务增强

image.png

CGLIB

通过继承的方式实现,,无论目标对象有没有实现接口都可以代理,但是无法处理final的情况
Enhancer.setSuperClass
enhancer.setCallback(MethodInteerceptor)
Object = enhancer.create()
object.getUser();

image.png

线程池

  • 各个参数含义
  • 提交任务

//参数初始化
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心线程数量大小
private static final int corePoolSize = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//线程池最大容纳线程数
private static final int maximumPoolSize = CPU_COUNT * 2 + 1;
//线程空闲后的存活时长
private static final int keepAliveTime = 30;
//任务过多后,存储任务的一个阻塞队列
BlockingQueue workQueue = new SynchronousQueue<>();
//线程的创建工厂
ThreadFactory threadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, “AdvacnedAsyncTask #” + mCount.getAndIncrement());
}
};
//线程池任务满载后采取的任务拒绝策略
RejectedExecutionHandler rejectHandler = new ThreadPoolExecutor.DiscardOldestPolicy();
//线程池对象,创建线程
ThreadPoolExecutor mExecute = new ThreadPoolExecutor(
corePoolSize, //线程池的核心线程数
maximumPoolSize,//线程池所能容纳的最大线程数
keepAliveTime,//线程的空闲时间
TimeUnit.SECONDS,//keepAliveTime对应的单位
workQueue,//线程池中的任务队列
threadFactory, //线程工厂
rejectHandler//当任务无法被执行时的拒绝策略
);
创建一个线程池需要输入几个参数:

corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。
runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。可以选择以下几个阻塞队列。
ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
PriorityBlockingQueue:一个具有优先级得无限阻塞队列。
maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。
ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字,Debug和定位问题时非常又帮助。
RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。
1、ThreadPoolExecutor.AbortPolicy:

  1. 当线程池中的数量等于最大线程数时抛 java.util.concurrent.RejectedExecutionException 异常,涉及到该异常的任务也不会被执行,线程池默认的拒绝策略就是该策略。
  2. 2ThreadPoolExecutor.DiscardPolicy():
  3. 当线程池中的数量等于最大线程数时,默默丢弃不能执行的新加任务,不报任何异常。
  4. 3ThreadPoolExecutor.CallerRunsPolicy():
  5. 当线程池中的数量等于最大线程数时,重试添加当前的任务;它会自动重复调用execute()方法。
  6. 4ThreadPoolExecutor.DiscardOldestPolicy():
  7. 当线程池中的数量等于最大线程数时,抛弃线程池中工作队列头部的任务(即等待时间最久的任务),并执行当前任务。

keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。
TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
三、线程池的工作原则
当线程池中线程数量小于 corePoolSize 则创建线程,并处理请求。
当线程池中线程数量大于等于 corePoolSize 时,则把请求放入 workQueue 中,随着线程池中的核心线程们不断执行任务,只要线程池中有空闲的核心线程,线程池就从 workQueue 中取任务并处理。
当 taskQueue 已存满,放不下新任务时则新建非核心线程入池,并处理请求直到线程数目达到 maximumPoolSize(最大线程数量设置值)。
如果线程池中线程数大于 maximumPoolSize 则使用 RejectedExecutionHandler 来进行任务拒绝处理。

Spring IOC 的容器初始化流程

  1. bean创建
  2. bean的赋值
  3. bean的初始化
  4. 内存中清除bean
  5. 清除Bean 工厂

Spring boot 启动机制

  1. 如何整合第三方依赖

maven 父子集成
spring-boot-starter-pom.xml

  1. 怎么做到无配置文件集成SpringMVC
  • SpringBootApplication

  • ComponentScan 通过自动扫描加载注解的组件

  • EnableAutoConfiguration

    1. [@Import](#) 把一个类交给Spring 容器管理

    spring.factories
    集成SpringMVC 和 Tomcat
    内部集成Tomcat类 实现Tomcat功能
    使用EnableWebMVC 注解集成SpringMVC

image.png

  1. Tomcat怎么启动

什么是一致性Hash Hash 算法的问题

image.png

image.png

MQ有可能发送重复消息,如何解决

image.png

  • 什么是MQ

  • MQ的作用

异步处理 ,下单-发邮件短信 邮件短信业务交给消息中间件
应用解耦
流量削峰

  • 重复消息是怎么回事?为何会产生重复消息?

  • 重复消息带来的问题和如何解决重复消息

  • 解决重复消息采用幂等操作

1)乐观锁 增加数据版本号
2)去重表 建立一个唯一的索引

如何做限流策略,令牌桶和漏斗算法的使用场景

漏桶

令牌算法:比如秒杀保证一定的令牌数量来应对突发流量,
会以恒定速度往令牌池方令牌,如果请求者拿不到令牌,拒绝服务

服务A调用服务B多个接口,响应时间最短

Callable
FutureTask
ExtratorService 线程池 submit
get()

A系统给B系统转100块钱

数据如何保证一致性,性能优化 CAS锁

  • 事务 Transactional

Service 层 添加事务 比如调用发货然后更新订单状态

  • 编程式事务

  • 接口幂等性

数据增加版本号字段
update order set orderstatus=#{orderStatus}, version = version+1
where orderid = #{orderId} and version = #{version}

多线程读操作大于写操作,如何解决并发问题

  • 内置锁加锁 ,读大于写,效率低

读多写少场景如何解决?

  • volatile 一写多读

  • 读写锁 (多写多读)

  • 使用写时复制容器(CopyOnWrite 系列) (很少写,很多读)

CopyOnWriteArrayList
CopyOnWriteArraySet
缺点:1)写操作 占用内存 2) 不能保证数据实时一致性,只能保证最终一致性

按线程池内部实现,当提交新任务时线程池是如何处理的?

执行任务的时间包括:
T1 创建线程时间
T2 在线程中执行任务的时间
T3 线程销毁时间

public ThreadPoolExecutor(
int corePoolSize, 核心线程数
int maximumPoolSize, 线程池允许的最大线程数量
long keepAliveTime, 空闲线程存活时间
TimeUnit unit, 空闲线程存活时间单位
BlockingQueue workQueue 放超出线程池容量的队列
RejectedExecutionHandler handler 拒绝策略
) {

image.png
提交任务执行过程
1 提交新任务创建主线程
2 达到主线程数量,放到阻塞队列
3 阻塞队列满了,创建新非主线程
4 达到线程池最大线程数量,执行拒绝策略

RejectedExecutionHandler 可以自定义

Transaction 标签使用

一般写在什么位置

image.png

Transaction 事务回滚规则

image.png

image.png

Redis高性能的原因

1) 内存中数据库,存储数据快
2)key value 存储, 数据保存相对简单
3)单线程,避免了多线程的资源消耗
4)多路复用
5) Resp协议

解决缓存数据一致性方案

image.png

数据实时同步

强一致性,1)更新数据库淘汰缓存 2) 读请求更新缓存 3)避免缓存雪崩,更新缓存过程需要进行同步控制,同一时间只允许一个请求访问数据库。 4)保证数据一致性,加上缓存失效

数据准实时更新

image.png

任务调用更新

浅谈 http 和https

http 不安全

数据拦截 数据篡改 数据攻击

https 安全

数据加密 身份验证 数据完整性

  • 对称加密

  • 非对称加密

公钥 私钥
架构师视频总结 - 图13
其工作过程大致是:
1、客户端发起HTTPS请求
浏览器里面输入一个HTTPS网址,然后连接到服务端的443端口上。注意这个过程中客户端会发送一个密文族给服务端,密文族是浏览器所支持的加密算法的清单。
2、服务端配置
采用HTTPS协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面。
这套证书其实就是一对公钥和私钥,可以这么理解,公钥就是一把锁头,私钥就是这把锁的钥匙,锁头可以给别人对某个东西进行加锁,但是加锁完毕之后,只有持有这把锁的钥匙才可以解锁看到加锁的内容。
前面说过客户端会传送密文族给服务端,服务端则会从这些密文族中,挑选出一个,比如百度吧:

架构师视频总结 - 图14

采用的就是RSA公钥加密算法来区分证书签名和交换密钥,通过AES算法来加密数据,至于GCM,应该是用来校验信息的
3、传送证书
这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构、过期时间等等。
4、客户端解析证书
这部分工作是由客户端的TLS来完成的,首先会验证公钥是否有效,如颁发机构、过期时间等等,如果发现异常则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随机值,然后用证书对该随机值进行加密。
注意一下上面提到的”发现异常”。证书中会包含数字签名,该数字签名是加密过的,是用颁发机构的私钥对本证书的公钥、名称及其他信息做hash散列加密而生成的。客户端浏览器会首先找到该证书的根证书颁发机构,如果有,则用该根证书的公钥解密服务器下发的证书,如果不能正常解密,则就是”发现异常”,说明该证书是伪造的。
5、传送加密信息
这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,然后客户端和服务端的通信就可以通过这个随机值来进行加密和解密了。
6、服务端解密信息
服务端用私钥解密后,得到了客户端传过来的随机值,至此一个非对称加密的过程结束,看到TLS利用非对称加密实现了身份认证和密钥协商。然后把内容通过该值进行对称加密。
7、传输加密后的信息
这部分是服务端用随机值加密后的信息,可以在客户端被还原。
8、客户端解密信息
客户端用之前生成的随机值解密服务端传送过来的信息,于是获取了解密后的内容,至此一个对称加密的过程结束,看到对称加密是用于对服务器待传送给客户端的数据进行加密用的。整个过程即使第三方监听了数据,也束手无策。

Cookie / Session 机制

Cookie

  1. Cookie 是为会话存储的键值信息
  2. Cookie 不可跨域名 (只能拿到当前域名下的cookie,包含父级域名)
  3. cookie 有有效期限制
  4. path 携带cookie的请求路径 (/ 表示全部请求)

    Session

1 Session 是服务器端基于内存的缓存技术,用来保存针对每个用户的会话数据
2 通过session Id 来区分用户,用户只要连接到服务器,服务器就会为之分配唯一的session ID
3 Session 也有失效时间 (超过时限未得到过链接的session销毁)
4 session用法:
HttpSession session = request.getSession();
session.setAttribute(String key,Object value)
session.getAttribute(String key)
session.removeAttribute(String key)

image.png