1. Bean的生命周期
(1)生成BeanDefinition
(2)合并BeanDefinition
(3)加载类
(4)实例化前
(5)实例化
(6)BeanDefinition的后置处理
(7)实例化后
(8)自动注入
(9)处理属性
(10)执行Aware
(11)初始化前
(12)初始化
(13)初始化后
1.1 生成BeanDefinition
Spring启动的时候会进行扫描,会先调用
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandid
ateComponents(String basePackage) 扫描某个包路径,并得到BeanDefinition的Set集合。
1.2 合并BeanDefinition
在父子BeanDefinition的情况下:
<bean id="parent" class="com.zhouyu.service.Parent" scope="prototype"/>
<bean id="child" class="com.zhouyu.service.Child" parent="parent"/>
因为child的父BeanDefinition是parent,所以会继承parent上所定义的scope属性。而在根据child来生成Bean对象之前,需要进行BeanDefinition的合并,得到完整的child的BeanDefinition。
1.3 加载类
合并BeanDefinition后,尝试创建Bean对象,创建的第一步为对象的实例化,所以首先要进行对象所属类的加载resolveBeanClass(mbd, beanName):若果beanClass属性的类型是Class,那么就直接返回,如果不是,则会根据类名进行加载
1.4 实例化前
在Spring中,实例化对象之前,Spring提供了一个扩展点,允许用户来控制是否在某个或某些Bean实例化之前做一些启动动作(BeanPostProcessor)
1.5 实例化
根据BeanDefinition去创建一个对象.
(1)Supplier创建对象
首先判断BeanDefinition中是否设置了Supplier,如果设置了则调用Supplier的get()得到对象。
(2)工厂方法创建对象
检查BeanDefinition中是否设置了factoryMethod,有两种方式可以设置factoryMethod
方式一:
<bean id="userService" class="com.zhouyu.service.UserService" factory‐
method="createUserService" />
// bean类型定义
public class UserService {
public static UserService createUserService() {
System.out.println("执行createUserService()");
UserService userService = new UserService();
return userService;
}
}
方式二:对于抽象类型的bean的创建
<bean id="commonService" class="com.zhouyu.service.CommonService"/>
<bean id="userService1" factory‐bean="commonService" factory‐method="createUserService"
/>
// bean的定义
public class CommonService {
public UserService createUserService() {
return new UserService();
}
}
(3)bean对象构造方法推断
判断使用哪种构造方法进行对象的构建
特殊的@lookup注解
@Component
public class UserService {
private OrderService orderService;
public void test() {
OrderService orderService = createOrderService();
System.out.println(orderService);
}
@Lookup("orderService")
public OrderService createOrderService() {
return null;
}
}
1.6 BeanDefinition的后置处理
Bean对象实例化出来之后,接下来就应该给对象的属性赋值了。在真正给属性赋值之前,Spring又提供了一个扩展点
MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()
1.7 实例化后
在处理完BeanDefinition后,Spring又设计了一个扩展点InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(),该扩展点在源码中使用次数极低
1.8 自动注入
自动注入对象依赖的属性
1.9 处理属性
这个步骤中,会处理@Autowired、@Resource、@Value等注解,也是通过postProcessProperties()扩展点来实现的,处理方式使用依赖注入
1.10 执行Aware
完成了属性赋值之后,Spring会执行一些回调
1.11 初始化前
初始化前,也是Spring提供的一个扩展点:
BeanPostProcessor.postProcessBeforeInitialization(),在该扩展点可以实现对完成依赖注入的Bean的处理
1.12 初始化
(1)查看当前Bean对象是否实现了InitializingBean接口,如果实现了就调用其afterPropertiesSet()
方法
(2)执行BeanDefinition中指定的初始化方法
1.13 初始化后
这是Bean创建生命周期中的最后一个步骤,也是Spring提供的一个扩展点:BeanPostProcessor.postProcessAfterInitialization()
1.14 Bean的销毁
Bean销毁是发送在Spring容器关闭过程中的。
销毁过程中涉及到一种设计模式:适配器模式(adapter同时实现目标接口与传入接口,将传入接口的数据转换为目标接口可接受零星)
在销毁时,Spring会找出实现了DisposableBean接口的Bean。
但是我们在定义一个Bean时,如果这个Bean实现了DisposableBean接口,或者实现了
AutoCloseable接口,或者在BeanDefinition中指定了destroyMethodName,那么这个Bean都属
于“DisposableBean”(目标接口),这些Bean在容器关闭时都要调用相应的销毁方法。
所以,这里就需要进行适配,将实现了DisposableBean接口、或者AutoCloseable接口等适配成实现了DisposableBean接口,所以就用到了DisposableBeanAdapter。
会把实现了AutoCloseable接口的类封装成DisposableBeanAdapter,而DisposableBeanAdapter
实现了DisposableBean接口
2. 依赖注入
2.1 手动注入:包括xml注入及构造方法注入
(1)xml注入:底层通过set方法完成注入
<bean name="userService" class="com.luban.service.UserService">
<property name="orderService" ref="orderService"/>
</bean>
(2)构造方法注入:
<bean name="userService" class="com.luban.service.UserService">
<constructor‐arg index="0" ref="orderService"/>
</bean>
2.2 Autowired自动注入
(1) XML的autowire自动注入
<bean id="userService" class="com.luban.service.UserService" autowire="byType"/>
//表示Spring会自动的给userService中所有的属性自动赋值(不需要这个属性上有@Autowired注解,但需要这个属性有对应的set方法)
支持进行自动注入的方式有:
(寻找set方法进行注入)byType,byName,
(寻找构造方法进行注入)constructor,default,no;
在创建Bean的过程中,在填充属性时,Spring会去解析当前类,把当前类的所有方法都解析出来,Spring会去解析每个方法得到对应的PropertyDescriptor对象;
注1:byName解析:
这个name并不是方法的名字,而是拿方法名字进过处理后的名字
i. 如果方法名字以“get”开头,比如“getXXX”,那么name=XXX
ii. 如果方法名字以“is”开头,比如“isXXX”,那么name=XXX
iii. 如果方法名字以“set”开头,比如“setXXX”,那么name=XXX
注2:通过构造方法的属性注入
如果是constructor,那么就可以不写set方法了,当某个bean是通过构造方法来注入时,spring利用构造方法的参数信息从Spring容器中去找bean,找到bean之后作为参数传给构造方法,从而实例化得到一个bean对象,并完成属性赋值
(2)通过@Autowired注解方式注入
优点:比xml配置文件提供更细粒度的自动注入方式(XML中的autowire控制的是整个bean的所有属性,而@Autowired注解是直接写在某个属性、某个set方法、某个构造方法上的)
2.3 基于@AutoWired注解底层注入原理
@Autowired注入举例:
// 普通注入点
@Autowired
private OrderService orderService;
// set方法注入
@Autowired
public void setOrderService(OrderService orderService);
2.3.1 各位置@Autowired寻找Bean:
(1)属性上:先根据属性类型去找Bean,如果找到多个再根据属性名确定一个
(2)构造方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
(3)set方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
2.3.2 寻找注入点
AutowiredAnnotationBeanPostProcessor:
在创建一个Bean的过程中,Spring会利用AutowiredAnnotationBeanPostProcessor的
postProcessMergedBeanDefinition()找出注入点并缓存
1. 遍历当前类的所有的属性字段Field
2. 查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该字段
是一个注入点
3. 如果字段是static的,则不进行注入
4. 获取@Autowired中的required属性的值
5. 将字段信息构造成一个AutowiredFieldElement对象,作为一个注入点对象添加到
currElements集合中。
6. 遍历当前类的所有方法Method
7. 判断当前Method是否是桥接方法,如果是找到原方法
8. 查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该方法
是一个注入点
9. 如果方法是static的,则不进行注入
10. 获取@Autowired中的required属性的值
11. 将方法信息构造成一个AutowiredMethodElement对象,作为一个注入点对象添加到
currElements集合中。
12. 遍历完当前类的字段和方法后,将遍历父类的,直到没有父类。
13. 最后将currElements集合封装成一个InjectionMetadata对象,作为当前Bean对于的注入点集合
对象,并缓存。
2.3.3 对注入点进行依赖注入
Spring在AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法中,会遍历所找到的注入点依次进行注入。
(1)字段注入
1. 遍历所有的AutowiredFieldElement对象。
2. 将对应的字段封装为DependencyDescriptor对象。
3. 调用BeanFactory的resolveDependency()方法,进行依赖查找,找到当前字段所匹配的Bean对象。
4. 将匹配结果存入缓存(比如当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了)
5. 利用反射将结果对象赋值给字段。
(2)set方法注入
1. 遍历所有的AutowiredMethodElement对象
2. 遍历将对应的方法的参数,将每个参数封装MethodParameter对象
3. 将MethodParameter对象封装为DependencyDescriptor对象
4. 调用BeanFactory的resolveDependency()方法,进行依赖查找,找到当前字段所匹配的Bean对象。
5. 将匹配结果存入缓存(比如当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了)
6. 利用反射将结果对象赋值给字段。
2.4 重点方法详解
2.4.1 findAutowireCandidates
寻找autowired候选:
1. 找出BeanFactory中类型为type的所有的Bean的名字
2. 把resolvableDependencies中key为type的对象找出来并添加到result中
3. 对找到的beanName进行判断,是否可进行自动注入(检查beanDefinition中的autowireCandidate属性是否为true)
4. 判断当前type是不是泛型,如果是泛型是会把容器中所有的beanName找出来的,如果是这种情况,那么在这一步中就要获取到泛型的真正类型,然后进行匹配
5. 如果当前DependencyDescriptor上存在@Qualifier注解,那么则要判断当前beanName上是否定义了Qualifier,并且是否和当前DependencyDescriptor上的Qualifier相等,相等则匹配
6. 经过上述验证之后,当前beanName才能成为一个可注入的,添加到result中
2.4.2 @Qualifier的使用
(1)解决@Autowired注解注入时多个bean不知加载哪个的问题,通过@Qualifier指定要加载的bean
@component("test")
public class TestImpl impements Test {}
@component("test2")
public class TestImpl2 impements Test {}
@component
public class Service {
@Autowired
@Qualifier("test")
private Test testMatters;
}
(2)与@Primary区别
@Primary注解标注在默认情况下优先注入哪个bean
@component
@Primary
public class TestImpl impements Test {}
@component
public class TestImpl2 impements Test {}
@component
public class Service {
@Autowired
private Test testMatters;
}
2.5 依赖注入总体流程
(1)先找到所有注入点
(2)遍历每个注入点
(3)根据注入点类型找到Bean
(4)对找到的多个Bean:
单例Bean:直接注入该Bean
多例Bean:向下判断
(5)先判断isAutoWiredCandidate(是否为autowired候选)
(6)判断是否符合@Qualifier
(7)若还有多个Bean
(8)取@Primary标注的Bean
(9)取优先级最高的Bean
(10)进行名称筛选:
属性注入:则为属性名
set方法注入:为参数名称
(11)结束
2.6 @Resource注解
(1)同样标注注入点,通过调用inject()方法完成注入BeanPostProcess中;
(2)与@Autowired区别
@Resource不依赖Spring框架,底层不同
性能无区别
3. 循环依赖问题
3.1 循环依赖问题
// A依赖了B
class A{
public B b;
}
// B依赖了A
class B{
public A a;
}
3.2 解决思路
通过存入缓存的方式进行解决
(1)实例化一个service -> 得到一个对象,放入临时Map中<name, aBean>
(2)实例化BService过程中,发现无单例,首先尝试从Map中获取到bBean
3.3 解决方案 -- 三级缓存
(1)singletonObjects单例池
(2)earlySingletonObjects存储代理对象/早期未完成初始化对象
解决创建过程中原始对象无处存放的问题;
(3)SingtonFactories存放Aservice创建时原始对象,在Bservice依赖时获取
打破循环依赖的关键,未初始化的属性预先放入缓存中(第一次遇到即放入);
3.4 总体流程
(1)填充Aservice属性
(2)去单例池中找
(3)CreateSet
(4)出现循环依赖
(5)尝试从earlySingletonObjects中寻找
(6)找不到,从最底层SingletonFactories中查找,肯定可以找到
(7)执行lambda
(8)将lambda生成的Bean存入earlySinletonObjects中,并返回
3.5 补充
(1)原型Bean循环问题可以解决吗?
不可解决,若两个Bean均为原型,则要求每次创建一个新实例,走不出循环;
(2)自身循环注入问题
同样使用三级缓存解决;
4. Spring寻找Bean构造器的集中方式
(1)默认情况下,用无参构造方法/仅有的一个构造方法
(2)用户指定构造方法入参值:通过getBean()或BeanDefinition中getConstructorArgumentValues()指定指定,框架通过参数数量,类型等因素匹配构造方法
(3)由框架自动选择构造方法及入参,xml配置寻找方法
<bean id = "userService" class = "userService" autowired = "byType"/> // 向下寻找set方法
(4)通过注解@Autowired注解指定某个构造方法,希望框架自动找入参值
<bean id = "userService" class = "userService" autowired = "byName"/>
public class userService() {}
4.1 补充
(1)@Bean
Spring框架将@Bean修饰的方法解析为BeanDefinition
public class Appconfig {
@Bean
public static UserService userService() {} // 生成一个BeanDefinition
@Bean
public static UserService userService(OrderService order) {}
// 发现已有BeanDefinition,复用即可
}
(2)@lookUp的使用
@lookUp将按照用户指定方法生成代理对象
@Component
public class UserService {
@Autowired
private OrderService orderService;
public void test() {}
@LookUp("OrderService")
public OrderService func() {
// 调用时,获得新的OrderService的Bean代理对象
return null;
}
}
@Component
@Scope("prototype")
public class OredrService {}
5. Spring框架启动原理
5.1 流程
(1)构造一个BeanFactory对象
(2)解析配置类,得到BeanDefinition,并注册到BeanFactory中
(3)因为ApplicationContext还支持国际化,所以还需要初始化MessageSource对象
(4)因为ApplicationContext还支持事件机制,所以还需要初始化ApplicationEventMulticaster对象
(5)把用户定义的ApplicationListener对象添加到ApplicationContext中,等Spring启动完了就要发布事件了
(6)创建非懒加载的单例Bean对象,并存在BeanFactory的单例池中
(7)调用Lifecycle Bean的start()方法
(8)发布ContextRefreshedEvent事件
5.2 BeanFactoryPostProcessor
BeanPostProcessor表示Bean的后置处理器,是用来对Bean进行加工的,类似的,BeanFactoryPostProcessor理解为BeanFactory的后置处理器,用来用对BeanFactory进行加工的
@Component
public class ZhouyuBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService"); beanDefinition.setAutowireCandidate(false);
}
}
5.3 如何理解refresh()
ConfigurableApplicationContext接口上refresh()方法的注释,意思是:加载或刷新持久化的配置,可能是XML文件、属性文件或关系数据库中存储的。
5.4 容器启动总结
(1)创建DefaultListableBeanFactory
(2)解析配置类
(3)扫描@Bean
(4)生成BeanDefinitionMap,BeanPostProcessor单例池
6. 配置类源码解析
6.1 不同解析配置类型
(1)Component 解析该配置类
(2)ComponentScan 扫描并注册BeanDefinition;有配置类则解析
(3)Import 调到ProcessImports()处理所导入的类
(4)ImportRource 将所导入的xml文件路径添加入当前配置类importedResource属性
(5)配置类中含有@Bean 将@Bean修饰的方法封装为BeanMethod对象,并添加入当前配置类beanMethods属性
最后:保存为BeanDefinition对象存入Factory中,获得配置类对应的Bean
6.2 补充@configuration注解
@configuration // 生成AppConfig的代理对象
public class Appconfig {
@Bean
public UserService userService() {
// 将会执行代理对象的构造方法
return new UserService();
}
}
注:BeanMethodInterceptor拦截器返回Bean对象
(1)有@configuration,返回它的代理对象
(2)无,返回Bean对象
7. Spring Aop原理
7.1 动态代理
(1)应用场景:
@Component
public class UserService {
public void test() {
println();
}
}
public class Test() {
public static void main(String[] args) {
UserService service = new UserService();
service.test(); // 有什么方法可以在不修改Test()方法的前提下,为service.test()前增加额外功能
}
}
(2)解决方案:动态代理设计模式
UserService target = new UserService();
Enhance en = new Enhance(); // cgLib增强器
en.setSuperClass(UserService.class);
en.setCallbacks(new Callback[] { new MethodInterceptor() {
public Object intercept(Object o, Method m, ...) {
// 切入逻辑
Object res = m.invoke(target, o); // java反射
return res;
}
}
});
// 调用时
UserService userService = (UserService)en.create();
userService.test(); // 含新逻辑
(3)利用JDK动态代理来生成一个代理对象:
UserService target = new UserService();
// UserInterface接口的代理对象
Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]
{UserInterface.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before...");
Object result = method.invoke(target, args);
System.out.println("after...");
return result;
}
});
UserInterface userService = (UserInterface) proxy;
userService.test()
7.2 Spring框架对AOP的处理 -- ProxyFactory
在Spring中进行了封装,封装出来的类叫做ProxyFactory,
表示是创建代理对象的一个工厂
UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
});
UserInterface userService = (UserInterface) proxyFactory.getProxy();
userService.test();
通过ProxyFactory,我们可以不再关系到底是用cglib还是jdk动态代理了,ProxyFactory会帮我们去判断,如果UserService实现了接口,那么ProxyFactory底层就会用jdk动态代理,如果没有实现接口,就会用cglib技术,上面的代码,就是由于UserService实现了UserInterface接口,所以最后产生的代理对象是UserInterface类型。
7.3 其他重要特性
- Aspect:表示切面,比如被@Aspect注解的类就是切面,可以在切面中去定义Pointcut、Advice等等
- Join point:表示连接点,表示一个程序在执行过程中的一个点,比如一个方法的执行,比如一个异常的处理,在Spring AOP中,一个连接点通常表示一个方法的执行。
- Advice:表示通知,表示在一个特定连接点上所采取的动作。Advice分为不同的类型,后面详细讨论,在很多AOP框架中,包括Spring,会用Interceptor拦截器来实现Advice,并且在连接
点周围维护一个Interceptor链 - Pointcut:表示切点,用来匹配一个或多个连接点,Advice与切点表达式是关联在一起的,Advice将会执行在和切点表达式所匹配的连接点上
- Introduction:可以使用@DeclareParents来给所匹配的类添加一个接口,并指定一个默认实现
- Target object:目标对象,被代理对象
- AOP proxy:表示代理工厂,用来创建代理对象的,在Spring Framework中,要么是JDK动态代理,要么是CGLIB代理
- Weaving:表示织入,表示创建代理对象的动作,这个动作可以发生在编译时期(比如Aspejctj),或者运行时,比如Spring AOP
7.4 创建代理对象的方式
我们希望ProxyFactory所产生的代理对象能直接就是Bean,能直接从Spring容器中得到UserSerivce的代理对象,而这些,Spring都是支持的。
(1)ProxyFactoryBean
@Bean
public ProxyFactoryBean userServiceProxy(){
UserService userService = new UserService();
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(userService);
proxyFactoryBean.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
});
return proxyFactoryBean;
}
通过这种方法来定义一个UserService的Bean,并且是经过了AOP的。但是这种方式只能针对某一个Bean。它是一个FactoryBean,所以利用的就是FactoryBean技术,间接的将UserService的代理对
象作为了Bean。
(2)通过注解定义PointCut以及Advice
@Aspect
@Component
public class ZhouyuAspect {
@Before("execution(public void com.zhouyu.service.UserService.test())")
public void zhouyuBefore(JoinPoint joinPoint) {
System.out.println("zhouyuBefore");
}
}
(3)Spring框架中整合ProxyFactory实践
@ComponentScan("com.test")
public class Appconfig {
@Bean // 将ProxyFactory功能注册为Bean;
// ProxyFactory实现了BeanPosytProcess接口,构造器将在其生命周期中执行
public ProxyFactoryBean userSecvice() {
ProxyFactoryBean proxy = new ProxyFactoryBean();
proxy.addAdvice(new zhouyuBeforeAdvice()); // 实现接口MethodBeforeAdvice
proxy.setTarget(userService);
return proxy;
}
}
// 使用时:
public static void main(String[] args) {
...
UserService service = application.getBean("Appconfig.class");
service.test();
...
}
7.5 AOP总结
- 总体由BeanPostProcessor实现
- 核心方法:
PostProcessAfterInitalization() {
...
wrappIfNecessary(bean, beanName, cacheKey);
...
}
- 寻找当前Bean匹配的advice,可以找到则创建proxyFactory
- findCandidatesAdviors : 由BeanFactory找到所有切面Bean;有@aspect注解,则解析,返回整个列表List
- 对List执行业务筛选,依次调用matches()方法进行匹配
- 返回proxyFactory<List>
- 执行返回proxyFactoryList中advice的invoke逻辑及代理逻辑
8. Spring事务
8.1 Aop流程总结
(1)Advisor类包括
- pointcut切点类型:
ClassFilter 类型匹配
MethodMatcher 方法匹配 - Advice: 方法拦截器 + 实际执行的逻辑
(2)流程总结:
初始化UserService Bean
找到所有匹配的Advisor
利用ProxyFactory生成代理对象
8.2 事务原理
@Transactional
public void test() {
jdbcTemplate.execute("insert into t1 value(1, 1, 1)");
}
(1)通过pointcut匹配生成的代理对象Advisor:
BeanFactoryTransactionAttributeSourceAdvisor
UserService userService = application.getBean("userService");
userService.test();
(2)流程(invoke):
- Spring事务管理器,创建DB连接Conn
- conn.autoCommit = false;放入ThreadLocal<Map>中;key(DataSource): Value(conn)
- target.test() 执行sql语句
- 提交,回滚
(3)事务传播机制 @transactional(propagation = xxx) - Spring事务管理器
- Conn放入ThreadLocal<Map>中
- target.test()
- a方法
- Spring创建DB连接conn2
- conn2放入ThreadLocal中
- conn2提交
- conn提交
注:多层结构使用递归方式解决
网友评论