## IOC容器
1. 往容器中添加Bean的四种方式
* @Component (@Controller, @Service, @Repository): 适用于自己写的类
* @Bean (@Configuration里面): 可以添加三方组件(因为第三方组件是别人写的, 无法在其文件中写@Component)
* @Import : 快速导入组件
- 普通: 简化三方组件的简单导入(比如很多@Bean只需要简单new一下, 使用此注解就减少了代码量)
- 扩展1: ImportSelector#selectImports, 返回需要导入的全类名字符串数组
- 扩展2: ImportBeanDefinitionRegistrar#registerBeanDefinitions, 手动在BeanDefinition级别向容器中注册组件
- 备注: Spring的@EnableXXX功能都是使用此注解向容器中添加YYY组件实现的, 比如@EnableAsync, @EnableScheduling, @EnableAspectJAutoProxy等等
* FactoryBean: 工厂Bean, getObject方法的返回值导入组件.
- 适用于创建Bean是一个非常复杂代码量很多的场景, 比如ProxyFactoryBean, SqlSessionFactoryBean
2. 组件扫描与定制化
* 扫描: @Configuration上标注的@ComponentScan
- 指定基础包, 可以自定义包含或排除的过滤器, 过滤器类型: 注解, 指定类型, 自定义等
* 定制化
- @Scope: 是否单实例的. 默认为单实例, 容器启动就创建对象, 可以加入@Lazy设置为延迟加载; 设置为多实例后变为懒汉模式加载
- @Conditional: 条件满足时才加入容器
- @Profile: 环境满足时才加入容器
* 属性赋值
- @PropertySource: 指定property文件
- @Value: 支持Spel表达式
* 自动装配
- @Autowired: 先按照类型装配, 多个时再按照属性名称装配
* @Primary: 优先装配的组件
* @Qualifier: 指定特定组件状态
* JSR250的@Resource, JSR330的@Inject, 功能类似却不如@Autowired完善, 建议@Autowired
* 使用底层组件: 实现xxxAware接口
3. 组件的生命周期
* 单实例bean容器启动创建, 容器销毁调用销毁方法; 多实例bean启动不创建, 且销毁IOC容器不管理
* 初始化和销毁方法
- @Bean的initMethod, destroyMethod指定
- Bean实现InitializingBean, DisposableBean接口
- JSR250规范: @PostConstruct, @ProDestory注解
* 后置处理器: BeanPostProcessor, 拦截所有bean的创建过程, 在init方法前后执行
## AOP切面
1. 开启: @EnableAspectJAutoProxy
2. 使用: 编写一个切面(@Aspect), 并将其放入容器中(@Component)即可
* 切点: @Pointcut
* 通知: 前置/后置/异常/最终/环绕
## 启动流程
```
AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext(MainConfig.class);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
this(); // 初始化beanFactory工程, reader 读取器, scanner 扫描器
this.beanFactory = new DefaultListableBeanFactory(); // 初始化bean工厂(父类的空参数构造方法中), new这个是因为功能最多(可以查看类继承结构)
this.reader = new AnnotatedBeanDefinitionReader(this); // 注解bean定义读取器: 创建标准环境(系统属性/系统环境变量), 表达式评估器conditionEvaluator
// 向容器中注册注解配置处理器: ConfigurationClassPostProcessor, AutowiredAnnotationBeanPostProcessor等
this.scanner = new ClassPathBeanDefinitionScanner(this); // 类路径bean定义扫描器: 标记@Component注解是扫描时需要加入容器的过滤器
register(componentClasses); // 向容器中注册主配置类
refresh(); // 容器刷新(12步骤)
//~~~~~~~~~~~~~~~~~~~~~~~~~~refresh()~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing. ==> 1.准备刷新: 记录时间, 设置状态, 初始化属性源(空方法), 验证必需属性
prepareRefresh();
// Tell the subclass to refresh the internal bean factory. ==> 2.刷新bean工厂: 仅设置个状态, 如果是RefreshableApplicationContext则会销毁单实例bean,重新创建
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context. ==> 3.设置spel表达式解析器,资源编辑注册器,xxxAware后置处理器,监听探测器,向容器中注册环境/系统属性/系统环境
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses. ==> 4.空方法
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context. ==> 5.**bean工厂后置处理器执行: 解析配置类(@Configuration), 把所有的bean定义都加入到工厂中**
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation. ==> 6.注册bean后缀处理器, 用于拦截bean的创建
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context. ==> 7.初始化消息源(策略模式解析消息,支持参数化和国际化)
initMessageSource();
// Initialize event multicaster for this context. ==> 8.初始化事件多播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses. ==> 9.空方法(留给子类实现, SpringBoot中在此处启动tomcat)
onRefresh();
// Check for listener beans and register them. ==> 10.注册监听器, 并发布早期事件
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons. ==> 11.**冻结配置, 并初始化所有的单实例bean**
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event. ==> 12.完成刷新: 清理缓存, 初始化生命周期处理器并调用器onRefresh方法(eureka发现的启动在此处), 发布刷新完成事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
```