Spring高级接口Aware浅析

 

Aware 接口功能阐述

Aware 接口提供了一种【内置】 的注入手段,例如

a.BeanNameAware 注入 bean 的名字

b.BeanFactoryAware 注入 BeanFactory 容器

c.ApplicationContextAware 注入 ApplicationContext 容器

d.EmbeddedValueResolverAware 注入 ${} 解析器

 

功能案例演示

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 aaa(ApplicationContext applicationContext) {
      log.debug("当前bean " + this + " 使用@Autowired 容器是:" + applicationContext);
  }
  @PostConstruct
  public void init() {
      log.debug("当前bean " + this + " 使用@PostConstruct 初始化");
  }
}

测试:

  GenericApplicationContext context = new GenericApplicationContext();   
context.registerBean("myBean", MyBean.class);
context.refresh(); 
context.close();

可能这里有人会有疑问: b、c、d 的功能用 @Autowired 就能实现啊, 为啥还要用 Aware 接口呢

简单地说:

a.@Autowired 的解析需要用到 bean 后处理器, 属于扩展功能

b.而 Aware 接口属于内置功能, 不加任何扩展, Spring 就能识别

某些情况下, 扩展功能会失效, 而内置功能不会失效

如下所示:

  @Autowired
  public void aaa(ApplicationContext applicationContext) {
      log.debug("当前bean " + this + " 使用@Autowired 容器是:" + applicationContext);
  }
  @PostConstruct
  public void init() {
      log.debug("当前bean " + this + " 使用@PostConstruct 初始化");
  }

在这里,你会发现用 Aware 注入 ApplicationContext 成功, 而 @Autowired 注入 ApplicationContext 失败

 

扩展功能失效场景分析

@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");
      };
  }
}
context.refresh(); 

这行代码的执行顺序,到容器里找到所有的.beanFactory 后处理器来执行,添加 bean 后处理器,初始化单例。

Java 配置类不包含 BeanFactoryPostProcessor 的情况

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

对应代码

@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");
      };
  }
}

注意

解决方法:

  • 用内置依赖注入和初始化取代扩展依赖注入和初始化
  • 用静态工厂方法代替实例工厂方法,避免工厂对象提前被创建

测试:

 GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("myConfig2", MyConfig2.class);
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
context.registerBean(CommonAnnotationBeanPostProcessor.class);
context.registerBean(ConfigurationClassPostProcessor.class);
context.refresh();
context.close();

输出结果:

 

总结

  • Aware 接口提供了一种【内置】 的注入手段, 可以注入 BeanFactory, ApplicationContext
  • InitializingBean 接口提供了一种【内置】的初始化手段
  • 内置的注入和初始化不受扩展功能的影响, 总会被执行, 因此 Spring 框架内部的类常用它们

关于Spring高级接口Aware浅析的文章就介绍至此,更多相关Spring Aware内容请搜索编程宝库以前的文章,希望以后支持编程宝库

 一、Java使用BigDecimal公式计算(精确计算)介绍: 使用BigDecimal加减乘除方法运算,可以使用BigDecimal类提供的add、subtract、 ...