基础概念:
1、IoC 和 DI
IoC (Inversion of Control),即控制反转。是 Spring 的一种设计思想。
在传统的程序设计,我们直接在对象内部通过 new 来创建对象,是程序主动去创建依赖对象;而在 Spring 中有专门的一个容器来创建和管理这些对象,并将对象依赖的其他对象注入到该对象中,这个容器我们一般称为 IoC 容器。
所有的类的创建、销毁都由 Spring 来控制,也就是说控制对象生存周期的不再是引用它的对象,而是 Spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被 Spring 控制,所以这叫控制反转。
DI(Dependency Injection),即依赖注入,由 Martin Fowler 提出。可以认为 IoC 和 DI 其实是同一个概念的不同角度描述。
依赖注入是指组件之间的依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。
通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
2、bean
官方概念:在 Spring 中,构成应用程序主干并由 Spring IoC 容器管理的对象称为 bean。 bean 是一个由 Spring IoC 容器实例化,组装和管理的对象。
大白话:bean 可以认为是那些我们想注入到 Spring IoC 容器的 Java 对象实例的抽象。
我们经常会在 Service 上使用 @Service 注解,然后在要使用该 Service 的类中通过 @Autowire 注解来注入,这个 Service 就是一个 bean。在这个地方,@Service 注解相当于告诉 IoC 容器:这个类你需要帮我创建和管理;而 @Autowire 注解相当于告诉 IoC 容器:我需要依赖这个类,你需要帮我注入进来。
3、BeanDefinition
理解了 bean,BeanDefinition 就好理解了。BeanDefinition 是 bean 的定义,用来存储 bean 的所有属性方法定义。
4、BeanFactory 和 ApplicationContext
BeanFactory:基础类型 IoC 容器,提供完整的 IoC 服务支持。
ApplicationContext:BeanFactory 的子接口,在 BeanFactory 的基础上构建,是相对比较高级的 IoC 容器实现。包含 BeanFactory 的所有功能,还提供了其他高级的特性,比如:事件发布、国际化信息支持、统一资源加载策略等。正常情况下,我们都是使用的 ApplicationContext。其还有个重要特性就是ApplicationContext不是懒加载的。
5、FactoryBean
一般情况下,我们将 bean 的创建和管理都交给 Spring IoC 容器,Spring 会利用 bean 的 class 属性指定的类来实例化 bean。
但是如果我们想自己实现 bean 的创建操作,可以实现吗?答案是可以的,FactoryBean 就可以实现这个需求。
FactoryBean 是一种特殊的 bean,它是个工厂 bean,可以自己创建 bean 实例,如果一个类实现了 FactoryBean 接口,则该类可以自己定义创建实例对象的方法,只需要实现它的 getObject() 方法即可。
spring的ioc的容器bean的refresh过程。。说实话代码复杂流程长(12个方法。。。)。看个七八遍能看出主干流程就不错了。。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 设置容器状态,启动时间,状态激活等
prepareRefresh();
// 创建bean工厂,如果已经有老的则把老的干掉,默认创建的是DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// bean工厂投入生产前的各种配置,如bean定义器、加载器,后置处理器注册环境相关的默认bean到单例缓存map中等
prepareBeanFactory(beanFactory);
try {
// 工厂后置处理器默认空实现 在通过方法prepareBeanFactory执行了标准的初始化之后来修
//改内部的bean factory。此时所有的bean definition都已经加载完毕但是没有任何的bean完
//成初始化。
postProcessBeanFactory(beanFactory);
// 应用BeanFactoryPostProcessor
//在bean definition加载完毕后,在通过bean definition生成bean之前,
//调用BeanFactoryPostProcessor,在这里可以随意修改所有用户bean的定义
invokeBeanFactoryPostProcessors(beanFactory);
// 实例化和注册BeanPostProcessor,bean的后置处理器,初始化前后进行处理工作
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource,辅助i18n
initMessageSource();
// 初始化上下文的时间广播器。event
initApplicationEventMulticaster();
// 空实现。目前啥也没干
onRefresh();
// 注册监听器
registerListeners();
// 初始化非延迟加载的单例bean
finishBeanFactoryInitialization(beanFactory);
// 完成刷新
finishRefresh();
}
1、ioc流程:
1.准备阶段,设置一些容器的参数,状态。
2.创建beanFactory,DefaultListableBeanFactory.接着配置,如bean定义器、加载器,后置处理器此时所有的bean definition都已经加载完毕但是没有任何的bean完成初始化
3、应用BeanFactoryPostProcessor,在在beandefinition加载完毕后,beanDefinition加载bean之前,通过BeanFactoryPostProcessor可以自定义修改对象
4、实例化和注册BeanPostProcessor,bean的后置处理器
5、通过反射将beanDefinition对象实例化成bean对象
5、初始化广播器注册监听器
6、初始化对象,填充对象属性,执行beanPostProcessor,init-mehtod方法。
7、生成完整的bean对象后,调用getbean对象获取对象
8、对象销毁
bean的生命周期:首先,bean的生命周期就是 实例化,属性注入,初始化,销毁
解决循环依赖问题:java的引用传递(对象的属性可以延迟设置)和三级缓存
/** 一级缓存,缓存初始化完成的单例对象,放到这里的单例对象是可以直接使用的 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 二级缓存,缓存提前曝光的单例对象,放到这里的单例对象是不完整的*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** 三级缓存,缓存可以创建bean的工厂,ObjectFactory是一个生产者函数式接口,
实现这个接口的lambda表达式提供一个创建bean的方法*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
1、通过提前曝光实例化的bean(执行bean的构造方法),解决循环依赖,因此构造器注入的bean循环依赖无法解决。此时构造器都还没执行,还没有实例化对象的引用
2、多例模式的bean不使用缓存,循环依赖叶无法解决
3、A在实例化之后放入三级缓存;当B注入属性A时,A从三级缓存升级到二级缓存(A此时尚不完整),A完成初始化之后升级到一级缓存。B在实例化之后放入三级缓存;在初始化之后升级到一级缓存
4、3级缓存解决代理对象的循环依赖。
aop:aop其实是beanPostProssed 的一个拓展点,是bean后置处理器里的执行逻辑。
通过 DefaultAopProxyFactory 调用createAopProxy来创建代理对象放入到ioc容器。其和 原对象具有相同给的hashCode值,但是不同的内存地址。create是通过一组jvm指令集获取源对象的字节码进行修改生成的代理对象,jdk动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。需要实现其invok方法。使用cglib必须要用接口的原因就是public class $Proxy1 extends Proxy implements xxxxx 代理类受限于java单继承的语法限制。
事务@Transaction
在开启事务@EnableTransaction注解的时候实际上是注入了三个类:
TransactionIntercetor:用于拦截方法,事务的创建提交回滚等
TransactionInAttributeSourcePoint: 用作方法匹配,
TransactionAttributeSource:解析事务的属性,并且缓存
1、实例化事务拦截器TransactionIntercetor、事务属性解析器TransactionAttributeSource 以及增强器 BeanFactoryTransactionAttributeSourceAdvisor
2、先调用增强器接口找出所有的advisors
3、然后找到自己的增强器后反射获取所有的类方法,并且匹配哪些方法有事务注解,先查混缓存,如果没有则解析事务注解缓存起来
4、根据这个事务注解类创建代理对象。
注解无效情况:
获取事务属性时判断了方法是否ispublic。不是public事务无效
同类中调用或者catch异常或者是事务传播行为设置错误。
事务传播行为默认:当前事务存在则加入,不存在创建。 还有存在则加入,不存在则不用事务、抛异常等
总结:
ioc容器初始化过程
1、设置容器的一些状态和参数
2、创建ioc容器,默认使用DefaultListableBeanFactory创建bean工厂。并且配置Bean的定义,加载器以及后置处理等。此时Bean Definition 以及加载但是未初始化
3、应用factory处理器,在在通过Bean Definition生成bean之前,通过BeanFactoryPrecess可以对bean Definition进行修改
4、通过Bean Definition 用反射实例化成Bean对象
5、初始化和注册event监听器
6、初始化Bean对象,实例化和注册BeanPostProcess。执行器后置方法,bean的init方法等
7、生成完成的bean对象。此时可以调用getBean获取对象。
bean生命周期严格讲 初始化--属性注入--调用Aware方法--BeanPostProcess前置处理器方法--初始化方法--BeanProcess后置处理方法--Bean完成初始化可以使用--容器关闭调用destory方法--自己定义的销毁方法--over
Aop其实说白了,是spring ioc 里面 beanPostProcess的一个扩展点,是bean后置处理器里的延伸逻辑。在beanPostProcess的后置处理方法里,最终是通过DefaultAutoProxyFactory的createAopProxy来创建代理对象放入到ioc容器中,所以原始对象并不会出现在容器中。jdk动态代理依靠反射生成一个匿名内部类,在执行方法前调用invokerHandl来处理。而cglib动态代理则通过集成Proxy类,通过在家原始类的字节码进行修改而生成的新的代理对象,因其已经实现了Proxy类,因此代理对象必须是接口才能符合java的语法规范。
spring事务也是基于动态代理来实现的。当我们使用@EnableTrantsaction注解时实际上是网容器里注册了三个类:@TrantsactionIntercetor:用于拦截标的方法,@TransactionAttributeSoucePoit:方法的匹配,也就是要拦截哪些方法。@TransactionAttribute 解析事务注解属性,并缓存
通过拦截,解析然后生成事务注解类的代理对象,在增强方法里进行事务控制。
其中注意aop在同类中调用方法将不生效,事务注解对是否是public方法进行了判断,非public方法无效。
springboot的类自动装配spi机制实现是其会自动加载mat-info下spring.factories文件中配置的类形象autoCofig,其最终还是会调用ioc容器舒适化方法,通过其将自动配置类放入到ioc容器中区。
其内置tomcat启动也是通过将Enviroment、profile等配置注入到Server。然后将ServletWebServerApplicationContext内通过onFresh方法注册进去。