部分内容参考 Spring整理系列(06)——spring中Aware结尾接口
前言
在 Spring 中,有一个特殊的约定,就是被 Spring 容器管理的 bean,如果实现了 Spring 提供的以 Aware 结尾的接口,那么在对 bean 进行实例化的过程中,容器会调用相应的接口方法,通过这个特性,我们可以获取容器或者 bean 相关的一些属性。比较常用的就有 BeanFactoryAware
、BeanNameAware
、ApplicationContextAware
、ResourceLoaderAware
、ServletContextAware
等等。
使用方法
这里以 BeanNameAware
、ApplicationContextAware
为例,演示相关接口的使用方法。相关的代码来自 Dubbo 框架的 com.alibaba.dubbo.config.spring.ServiceBean
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware {
private static final long serialVersionUID = 213195494150089726L;
private transient ApplicationContext applicationContext;
private transient String beanName;
public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; SpringExtensionFactory.addApplicationContext(applicationContext); if (applicationContext != null) { SPRING_CONTEXT = applicationContext; try { Method method = applicationContext.getClass().getMethod("addApplicationListener", new Class<?>[]{ApplicationListener.class}); method.invoke(applicationContext, new Object[] {this}); supportedApplicationListener = true; } catch (Throwable t) { if (applicationContext instanceof AbstractApplicationContext) { try { Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", new Class<?>[]{ApplicationListener.class}); if (! method.isAccessible()) { method.setAccessible(true); } method.invoke(applicationContext, new Object[] {this}); supportedApplicationListener = true; } catch (Throwable t2) { } } } } }
public void setBeanName(String name) { this.beanName = name; } }
|
代码中只保留了与 Aware 接口相关的内容,可以看到 ServiceBean
实现了 BeanNameAware
、ApplicationContextAware
接口,对应的方法为 com.alibaba.dubbo.config.spring.ServiceBean#setBeanName
和 com.alibaba.dubbo.config.spring.ServiceBean#setApplicationContext
,这两个方法将会被容器调用,带来的结果就是 ServiceBean
可以直接获取到容器上下文环境 ApplicationContext
和当前 bean 在容器中的表示的 BeanName
。
类似的我们也可以自己实现这两个接口,并根据自己的需求来做出相应的函数实现,具体的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
public class MyApplicationContext implements BeanNameAware,ApplicationContextAware{ private String beanName;
@Override public void setBeanName(String beanName) { this.beanName = beanName; System.out.println("MyApplicationContext beanName:"+beanName); }
@Override public void setApplicationContext(ApplicationContext context) throws BeansException { System.out.println(context.getBean(this.beanName).hashCode()); } }
|
然后在 Spring 配置文件中加上如下 bean 节点,那么容器中所管理的 MyApplicationContext 在实例化过程中将会执行这两个方法。
1
| <bean name ="myContext" class="com.jsun.test.springDemo.aware.MyApplicationContext"></bean>
|
总结
这里只是以 BeanNameAware
、ApplicationContextAware
接口进行了说明,其他的 Aware 结尾的接口的使用方法类似,表示获取到某种属性的能力。不仅如此,Spring 中的其他很多的接口的设计也是采用了这种思想,比如 ServiceBean
实现的 DisposableBean
,ApplicationListener
接口。这是一种很优秀的设计思想,Spring 容器在其初始化的特殊时刻将会统一调用实现了对应接口的实例的对应方法。