## 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(); } } } ```