代码块
一 概述
xml时代,Spring Bean是通过ClassPathXmlApplicationContext创建管理的. 而后,新版SpringMVC和Spring Boot 替换为AnnotationConfigApplicationContext,支持注解的方式创建Bean. 实例代码:
@ComponentScan("com.zhouyu")
public class AppConfig {
@Bean
public UserService userService(){
return new UserService();
}
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();
二 扫描所有需要创建的Bean
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
- 解析AppConfig.class, 获取ComponentScan注解定义的包路径.
- 获取包路径下所有class,查看是否有@Component、 @Service等注解. 如果有,则保存下来Map<String, Class> --BeanDefinitionMap, key:按规则生成的beanName,value就是类本身
三 Bean创建
context.getBean("userService")
3.1 利用构造方法实例化对象
- 通过beanName, 从BeanDefinitionMap中,获取到要创建对象的class类
- 调用class类的构造方法实例化一个对象
推断构造方法
推断构造方法:存在多个构造方法,如何进行选择
- 如果只有一个,直接使用它
- 如果大于一个,其中存在无参构造方法,调用无参构造方法
- 如果大于一个,且不存在无参构造方法,但是某个存在注解@Autowired,则使用@Autowired注解这个
- 如果大于一个,且不存在无参构造方法, 所有构造方法都没有使用@Autowired,则报错
3.2 属性注入
获取类的所有属性,检查是否包含@Autowired,@Resource等注解的属性.存在则Spring找到并注入(依赖注入). 这里可能存在循环依赖.
3.3 Aware接口回调
通过检查实例化对象是否实现了XXXAware接口, 容器在属性注入后,回调接口方法,传入Bean创建时候的环境信息给Bean
BeanNameAware: 传递beanName
BeanClassLoaderAware: 传递类加载器
BeanFactoryAware:传递beanFactory
...
3.4 初始化前置调用
Spring会判断该对象中是否存在某个方法被@PostConstruct注解 了,如果存在,Spring会调用当前对象的此方法
3.5 初始化调用
Spring会判断该对象是否实现了InitializingBean接口,如果实现了,就表示当前对象必须实现该接口中的afterPropertiesSet()方法,那Spring就会调用当
前对象中的afterPropertiesSet()方法
3.6 初始化后置调用
Spring会判断当前对象需不需要进行AOP,如果不需要那么Bean就创建完 了,如果需要进行AOP,则会进行动态代理并生成一个代理对象做为Bean
当Spring根据UserService类来创建一个Bean时:
- 如果不用进行AOP,那么Bean就是UserService类的构造方法所得到的对象。
- 如果需要进行AOP,那么Bean就是UserService的代理类所实例化得到的对象,而不是UserService本身所得到的对象。
四 单例与原型
通过@Scope注解. 判断对象时 单例还是原型.
- 如果是单例, 则将对象放入单例池(Map<String,Object> ),返回
- 如果是原型,则直接返回
五. AOP扩展
5.1 AOP大致流程
1) 判断是否需要AOP
a. 获取所有的切面Bean
b. 遍历所有方法, 是否@Before、@After等注解
c. 如果有,则判断所对应的Pointcut是否和当前Bean对象的类是否匹配
d. 如果匹配到,表示需要AOP
2) cglib进行AOP的大致流程
a. 生成代理类UserServiceProxy,代理类继承UserService
b. UserServiceProxy 重写UserService中方法(test),且持有元UserService对象(target)
c. 重写代码
执行切面逻辑(@Before)
调用target.test()
执行切面逻辑(@after)
5.2 Spring 事务大致流程
Spring事务也是通过AOP实现的
大致流程如下:
a. 判断当前执行的方法是否存在@Transactional注解
b. 如果存在,则利用事务管理器(TransactionMananger)新建一个数据库连接
c. 修改数据库连接的autocommit为false
d. 执行业务代码即执行sql
e. 执行完了之后如果没有出现异常,则提交,否则回滚
大坑
Spring事务是否会失效的判断标准:某个加了@Transactional注解的方法被调用时,要判断到底是不是直接被代理对象调用的,如果是则事务会生效,如果不是则失效。 当然,所有AOP实现都是如此.