1. Spring
BeanFactory是一个工厂类,用于管理Bean的一个工厂,在Spring中,所有Bean都是由BeanFactory(也就是IOC容器)来进行管理的。
FactoryBean是一个工厂Bean,创建的bean是getObject方法返回的对象。一般用于创建比较复杂的bean。
IOC容器实现的是服务的发现和注册,其作用和SPI相似。
- 配置文件扫描路径;
- 递归包扫描获取.class文件;
- 通过反射的方式,创建Object对象;
- 属性注入;
- 责任链的方式,执行各个BeanPostProcessor,生成代理对象;
- 将对象放入缓存池singletonObjects中;
Spring的事务管理机制包括:声明式事务和编程式事务。
Spring基础篇(1)-事务
事务的传播(propagation [ˌprɒpə'ɡeɪʃn])行为是指:如果在开始当前事务之前,一个事务上下文已经存在,此时我们可以有多个选项指定事务性方法的执行行为。
-
PROPAGATION_REQUIRED
:[adj 必须的]默认传播行为,指的是若当前存在事务,则加入该事务;如果当前没有事务,则创建一个新事务。 -
PROPAGATION_REQUIRES_NEW
:[v 需要新的]需要创建一个新的,若当前有事务,则将当前事务挂起。 -
PROPAGATION_SUPPORTS
:[v 支持]当前存在事务,就在事务中运行;当前不存在事务,则不在事务中运行。 -
PROPAGATION_NOT_SUPPORTED
[v 不被支持]不运行在事务中,当前有事务,则挂掉当前事务。 -
PROPAGATION_NEVER
:[adv 绝不]不运行在事务中,如果当前有事务,则抛出异常。 -
PROPAGATION_MANDARORY
[[ˈmændətəri]强制的]`必须运行在事务中,如果当前方法没有事务,则抛出异常。 -
PROPAGATION_NESTED
[[nestɪd] 嵌套的]当前存在事务,则创建一个事务作为当前事务的嵌套事务运行,如果当前没有事务,则创建一个新的事务。
默认配置下,Spring只有在抛出运行时异常(RuntimeException及其子类)或者Error异常时才会回滚,但是可以配置rollbackFor=Exception.class
将检查时异常进行回滚。
【事务嵌套调用】事务A方法调用事务B方法;
【事务B出现异常】事务A捕获事务B的异常(其实事务A不想回滚);
【事务A回滚操作】最终事务A还是回滚了;
如果事务B失败不影响事务A,可以将事务B的传播行为设置为propagation=Propagation.REQUIRES_NEW
。
REQUIRES_NEW
:当前存在事务,则将事务挂起。如果没有事务,则创建新事务。
SpringAOP联盟(1)—Advisor,Advice,Pointcut,Advised、ProxyConfig
SpringAOP联盟(3)—代理工厂
Spring内部真正创建出代理对象是通过ProxyFactory。
Spring的AOP实现原理是通过动态代理实现的。而Spring的AOP使用了两种动态代理:分别是JDK动态代理和CGLib动态代理。
Spring默认的策略:如果目标类是接口,则使用JDK动态代理,否则使用Cglib来生成代理。
JDK动态代理:
JDK代理注意涉及到java.lang.reflect
包下的两个类:Proxy和InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义的横切逻辑,并通过反射机制调用目标类代码,动态将横切逻辑和业务逻辑编制在一起,Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。
CGlib可以在运行期扩展Java类与实现Java接口,本质上是通过字节码增强技术在运行期动态生成新的class。
优点:
- JDK动态代理是JDK原生的,不需要任何依赖既可使用;
- 通过反射机制生成代理类速度要比cglib操作字节码生成代理类速度更快;
缺点:
- 使用JDK动态代理,被代理的类必须实现接口;
- JDK动态代理执行代理方法时,需要通过反射机制回调,方法执行效率低;
优点:
- CGlib代理类,无需实现接口;
- CGlib代理类执行代理方法时效率要高于JDK的动态代理;
缺点:
- CGlib代理类是操作字节码的方式,故生成代理类的速度要比JDK反射的速度要慢。
- CGlib代理类使用的是继承,也就意味着需要被代理的类是一个final类,无法使用CGlib代理。
三级缓存的作用:
一级缓存:单例池,即常说的spring容器。
二级缓存:若允许循环依赖,将singletonFactory存入二级缓存。目的是延迟加载,真正发生循环依赖时对对象进行代理操作。
三级缓存:防止二级缓存多次处理,并且标示发生过循环依赖,以便后续spring自检。
关键点:三级缓存中未获取到bean,然后登记Bean正在创建。
关键点:有一个标识Bean是否在创建。这个标识决定了是去创建bean,还是去earlySingletonObjects(第三级缓存)
中获取bean。
而这个标识是第一次在三级缓存中未获取到对象时,登记Bean正在创建。
- 正常流程下生命周期回调方法结束后执行BeanPostProcessor的postProcessAfterInitialization进行AOP代理,生成代理对象。
- 循环依赖情况下,在二级缓存singletonFactories生成对象时,会执行SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference进行AOP代理,目的是将代理对象注入到Bean中,解决循环依赖。
若循环依赖,提前会进行AOP代理,生成了earlySingletonObject代理对象。并且注入到Bean中。若正常流程下又获取到了新的代理对象,那么Spring便不知道以哪个代理版本为主。便会抛出自检异常。
registry [ˈredʒɪstri] 乱着死捶
组件 | 名称 | 作用 |
---|---|---|
DispatcherServlet | 前端控制器 | 接受请求,响应结果 |
HandlerMapping | 处理器映射器 | 根据请求URL查找handler,获取HandlerExecutionChain |
HandlerAdapter | 处理器适配器 | 按照特定规则,去执行对应的handler |
Handler | 处理器(Controller) | 接受用户请求,调用业务处理方法 |
ViewResolver | 视图解析器 | 进行视图解析,将逻辑视图解析为物理视图 |
View | 视图 | 将数据展示给用户的页面,例如JSP、freemarker |
Spring源码篇(1)—RequestMappingHandlerMapping(Handler的注册)
Spring源码篇(2)—RequestMappingInfo与RequestCondition(Handler—映射)
SpringBoot2.x—定制HandlerMapping映射规则
项目启动后,Spring可以获取到容器中所有Bean对象。而RequestMappingHandlerMapping将处理@RequestMapping标签完成handler的注册(存储到map中)。
- 根据@Controller和@RequestMapping标签筛选Bean。
- 根据@RequestMapping标签来筛选Bean中所有方法,将@RequestMapping标签解析为RequestMappingInfo对象。
- RequestMappingInfo和method对象进行注册。
Request不仅可以与@RequestMapping属性进行匹配(当然匹配规则是固定的),还可以使用自定义规则进行匹配。
在@RequestMapping类/方法上使用自定义注解。这样在解析含义@RequestMapping注解的类/方法时,用户便可以解析自定义注解的值,从而创建自定义的RequestCondition
对象,选择出优先级最高的HandlerMethod对象。
根据上述描述,HandlerMapping实际上完成了两件工作:
- 根据请求获取到HandlerMethod,即定位到最优的Controller层的方法进行处理(即HandlerMethod);
- 将HandlerMethod与Interceptor封装为一个HandlerExecutionChain。
其他
虚拟机级别的AOP功能,实现了对字节码增强的功能。
- 反射破坏:反射是通过调用构造方法生成新的对象,所以如果我们想要阻止单例破坏,可以在构造方法中进行判断,若已有实例, 则阻止生成新的实例。
- Serializable序列化破坏: 就可以通过反序列化破坏单例,所以我们可以不实现序列化接口,如果非得实现序列化接口,可以重写反序列化方法readResolve(), 反序列化时直接返回相关单例对象。
相关文章
Spring精华篇(1)— druid配置导致循环依赖(自检异常)
项目实战—那些年常用的单例模式