Spring原理学习(四)Aware 接口

1、Aware 接口

Aware 接口用于注入一些与容器相关信息,例如:

  • BeanNameAware 注入 bean 的名字
  • BeanFactoryAware 注入 BeanFactory 容器
  • ApplicationContextAware 注入 ApplicationContext 容器
  • EmbeddedValueResolverAware ${}

主启动类

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

    public static void main(String[] args) {

        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("mybean", MyBean.class);

        context.refresh();
        context.close();

    }
}

MyBean类

InitializingBean 接口提供了一种【内置】的初始化手段

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 + " 初始化");
    }
}

结果:

[main] com.itheima.a06.MyBean - 当前bean com.itheima.a06.MyBean@43a0cee9 名字叫:mybean 
[main] com.itheima.a06.MyBean - 当前bean com.itheima.a06.MyBean@43a0cee9 容器是:org.springframework.context.support.GenericApplicationContext@97e1986, started on Thu Nov 03 13:55:31 CST 2022 
[main] com.itheima.a06.MyBean - 当前bean com.itheima.a06.MyBean@43a0cee9 初始化 

为什么要使用 Aware 接口?

简单地说:

  • @Autowired 的解析需要用到 bean 后处理器,属于扩展功能
  • 而 Aware 接口属于内置功能,不加任何扩展,Spring 就能识别
  • 某些情况下, 扩展功能会失效, 而内置功能不会失效

例如下面这个例子:你会发现用 Aware 注入 ApplicationContext 成功,而 @Autowired 注入 ApplicationContext 失败要想生效就得加处理器。

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 初始化");
    }
}

结果: @Autowired 和 @PostConstruct 失效

[main] com.itheima.a06.MyBean - 当前bean com.itheima.a06.MyBean@43a0cee9 名字叫:mybean 
[main] com.itheima.a06.MyBean - 当前bean com.itheima.a06.MyBean@43a0cee9 容器是:org.springframework.context.support.GenericApplicationContext@97e1986, started on Thu Nov 03 13:55:31 CST 2022 
[main] com.itheima.a06.MyBean - 当前bean com.itheima.a06.MyBean@43a0cee9 初始化 

如果想让@Autowire,和@PostConstruct生效,就得添加后处理器

context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
context.registerBean(CommonAnnotationBeanPostProcessor.class);

  对比:

  • 内置的注入和初始化不受扩展功能的影响,总会被执行

  • 而扩展功能受某些情况影响可能会失效

  • 因此 Spring 框架内部的类常用内置注入和初始化

2、配置类 @Autowired 失效分析

配置类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("初始化");
    }

    @Bean //  beanFactory 后处理器
    public BeanFactoryPostProcessor processor1() {
        return beanFactory -> {
            log.debug("执行 processor1");
        };
    }
}

主启动类

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

    public static void main(String[] args) {

        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("myConfig1", MyConfig1.class);
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.registerBean(ConfigurationClassPostProcessor.class);

        //执行顺序: 1. beanFactory 后处理器,  2. 添加 bean 后处理器, 3. 初始化单例
        context.refresh();

        context.close();

    }
}

 结果:@Autowired,@PostConstruct注解失效

[main] com.itheima.a06.MyConfig1 - 执行 processor1 

Java 配置类不包含 BeanFactoryPostProce

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

解决办法

  • 用内置依赖注入和初始化取代扩展依赖注入和初始化

  • 用静态工厂方法代替实例工厂方法,避免工厂对象提前被创建

@Configuration
public class MyConfig2 implements InitializingBean, ApplicationContextAware {

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

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

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

    @Bean //  beanFactory 后处理器
    public BeanFactoryPostProcessor processor2() {
        return beanFactory -> {
            log.debug("执行 processor2");
        };
    }
}

 主启动类

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

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("myConfig2", MyConfig2.class);
        context.registerBean(ConfigurationClassPostProcessor.class);

        context.refresh();
        context.close();

    }
}

结果:

[main] com.itheima.a06.MyConfig2 - 注入 ApplicationContext 
[main] com.itheima.a06.MyConfig2 - 初始化 
[main] com.itheima.a06.MyConfig2 - 执行 processor2 
  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鲁蛋儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值