赞
踩
今天将会学到Aware 接口及 InitializingBean 接口
我们可以先了解他们的作用:
1. Aware 接口用于注入一些与容器相关信息, 例如
a. BeanNameAware 注入 bean 的名字
b. BeanFactoryAware 注入 BeanFactory 容器
c. ApplicationContextAware 注入 ApplicationContext 容器
d. EmbeddedValueResolverAware ${}
2. InitializingBean 接口提供了一种【内置】的初始化手段
明白了作用我们可以写两个配置类来验证
配置类一我们用正常注解的方式注入bean以及实现bean的初始化方法
- @Configuration
- public class MyConfig1 {
-
- private static final Logger log = LoggerFactory.getLogger(MyConfig1.class);
-
- @Autowired
- public void setApplicationContext(ApplicationContext applicationContext) {
- log.debug("@Autowired注入 ApplicationContext");
- }
-
- @PostConstruct
- public void init() {
- log.debug("@PostConstruct初始化");
- }
-
- @Bean // beanFactory 后处理器
- public BeanFactoryPostProcessor processor1() {
- return beanFactory -> {
- log.debug("执行 processor1");
- };
- }
-
- }
配置类二我们用实现上述两个接口的方法来实现注入bean以及实现bean的初始化方法
- @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");
- };
- }
- }
创建启动类,并将这两个配置类bean对象注入容器中,观察结果
- public class Spring06Application {
-
- public static void main(String[] args) {
- //创建一个干净的容器
- GenericApplicationContext context = new GenericApplicationContext();
- //注入bean
- context.registerBean("myConfig1", MyConfig1.class);
- context.registerBean("myConfig2", MyConfig2.class);
-
- //初始化容器
- context.refresh();
- for (String name : context.getBeanDefinitionNames()) {
- System.out.println(name);
- }
-
- //销毁容器
- context.close();
-
- }
- }
可以看到两个配置类的bean对象都成功注入容器当中,但是只有实现接口的方法实现了bean对象的注入以及bean的初始化方法(由于容器中缺少了解析bean的bean后处理器)
我们往容器中添加bean后处理器解析注解
- context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
- context.registerBean(CommonAnnotationBeanPostProcessor.class);
此时可以看到利用注解的方式注入bean也成功实现,bean的初始化方法也成功实现
总结:实现Aware 接口及 InitializingBean 接口,由于提供了内置的注入方法,所以不需要依赖与bean的后处理器,注解方式需要依赖与bean后处理器,用 @Autowired 就能实现啊, 为啥还要用 Aware 接口呢
简单地说:
a. @Autowired 的解析需要用到 bean 后处理器, 属于扩展功能
b. 而 Aware 接口属于内置功能, 不加任何扩展, Spring 就能识别
某些情况下, 扩展功能会失效, 而内置功能不会失效
我们再容器中添加添加解析bean注解的后处理器,把beanfactory后处理器注入容器中观察结果
- public class Spring06Application {
-
- public static void main(String[] args) {
- //创建一个干净的容器
- GenericApplicationContext context = new GenericApplicationContext();
- //注入bean
- // context.registerBean("myBean",MyBean.class);
- context.registerBean("myConfig1", MyConfig1.class);
- context.registerBean("myConfig2", MyConfig2.class);
-
- context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
- context.registerBean(CommonAnnotationBeanPostProcessor.class);
- context.registerBean(ConfigurationClassPostProcessor.class);
- //初始化容器
- context.refresh();
-
- for (String name : context.getBeanDefinitionNames()) {
- System.out.println(name);
- }
- //销毁容器
- context.close();
-
- }
- }
可以看到用注解注入的bean以及初始化方法并没有被成功解析
对比
内置的注入和初始化不受扩展功能的影响,总会被执行
而扩展功能受某些情况影响可能会失效
因此 Spring 框架内部的类常用内置注入和初始化
Java 配置类包含 BeanFactoryPostProcessor 的情况,因此要创建其中的 BeanFactoryPostProcessor 必须提前创建 Java 配置类,而此时的 BeanPostProcessor 还未准备好,导致 @Autowired 等注解失效
注意
解决方法:
用内置依赖注入和初始化取代扩展依赖注入和初始化
用静态工厂方法代替实例工厂方法,避免工厂对象提前被创建
准备好类并实现初始化方法接口(此时有注解方式实现初始化,接口方式实现初始化,bean注解方式指定初始化方法)
- public class Bean1 implements InitializingBean {
- private static final Logger log = LoggerFactory.getLogger(Bean1.class);
-
- @PostConstruct
- public void init1() {
- log.debug("初始化1");
- }
-
- @Override
- public void afterPropertiesSet() throws Exception {
- log.debug("初始化2");
- }
-
- public void init3() {
- log.debug("初始化3");
- }
- }
创建类实现销毁方法接口
- public class Bean2 implements DisposableBean {
- private static final Logger log = LoggerFactory.getLogger(Bean2.class);
-
- @PreDestroy
- public void destroy1() {
- log.debug("销毁1");
- }
-
- @Override
- public void destroy() throws Exception {
- log.debug("销毁2");
- }
-
- public void destroy3() {
- log.debug("销毁3");
- }
- }
Spring 提供了多种初始化手段,除了课堂上讲的 @PostConstruct,@Bean(initMethod) 之外,还可以实现 InitializingBean 接口来进行初始化,如果同一个 bean 用了以上手段声明了 3 个初始化方法,那么它们的执行顺序是
@PostConstruct 标注的初始化方法
InitializingBean 接口的初始化方法
@Bean(initMethod) 指定的初始化方法
与初始化类似,Spring 也提供了多种销毁手段,执行顺序为
@PreDestroy 标注的销毁方法
DisposableBean 接口的销毁方法
@Bean(destroyMethod) 指定的销毁方法
扩展:
1.aware接口执行在@PostConstruct 标注的初始化方法InitializingBean 接口的初始化方法之间,
2.执行destroySingletons()方法销毁之后,仍可创建新的单例
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。