spring 06 Aware 接口

Aware 接口

  • Aware 接口及 InitializingBean 接口
  1. Aware 接口提供了一种【内置】 的注入手段,例如
    • BeanNameAware 注入 bean 的名字
    • BeanFactoryAware 注入 BeanFactory 容器
    • ApplicationContextAware 注入 ApplicationContext 容器
    • EmbeddedValueResolverAware 注入 ${} 解析器
  2. InitializingBean 接口提供了一种【内置】的初始化手段
  3. 对比
    • 内置的注入和初始化不受扩展功能的影响,总会被执行
    • 而扩展功能受某些情况影响可能会失效
    • 因此 Spring 框架内部的类常用内置注入和初始化
    • 拓展功能需要添加相应的后处理器 ,如
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class); // 解析 @Autowired、 @Value
        context.registerBean(CommonAnnotationBeanPostProcessor.class);  // 解析 @Resource、@PostConstruct、@PreDestroy
        context.registerBean(ConfigurationClassPostProcessor.class);   // 解析 @ComponentScan、 @Bean、 @Import、 @ImportResource
点击查看代码
@Slf4j
public class S06Bean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, EmbeddedValueResolverAware,InitializingBean {

    /**
     * 注入 Bean 的名字
     * @param s Bean 的名字
     */
    @Override
    public void setBeanName(String s) {
        log.info("当前 Bean" + this + "名字是" + s);
    }

    /**
     * 初始化
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {

    }

    /**
     * 注入 BeanFactory 容器
     * @param beanFactory
     * @throws BeansException
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.info("当前 Bean" + this + "  BeanFactory 是" + beanFactory);

    }

    /**
     *注入 ApplicationContext 容器
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("当前 Bean" + this + "  ApplicationContext 是 " + applicationContext);

    }

    /**
     * 注入 ${} 解析器
     * @param resolver
     */
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {

    }
}

配置类 @Autowired 失效分析

Java 配置类不包含 BeanFactoryPostProcessor 的情况

sequenceDiagram participant ac as ApplicationContext participant bfpp as BeanFactoryPostProcessor participant bpp as BeanPostProcessor participant config as Java配置类 ac ->> bfpp : 1. 执行 BeanFactoryPostProcessor ac ->> bpp : 2. 注册 BeanPostProcessor ac ->> +config : 3. 创建和初始化 bpp ->> config : 3.1 依赖注入扩展(如 @Value 和 @Autowired) bpp ->> config : 3.2 初始化扩展(如 @PostConstruct) ac ->> config : 3.3 执行 Aware 及 InitializingBean config -->> -ac : 3.4 创建成功

Java 配置类包含 BeanFactoryPostProcessor 的情况,因此要创建其中的 BeanFactoryPostProcessor 必须提前创建 Java 配置类,而此时的 BeanPostProcessor 还未准备好,导致 @Autowired 等注解失效

sequenceDiagram participant ac as ApplicationContext participant bfpp as BeanFactoryPostProcessor participant bpp as BeanPostProcessor participant config as Java配置类 ac ->> +config : 3. 创建和初始化 ac ->> config : 3.1 执行 Aware 及 InitializingBean config -->> -ac : 3.2 创建成功 ac ->> bfpp : 1. 执行 BeanFactoryPostProcessor ac ->> bpp : 2. 注册 BeanPostProcessor

对应代码

@Configuration
public class MyConfig1 {

    private static final Logger log = LoggerFactory.getLogger(MyConfig1.class);

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        log.debug("注入 ApplicationContext");
    }

    @PostConstruct
    public void init() {
        log.debug("初始化");
    }

    @Bean //  ⬅️ 注释或添加 beanFactory 后处理器对应上方两种情况
    public BeanFactoryPostProcessor processor1() {
        return beanFactory -> {
            log.debug("执行 processor1");
        };
    }

}

注意

解决方法:

  • 用内置依赖注入和初始化取代扩展依赖注入和初始化
  • 用静态工厂方法代替实例工厂方法,避免工厂对象提前被创建
点击查看代码
@Slf4j
public class S06Config1  implements InitializingBean, BeanNameAware, ApplicationContextAware {

    @Autowired
    public void getApplicationContext(ApplicationContext applicationContext) {
        log.info("@Autowired 注入的 ApplicationContext 是" + applicationContext);
    }

    @PostConstruct
    public void init() {
        log.info("@PostConstruct 初始化");
    }

    @Override
    public void setBeanName(String s) {
        log.info("当前 Bean" + this + "名字是" + s);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info(this + "初始化。。。");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("当前 Bean" + this + " ApplicationContext 名字是" + applicationContext);

    }

    @Bean
    public  BeanFactoryPostProcessor getBeanFactoryPostProcessor() {
        return b ->{
            log.info("执行 BeanFactoryPostProcessor");
        };
    }

    //用静态工厂方法代替实例工厂方法,避免工厂对象提前被创建
//    @Bean
//    public static BeanFactoryPostProcessor getBeanFactoryPostProcessor() {
//        return b ->{
//            log.info("执行 BeanFactoryPostProcessor");
//        };
//    }
}

posted @ 2022-06-19 17:01  xy7112  阅读(47)  评论(0)    收藏  举报