目录
IOC
IOC实现方式
BeanFactory
BeanFactory实现方式
ApplicationContext
ApplicationContext实现方式
基于 XML的Spring项目:
基于SpringBoot:
初始化过程
AOP
JDK动态代理
CGLIB动态代理
JDK动态代理与CGLIB动态代理的区别
实现方式
相关注解
核心方法
执行优先级
核心思想:将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理,IOC最常见以及最合理的实现方式叫做依赖注入(DI)
DI(依赖注入):把底层类作为参数传入上层类,实现上层类对下层类的“控制”
实现流程:
IOC优点:
Spring 提供了两种容器类型来提供支持 IOC方式:
ApplicationContext除了拥有BeanFactory的所有支持,ApplicationContext提供了其他高级特性:
• MessageSource, 提供国际化的消息访问
• 资源访问,如URL和文件
• 事件传播
• 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的 web层
ApplicationContext 间接继承自 BeanFactory,ApplicationContext 和 BeanFactory的继承关系如下:
BeanFactory 是基础类型IOC容器,提供完整的IOC服务支持。如果没有特殊指定,默认采用延迟初始化策略(lazy-load)。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初始化以及依赖注入工作。因此,相对来说,容器启动初期的时候速度是比较快的。所需要的资源有限。所以,对资源有限,并且功能要求不是很严格的场景,BeanFactory是比较合适的IOC容器
实际上,BeanFactory只是一个接口,它负责定义如何访问容器内管理的Bean的方法,各个BeanFactory的具体实现类负责具体Bean的注册以及管理工作。
BeanFactory有三个直接子类:
DefaultListableBeanFactory这个类其实就是 BeanFactory的默认实现类,一个比较通用的BeanFactory实现类,它除了间接实现 BeanFactory接口外,还实现了 BeanDefinitionRegistry接口,该接口才是BeanFactory实现中担任 Bean注册管理的角色,它抽象的定义了Bean注册的逻辑
ApplicationContext是在BeanFactory的基础上构建的,是相对比较高级的容器实现,ApplicationContext 容器启动之后,默认全部初始化并绑定完成,所以,对于BeanFactory来说,ApplicationContext 往往要求更多的系统资源,因此,ApplicationContext更适用于系统资源充足,并且要求更多功能的场景中。
Spring 为基本的 BeanFactory 类型容器提供了 XmlBeanFactory 实现(继承自DefaultListableBeanFactory),相应的,它也为 ApplicationContext 类型容器提供了以下几个常用的实现:
在官方文档中给出对于一个 SpringBoot 应用它对应的Context的情况:
当创建一个ClassPathXmlApplicationContext时,构造方法做了两件事情:
ClassPathXmlApplicationContext通过调用父类AbstractApplicationContext的refresh方法启动整个IOC容器对Bean定义的载入过程,refresh是一个模板方法,规定了IOC容器的启动流程。在创建IOC容器前如果已有容器存在,需要把已有的容器销毁,保证在refresh方法后使用新创建的IOC容器。
容器创建后通过LoadBeanDefinitions方法加载Bean配置资源,该方法做两件事:
Spring IOC容器中注册解析的Bean信息存放在一个HashMap集合中,key时字符集,只是BeanDefinition,注册过程中需要使用synchronized保证线程安全。当配置信息中配置的Bean被解析且被注册到IOC容器中后,初始化就算真正完成了,Bean定义信息已经可以使用且可被检索。
Spring AOP全称为Spring Aspect-Oriented Programming,即面向切面编程,实现方式:代理
Spring AOP使用动态代理技术在运行期间织入增强的代码,主要有两种代理机制:
为什么JDK动态代理只能代理接口?
通过Proxy.newProxyInstance()方法实现,其需要传入被动态代理的一个接口类,
其底层在于,JDK动态代理会在程序运行期间动态生成一个代理类$Proxy0,其会继承java.lang.reflect.Proxy类,同时去实现被代理类的接口,每个动态代理类都会继承一个Proxy,Java只能单继承所以不能代理实现类,如果要去代理实现类的话,那么代理类不仅要继承Proxy,还要继承当前类,违反了多继承的原则
JDK动态代理可以代理实现类吗?
可以,Proxy这个类只是保存了动态代理的一个名为InvocationHandler处理器,可以不抽取出来,直接设置在$Proxy0中,这样就可以代理实现类
CGLIB是一个强大的高性能代码生成包,通过修改其字节码在运行时期(非编译时期)生成被代理对象的子类,并重写了被代理对象的所有方法,从而作为代理对象
局限性:代理类被final关键字所修饰,无法生成子类,也就无法代理
AbstractAdvisorAutoProxyCreator类
AbstractAdvisorAutoProxyCreator实现了BeanPostProcessor,所以它本质上来说也是一个Spring的后置处理器,在Spring Bean实例化后,在初始化前后会经过这个后置处理器的加工,从而来实现AOP的代理生成。
大致过程是:AbstractAdvisorAutoProxyCreator通过BeanPostProcessor机制来加工初始化后的Bean,找到容器中所有的Advisor(切点+切面逻辑),然后判断这个Bean是否存在Advisor所匹配的切点,如果匹配就表示当前这个初始化的Bean需要代理,此时就会通过ProxyFactory选择具体的动态代理手段来构建代理对象。
如果开启了@EnableAspectJAutoProxy注解,并且proxyTargetClass属性为true,那么无条件使用CGLIB。如果需要代理的对象基于接口,且参数没有指定强制使用CGLIB则使用JDK的动态代理
@EnableAspectJAutoProxy
这个注解的核心原理就是往IOC容器中Import了一个AnnotationAwareAspectJAutoProxyCreator类的Bean实例。这个类继承自AbstractAdvisorAutoProxyCreator,所以它本质上也是一个BeanPostProcessor后置处理器。 AnnotationAwareAspectJAutoProxyCreator除了可以找到所有的Advisor类型的Bean,还可以找到@Aspect注解的Bean,并将其解析为Advisor对象,然后走AOP的逻辑生成代理对象。