spring生命周期和bean生命周期,spring bean生命周期 简书
终极管理员 知识笔记 120阅读
入门使用的Spring代码
ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(spring.xml);UserService userService (UserService) context.getBean(userService);userService.test();
思考问题

1、第一行代码都做了哪些事情
2、第二行代码getBean()
如何实现的返回的UserService
对象和new创建的对象有什么区别

在新版的Spring MVC
和Spring Boot
的底层主要用的都是AnnotationConfigApplicationContext
AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class);UserService userService (UserService) context.getBean(userService);userService.test();
注意AppConfig.class
和spring.xml
的本质是一样的都表示Spring的配置类比两种写法
spring.xml中的内容为<context:component-scan base-packagecom.gax/><bean iduserService classcom.gax.service.UserService/> AppConfig中的内容为ComponentScan(com.gax)public class AppConfig { Bean public UserService userService(){ return new UserService(); }}
目前spring.xml
这种方式已经很少见了更多的是使用Spring MVC
或者Spring Boot
这两种也是基于spring.xml
这种方式在内部创建一个ApplicationContext
但是也有区别
1、Spring MVC
创建的是XmlWebApplicationContext
和ClassPathXmlApplicationContext
类似都是基于XML配置的
2、Spring Boot
创建的是AnnotationConfigApplicationContext
后续重点学习研究的是AnnotationConfigApplicationContext
这一种
Spring中是如何创建一个对象
AnnotationConfigApplicationContext
可以简单理解为创建Java对象当调用context.getBean(userService)
方法时创建一个对象。那么问题来了方法内部如何知道userService
对应的是UserService
类呢
可以分析出来AnnotationConfigApplicationContext
的构造方法做的一些事情
1、解析AppConfig.class
得到扫描路径
2、遍历扫描路径下的所有Java类如果类上面有Component、Service等注解那么Spring就会把这个类记录下来存放在一个Map里比如像Map<String, Class>
Spring源码中叫BeanDefinitionMap
3、Spring根据规则生成当前类的beanName
作为存入Map时的key当前类作为存入Map时的valueSpring中的beanName
默认是类名首字母小写
Bean的创建过程
Spring到底是如何来创建一个Bean的呢也就是Bean创建的生命周期。大致流程如下
1、利用该类的构造方法来实例化得到一个对象有多个构造方法时Spring会做出选择推断构造方法
2、得到一个对象后Spring会判断该对象中是否存在被Autowired注解了的属性把这些属性找出来并由Spring进行赋值依赖注入
3、依赖注入后Spring会判断该对象是否实现了BeanNameAware接口、BeanClassLoaderAware接口、BeanFactoryAware接口如果实现了就表示当前对象必须实现该接口中所定义的setBeanName()、setBeanClassLoader()、 setBeanFactory()方法那Spring就会调用这些方法并传入相应的参数Aware回调
4、Aware回调后Spring会判断该对象中是否存在某个方法被PostConstruct注解了如果存在Spring会调用当前对象的此方法初始化前
5、Spring会判断该对象是否实现了InitializingBean接口如果实现了就表示当前对象必须实现该接口中的afterPropertiesSet()方法那Spring就会调用当前对象中的afterPropertiesSet()方法初始化
6、Spring会判断当前对象需不需要进行AOP如果不需要那么Bean就创建完了如果需要进行AOP则会进行动态代理并生成一个代理对象做为Bean初始化后
注意不用AOP时Bean就是构造方法创建的普通对象需要AOP时Bean是代理类实例化的对象
Bean对象创建完成后如果是单例Bean就放在Map里下次可以直接从Map中直接获取Spring源码中Map就是单例池如果是原型Bean就不用放在Map里下次重新创建
推断构造方法
选择构造方法的判断逻辑
1、只有一个构造方法无论是否有参Spring都会选择这个
2、有多个构造方法时Spring会选择无参的构造方法无参本身就是一种默认
没有无参构造方法且构造方法上面都没有Autowired注解时报错Spring不知道选择哪一个
没有无参构造方法但是某个构造方法上面添加了Autowired注解Spring选择这一个构造方法
注意Spring选择有参构造方法时Spring会先根据参数类型类型相同再根据参数名字去找Bean对象类型和名字都找不到就报错
推断构造方法确定用哪个构造方法确定入参的Bean对象
AOP大致流程
判断当前Bean对象需不需要进行AOP
1、找出所有的切面Bean
2、遍历切面中的每个方法看是否写了Before、After等注解
3、如果写了则判断所对应的Pointcut是否和当前Bean对象的类匹配
4、如果匹配则表示当前Bean对象有匹配的的Pointcut需要进行AOP
利用cglib进行AOP的大致流程cglib说白了就是父子类
1、生成代理类XXServiceProxy代理类继承XXService
2、代理类中重写了父类的方法
3、代理类中有一个target属性该属性的值为被代理对象
这里的被代理对象是推断构造方法实例化的对象完成了依赖注入、初始化等
4、代理类中的方法被执行时先执行before的切面逻辑再执行target.目标方法
注意XXServiceProxy是代理类它实例化出来的是代理对象target是被代理对象
思考代理对象的属性是null没有进行依赖注入为什么
没有必要大部分情况用不到需要用的话也可以通过target获取
Spring事务
在某个方法上加了Transactional注解后就表示该方法在调用时会开启Spring事务而这个方法所在的类所对应的Bean对象会是该类的代理对象。
1、判断当前执行的方法是否存在Transactional注解
2、如果存在则利用事务管理器TransactionMananger新建一个数据库连接
3、修改数据库连接的autocommit为false
4、执行target.目标方法业务逻辑的sql
5、执行完之后没有异常则提交否则回滚
事务失效的场景分析
1、调用目标方法的是否为代理类使用代理类调用时才有切面的逻辑
2、是否使用的同一个事务管理器或者说是否同一个数据库连接