概述
自定义组件要想使用Spring容器底层的一些组件(比如:ApplicationContext、BeanFactory等),此时,只需要让自定义组件实现XxxAware接口即可。此时,Spring在创建对象的时候,会调用XxxAware接口定义的方法,注入相关的组件。
XxxAware接口概览
其实,我们之前使用过XxxAware接口,例如,我们之前创建的Employee类,就实现了ApplicationContextAware接口,Employee类的源码如下所示。
package io.mykit.spring.plugins.register.bean; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * @author binghe * @version 1.0.0 * @description 测试ApplicationContextAware */ @Component public class Employee implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
从Employee类的源码可以看出,实现ApplicationContextAware接口的话,需要实现setApplicationContext()方法。在IOC容器启动并创建Employee对象时,Spring会调用setApplicationContext()方法,并且会将ApplicationContext对象传入到setApplicationContext()方法中,我们只需要在Employee类中定义一个ApplicationContext类型的成员变量来接收setApplicationContext()方法的参数,就可以使用ApplicationContext对象了。
其实,在Spring中,类似于ApplicationContextAware接口的设计有很多,本质上,Spring中类似XxxAware接口都继承了Aware接口,我们来看下Aware接口的源码,如下所示。
package org.springframework.beans.factory; /** * @author Chris Beams * @author Juergen Hoeller * @since 3.1 */ public interface Aware { }
可以看到,Aware接口是Spring 3.1版本中引入的接口,在Aware接口中,并未定义任何方法。
接下来,我们看看都有哪些接口继承了Aware接口,如下所示。
XxxAware接口案例
接下来,我们就挑选几个常用的XxxAware接口来进行简单的说明。
ApplicationContextAware接口使用的比较多,我们先来说说这个接口,通过ApplicationContextAware接口我们可以获取到IOC容器。
首先,我们创建一个Blue类,并实现ApplicationContextAware接口,在实现的setApplicationContext()中将ApplicationContext输出,如下所示。
package io.mykit.spring.plugins.register.bean; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * @author binghe * @version 1.0.0 * @description 测试ApplicationContextAware接口 */ public class Blue implements ApplicationContextAware { private ApplicationContext applicationContext @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("传入的ioc:" + applicationContext); this.applicationContext = applicationContext; } }
我们也可以为Blue类同时实现几个XxxAware接口,例如,使Blue类再实现一个BeanNameAware接口,我们可以通过BeanNameAware接口获取到当前bean在Spring容器中的名称,如下所示。
package io.mykit.spring.plugins.register.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * @author binghe * @version 1.0.0 * @description 测试ApplicationContextAware接口 */ public class Blue implements ApplicationContextAware, BeanNameAware { private ApplicationContext applicationContext @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("传入的ioc:" + applicationContext); this.applicationContext = applicationContext; } @Override public void setBeanName(String name) { System.out.println("当前bean的名字"); } }
接下来,我们再实现一个EmbeddedValueResolverAware接口,我们通过EmbeddedValueResolverAware接口能够获取到StringValue解析器。如下所示。
package io.mykit.spring.plugins.register.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.util.StringValueResolver; /** * @author binghe * @version 1.0.0 * @description 测试ApplicationContextAware接口 */ public class Blue implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("传入的ioc:" + applicationContext); this.applicationContext = applicationContext; } @Override public void setBeanName(String name) { System.out.println("当前bean的名字"); } @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { String resolveStringValue = resolver.resolveStringValue("你好${os.name} 年龄:#{20*18}"); System.out.println("解析后的字符串为:" + resolveStringValue); } }
接下来,我们需要在Blue类上标注@Component注解将Blue类添加到IOC容器中,如下所示。
@Component public class Blue implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
运行AutowiredTest类的testAutowired02()方法,输出的结果信息如下所示。
postProcessBeforeInitialization...autowiredConfig=>io.mykit.spring.plugins.register.config.AutowiredConfig$$EnhancerBySpringCGLIB$$d3c83622@1c93084c postProcessAfterInitialization...autowiredConfig=>io.mykit.spring.plugins.register.config.AutowiredConfig$$EnhancerBySpringCGLIB$$d3c83622@1c93084c postProcessBeforeInitialization...personDao=>PersonDao{remark='1'} postProcessAfterInitialization...personDao=>PersonDao{remark='1'} postProcessBeforeInitialization...personDao2=>PersonDao{remark='2'} postProcessAfterInitialization...personDao2=>PersonDao{remark='2'} postProcessBeforeInitialization...personService=>PersonService{personDao=PersonDao{remark='2'}} postProcessAfterInitialization...personService=>PersonService{personDao=PersonDao{remark='2'}} postProcessBeforeInitialization...personController=>io.mykit.spring.plugins.register.controller.PersonController@48ae9b55 postProcessAfterInitialization...personController=>io.mykit.spring.plugins.register.controller.PersonController@48ae9b55 执行了Animal类的无参数构造方法 postProcessBeforeInitialization...animal=>io.mykit.spring.plugins.register.bean.Animal@c267ef4 执行了Animal类的初始化方法。。。。。 postProcessAfterInitialization...animal=>io.mykit.spring.plugins.register.bean.Animal@c267ef4 当前bean的名字:blue 解析后的字符串为:你好Windows 10 年龄:360 传入的ioc:org.springframework.context.annotation.AnnotationConfigApplicationContext@5ecddf8f, started on Wed Aug 19 00:10:13 CST 2020 postProcessBeforeInitialization...blue=>io.mykit.spring.plugins.register.bean.Blue@55182842 postProcessAfterInitialization...blue=>io.mykit.spring.plugins.register.bean.Blue@55182842 Cat类的构造方法... postProcessBeforeInitialization...cat=>io.mykit.spring.plugins.register.bean.Cat@76505305 Cat的postConstruct()方法... postProcessAfterInitialization...cat=>io.mykit.spring.plugins.register.bean.Cat@76505305 调用了Dog的有参构造方法 postProcessBeforeInitialization...dog=>Dog{cat=io.mykit.spring.plugins.register.bean.Cat@76505305} postProcessAfterInitialization...dog=>Dog{cat=io.mykit.spring.plugins.register.bean.Cat@76505305} postProcessBeforeInitialization...employee=>io.mykit.spring.plugins.register.bean.Employee@74235045 postProcessAfterInitialization...employee=>io.mykit.spring.plugins.register.bean.Employee@74235045 postProcessBeforeInitialization...fish=>Fish{cat=io.mykit.spring.plugins.register.bean.Cat@76505305} postProcessAfterInitialization...fish=>Fish{cat=io.mykit.spring.plugins.register.bean.Cat@76505305} Fish{cat=io.mykit.spring.plugins.register.bean.Cat@76505305} Cat的preDestroy()方法... 执行了Animal类的销毁方法。。。。。
输出结果中有如下信息。
当前bean的名字:blue 解析后的字符串为:你好Windows 10 年龄:360 传入的ioc:org.springframework.context.annotation.AnnotationConfigApplicationContext@5ecddf8f, started on Wed Aug 19 00:10:13 CST 2020
说明正确的输出了结果信息。
XxxAware原理
XxxAware的底层原理是由XxxAwareProcessor类实现的, 例如,我们这里以ApplicationContextAware接口为例,ApplicationContextAware接口的底层原理就是由ApplicationContextAwareProcessor类实现的。从ApplicationContextAwareProcessor类的源码可以看出,其实现了BeanPostProcessor接口,本质上都是后置处理器。
class ApplicationContextAwareProcessor implements BeanPostProcessor
接下来,我们就以分析ApplicationContextAware接口的原理为例,看看Spring是怎么将ApplicationContext对象注入到Blue类中的。
我们在Blue类的setApplicationContext()方法上打一个断点,如下所示。
接下来,我们以debug的方式来运行AutowiredTest类的testAutowired02()方法,
这里,我们可以看到,实际上ApplicationContext对象已经注入到Blue类中的setApplicationContext()方法中了。我们在IDEA的方法调用栈中选择postProcessBeforeInitialization()方法,如下所示。
我们双击IDEA中的postProcessBeforeInitialization()方法的调用栈,会在IDEA中自动定位到postProcessBeforeInitialization()方法中,如下所示。
其实,postProcessBeforeInitialization()方法所在的类就是ApplicationContextAwareProcessor。postProcessBeforeInitialization()方法的逻辑比较简单。
我们来看下在postProcessBeforeInitialization()方法中调用的invokeAwareInterfaces()方法,如下所示。
看到这里,大家是不是有种豁然开朗的感觉!Blue类实现了ApplicationContextAware接口后,Spring为啥会将ApplicationContext对象自动注入到setApplicationContext()方法中就不用说了吧!