美文网首页spring
Spring原理分析-Aware接口&InitializingB

Spring原理分析-Aware接口&InitializingB

作者: 石头耳东 | 来源:发表于2022-04-13 09:23 被阅读0次

前置文章:
一、Spring原理分析-BeanFactory与ApplicationContext
二、Spring原理分析-Bean生命周期
三、Spring原理分析-Bean后处理器
四、Spring原理分析-BeanFactory后处理器

零、本文纲要

一、Aware接口&InitializingBean
1、基础准备
2、总结
3、补充:EmbeddedValueResolverAware
二、@Autowired和@PostConstruct注解失效
1、基础准备
2、失效情形
3、失效原因
4、使用Aware接口避免失效
5、总结
补充总结

一、Aware接口&InitializingBean

1、基础准备

  • ① 编写 MyBean 实现 BeanNameAware, ApplicationContextAware, InitializingBean 接口,并使用 @Autowired、@PostConstruct 注解,如下:
public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {

    private static final Logger log = LoggerFactory.getLogger(MyBean.class);
    @Override
    public void setBeanName(String name) {
        log.debug("当前Bean:" + this + "的名字是:{}", name);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.debug("当前Bean:" + this + "的容器是:{}", applicationContext);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.debug("当前Bean:" + this + "初始化");
    }

    @Autowired
    public void injectContext(ApplicationContext applicationContext){
        log.debug("当前Bean:" + this + "[Autowired]的容器是:{}", applicationContext);
    }

    @PostConstruct
    public void init(){
        log.debug("当前Bean:" + this + "[PostConstruct]初始化");
    }
}
  • ② 编写测试类

注释掉AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor两个后处理器,如下:

public class Demo06 {
    private static final Logger log = LoggerFactory.getLogger(Demo06.class);

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("myBean", MyBean.class);
        //context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        //context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.refresh();
        context.close();
    }
}
Aware接口&InitializingBean.png

2、总结

【A】、各类Aware及其作用:

Ⅰ BeanNameAware 注入 bean 的名字;
Ⅱ BeanFactoryAware 注入 BeanFactory 容器;
Ⅲ ApplicationContextAware 注入 ApplicationContext 容器;
Ⅳ EmbeddedValueResolverAware 解析 ${}。

【B】、为什么后处理器能实现的功能要通过Aware接口实现:

对比之下可以发现,原生干净的 GenericApplicationContext 容器并没有各类后处理器,需要我们手动添加才能实现拓展。
而实现这类接口,原生容器就能直接实现拓展。

3、补充:EmbeddedValueResolverAware

BeanFactoryAware与ApplicationContext类似,此处不演示。演示实现EmbeddedValueResolverAware接口,如下:

  • ① 让MyBean实现EmbeddedValueResolverAware接口

实现接口实现方法,并添加如下内容:

private StringValueResolver resolver = null;
// 将 resolver 器对象绑定为 MyBean 属性
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
    this.resolver = resolver;
}
// 用于返回解析 ${} 内容
public String getPropertiesValues(String propertiesValues){
    return resolver.resolveStringValue(propertiesValues);
}
  • ② 修改测试类
// 从容器中获取 myBean 对象
MyBean myBean = context.getBean("myBean", MyBean.class);
// 输出环境变量 JAVA_HOME 大小写均可
System.out.println(myBean.getPropertiesValues("${java_home}"));
EmbeddedValueResolverAware解析.png

二、@Autowired和@PostConstruct注解失效

1、基础准备

  • ① 编写MyConfig1类
@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("初始化");
    }
}
  • ② 修改测试类

添加ConfigurationClassPostProcessor后处理器,注册MyConfig1,如下:

public class Demo06 {
    private static final Logger log = LoggerFactory.getLogger(Demo06.class);

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("myConfig1", MyConfig1.class);

        // 解析 @Autowired、@Value 注解
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);

        // 解析 @Resource、@PostConstruct、@PreDestroy 注解
        context.registerBean(CommonAnnotationBeanPostProcessor.class);

        // 解析 @Component、ConfigurationProperties、@Import、@ImportSource 注解
        context.registerBean(ConfigurationClassPostProcessor.class);

        context.refresh();
        context.close();
    }
}
基础准备测试通过的情形.png

此时,我们可以看到@Autowired和@PostConstruct都生效了。

2、失效情形

  • ① 修改MyConfig1类

添加@Bean的相关内容,如下:

@Bean
public BeanFactoryPostProcessor processor1(){
    return beanFactory -> {
        log.debug("执行 processor1");
    };
}
  • ② 测试
@Autowired和@PostConstruct都失效了.png

此时,后处理器拓展出来的注解都失效了。

3、失效原因

  • ① Java 配置类不包含 BeanFactoryPostProcessor 的情况
Java 配置类不包含 BeanFactoryPostProcessor 的情况.png
  • ② Java 配置类包含 BeanFactoryPostProcessor 的情况

案例中需要被执行的 BeanFactoryPostProcessor 在 MyConfig1 配置类中。为了保证 BeanFactoryPostProcessor 能顺利执行,此时会先创建和初始化 MyConfig1 对象。但是,注册 BeanPostProcessor 的步骤并没有执行到,所以 @Autowired 这类注解并没有生效。

Java 配置类包含 BeanFactoryPostProcessor 的情况.png

为了证明如上顺序,我们继续测试。

  • ③ 测试不失效的情形来佐证

添加 MyConfig2 类,如下:

@Configuration
public class MyConfig2 {

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

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

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

修改测试类,添加注册myConfig2,如下:

context.registerBean("myConfig2", MyConfig2.class);
测试不失效的情形.png

可以看到由于 MyConfig2 类中没有 BeanFactoryPostProcessor 的调用需被执行,所以其中的 BeanPostProcessor 可以正常执行到。

  • ④ 结论

BeanFactoryPostProcessor 的执行顺序问题导致 BeanPostProcessor 相关配置失效。

4、使用Aware接口避免失效

  • ① 编写MyConfig3

实现InitializingBean、ApplicationContextAware接口,如下:

@Configuration
public class MyConfig3 implements InitializingBean, ApplicationContextAware {

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

    @Bean
    public BeanFactoryPostProcessor processor3(){
        return beanFactory -> {
            log.debug("MyConfig3 执行 processor3");
        };
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.debug("MyConfig3 初始化");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.debug("MyConfig3 注入 applicationContext");
    }
}
  • ② 修改测试类

添加注册myConfig3的内容,如下:

context.registerBean("myConfig3", MyConfig3.class);
使用Aware接口避免失效.png

5、总结

  • ① 尽量避免在调用BeanFactoryPostProcessor的Bean中使用BeanPostProcessor相关配置;
  • ② 如果无法避免两者在同一个Bean中均要用到的情形,则考虑实现Aware接口来实现BeanPostProcessor类似的功能。

补充总结:

  • ① AutowiredAnnotationBeanPostProcessor后处理器:解析 @Autowired、@Value 注解;
  • ② CommonAnnotationBeanPostProcessor后处理器:解析 @Resource、@PostConstruct、@PreDestroy 注解;
  • ③ ConfigurationClassPostProcessor后处理器:解析 @Component、ConfigurationProperties、@Import、@ImportSource 注解。

三、结尾

以上即为Aware接口&InitializingBean的全部内容,感谢阅读。

相关文章

  • Spring原理分析-Aware接口&InitializingB

    前置文章:一、Spring原理分析-BeanFactory与ApplicationContext[https://...

  • Spring Aware容器感知技术

    ​ Spring Aware是什么 Spring提供Aware接口能让Bean感知Spring容器的存在,即让Be...

  • spring的aware们

    Aware是什么 spring框架提供了多个*Aware接口,用于辅助Spring Bean编程访问Spring容...

  • Aware Mode

    Aware接口 Spring中提供了一些以Aware结尾的接口,实现了Aware接口的bean在被初始化之后,可以...

  • Spring Aware相关接口的使用

    在spring中提供了很多关于Aware的接口,该接口拥有一个统一的规律,即在spring对实现了Aware相关接...

  • Spring知识点整理(持续更新)

    Aware接口使用 Spring中Aware.java是个没有任何方法的接口,有很多子接口,常见的比如BeanNa...

  • Spring5IOC容器解析——Aware接口

    Aware Aware 是 Spring 中的一个根接口,继承该接口的子接口有很多,但是该接口没有任何方法,所以大...

  • spring中Aware后缀

    aware: 意识到的;知道的; spring中带有Aware后缀的接口主要是和bean有关,实现了Aware后...

  • Spring Aware 接口

    有些时候,在 Bean 的初始化中,需要使用 Spring 框架自身的对象来执行一些操作,比如获取 Servlet...

  • SpringIoc之Aware

    Aware 概述 Aware是Spring提供的一个标记超接口,指示bean有资格通过回调样式的方法由Spring...

网友评论

    本文标题:Spring原理分析-Aware接口&InitializingB

    本文链接:https://www.haomeiwen.com/subject/mhunsrtx.html