一、spring容器中的aware接口介绍

  Spring中提供了各种Aware接口,比较常见的如BeanFactoryAware,BeanNameAware,ApplicationContextAware,BeanClassLoaderAware等,方便从上下文中获取当前的运行环境。我们先从使用的角度来说明aware接口的使用方式,举例如我们想得到当前的BeanFactory,我们可以让我们的实现类继承BeanFactoryAware接口,然后通过接口注入的方式得到当前容器中的BeanFactory:

public class Fruit implements BeanFactoryAware {
private BeanFactory beanFactory; @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

我们的Fruit类实现了aware接口,如果我们直接在应用中new一个Fruit的对象,当然是拿不到beanFactory变量的,我们必须在spring的配置文件中声明我们的fruit对象才行,也就是说fruit对象必须交给容器进行管理,容器帮你把各种aware接口中想要注入的对象设置到bean中。具体看容器管理aware接口的代码实现,代码在AbstractAutowireCapableBeanFactory的initializeBean方法中:

protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
// 判断对象实现的接口类型,处理特定的三种接口类型:BeanNameAware、BeanClassLoaderAware和BeanFactoryAware。
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
} if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
} if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
// 开始Bean初始化前处理、初始化、初始化后处理
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
} try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
} if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

可以看出来,aware接口的各种处理是在属性设置完成之后、bean初始化之前完成的。显然的,如果我们直接new出来一个bean,这些框架性的特性是没有使用到的。除了BeanFactoryAware、BeanNameAware、BeanClassLoaderAware之外的那些aware接口,比如ApplicationContextAware,再比如Webx中的自定义aware接口,它们又是怎么做到接口注入的呢?原来在应用中创建上下文容器时会注册一个BeanPostProcessor------ApplicationContextAwareProcessor,在这个类里面进行了context的注入,这样我们就能能够拿到bean中的context对象:

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
return bean;
}

那么容器是在什么时候把ApplicationContextAwareProcessor的对象注册到context的BeanPostProcessor列表中的呢,奥秘在org.springframework.context.support.AbstractApplicationContext.prepareBeanFactory(ConfigurableListableBeanFactory)方法中:

// Tell the internal bean factory to use the context's class loader.
beanFactory.setBeanClassLoader(getClassLoader()); // Populate the bean factory with context-specific resource editors.
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this)); // Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //在这里注册了我们想要的BeanPostProcessor
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

二、了解webx中实现的aware接口

  我们了解了aware的实现原理,我们就可以自己来实现自己的aware接口了。Webx就是这么做的(webx本身作为一个容器,本身注册了各类aware接口的BeanPostProcessor),比如我们想要感知到当前环境是否是生产模式,我们只需要实现ProductionModeAware接口就能够获得生产模式的值了。我们使用aware接口感觉很神奇很简便,原因是很多工作框架已经帮我们做了。webx中使用ProductionModeAwarePostProcessor这个BeanPostProcessor来进行生产模式的注入。在postProcessBeforeInitialization方法中:

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ProductionModeAware) {
((ProductionModeAware) bean).setProductionMode(configuration.isProductionMode());
} return bean;
}

所以任何实现了ProductionModeAware接口的类,在webx容器中都能够获得生产模式的取值。

三、自定义aware接口实现

  了解了个中原理,那么自定义aware接口实现起来并不复杂。我们只需要2步操作:1.实现我们aware接口的postprocessor,并在容器中注册;2.bean实体类集成我们自定义的aware接口并实现。代码如下:Aware接口比较简单,就做一件事情,把Apple对象注入。

public interface AppleAware {
void setApple(Apple a);
}

我们的BeanPostProcessor会检查是否是AppleAware接口,因为注册到容器的BeanPostProcessor会对每一个bean都做一次扫描:

public class AppleAwarePostProcessor implements BeanPostProcessor {

    private Apple a;

    public AppleAwarePostProcessor(Apple a) {
this.a = a;
} /* (non-Javadoc)
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof AppleAware) {
((AppleAware) bean).setApple(a);
}
return bean;
} /* (non-Javadoc)
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
return bean;
} }

实体类Market实现了AppleAware接口,能够得到Apple对象的注入:

public class Market implements AppleAware {

    private Apple a;

    @Override
public void setApple(Apple a) {
this.a = a;
} public String getName() {
return a.getName();
} }

最后是我们的测试类,一定要把我们的BeanPostProcessor加入到当前容器中,这一点非常重要:

public class TestAware {
public static void main(String args[]) {
ConfigurableBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
BeanPostProcessor bpp = new AppleAwarePostProcessor((Apple)beanFactory.getBean("apple"));
// 工厂对象中加入我们自定义的BeanPostProcessor
beanFactory.addBeanPostProcessor(bpp);
Market market = (Market) beanFactory.getBean("market");
System.out.println(market.getName());
}
}

四、

spring源码:Aware接口(li)的更多相关文章

  1. spring源码 AutowireCapableBeanFactory接口

    对于想要拥有自动装配能力,并且想把这种能力暴露给外部引用的BeanFactory类需要实现此接口.正常情况下,不要使用此接口应该更倾向于使用BeanFactory或者ListableBeanFacto ...

  2. spring源码 ListableBeanFactory接口

    ListableBeanFactory接口表示这些Bean是可列表的 /* * Copyright 2002-2016 the original author or authors. * * Lice ...

  3. spring源码 HierarchicalBeanFactory接口

    HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个Bean 有可能有父 Bean. /* * Copyright 2002-2012 the origi ...

  4. spring源码:学习线索(li)

    一.spring xml配置(不包括AOP,主要了解在初始化及实例化过程中spring配置文件中每项内容的具体实现过程,从根本上掌握spring) <bean>的名字 &,alia ...

  5. spring源码分析系列 (2) spring拓展接口BeanPostProcessor

    Spring更多分析--spring源码分析系列 主要分析内容: 一.BeanPostProcessor简述与demo示例 二.BeanPostProcessor源码分析:注册时机和触发点 (源码基于 ...

  6. spring源码:web容器启动(li)

    web项目中可以集成spring的ApplicationContext进行bean的管理,这样使用起来bean更加便捷,能够利用到很多spring的特性.我们比较常用的web容器有jetty,tomc ...

  7. Spring源码分析——资源访问利器Resource之接口和抽象类分析

    从今天开始,一步步走上源码分析的路.刚开始肯定要从简单着手.我们先从Java发展史上最强大的框架——Spring...旗下的资源抽象接口Resource开始吧. 我看了好多分析Spring源码的,每每 ...

  8. spring源码分析系列 (1) spring拓展接口BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

    更多文章点击--spring源码分析系列 主要分析内容: 一.BeanFactoryPostProcessor.BeanDefinitionRegistryPostProcessor简述与demo示例 ...

  9. spring源码分析系列 (3) spring拓展接口InstantiationAwareBeanPostProcessor

    更多文章点击--spring源码分析系列 主要分析内容: 一.InstantiationAwareBeanPostProcessor简述与demo示例 二.InstantiationAwareBean ...

  10. Spring源码解析 - AbstractBeanFactory 实现接口与父类分析

    我们先来看类图吧: 除了BeanFactory这一支的接口,AbstractBeanFactory主要实现了AliasRegistry和SingletonBeanRegistry接口. 这边主要提供了 ...

随机推荐

  1. 【Java每日一题】20170103

    20161230问题解析请点击今日问题下方的"[Java每日一题]20170103"查看(问题解析在公众号首发,公众号ID:weknow619) package Jan2017; ...

  2. PHP设计模式(三)抽象工厂模式(Abstract Factory For PHP)

    一.什么是抽象工厂模式 抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象 ,而且使用抽象工厂模式还要满足以下条件: 系统中有多个产品族,而系统一次只可能消费其中一族产品. 同 ...

  3. 太多选择——企业如何选择合适的BI工具?

    在没认清现状前,企业当然不能一言不合就上BI. BI不同于一般的企业管理软件,不能简单归类为类似用于提高管理的ERP和WMS,或用于提高企业效率的OA.BPM.BI的本质应该是通过展现数据,用于加强企 ...

  4. 在MySQL数据库中创建一个完整的表

    1.登陆成功后,首先进入某一个数据库 (不是指数据库服务器) use t1; //t1是数据库名 如图所示: 2.在此数据库中建立数据库表 2.1 先建立表结构(可以理解为表的列名,也就是字段名)在实 ...

  5. Oozie分布式任务的工作流——Spark篇

    Spark是现在应用最广泛的分布式计算框架,oozie支持在它的调度中执行spark.在我的日常工作中,一部分工作就是基于oozie维护好每天的spark离线任务,合理的设计工作流并分配适合的参数对于 ...

  6. BZOJ 1146: [CTSC2008]网络管理Network [树上带修改主席树]

    1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3522  Solved: 1041[Submi ...

  7. linux系统下基于mono部署asp.net,使用ef6与mysql出现的问题【索引】

    git clone github.com/mono的源码,日期:2014-06-19,百度网盘链接:http://pan.baidu.com/s/1kTG9EUb 关于asp.net利用mono部署到 ...

  8. Backbone源码解析(六):观察者模式应用

    卤煮在大概一年前写过backbone的源码分析,里面讲的是对一些backbone框架的方法的讲解.这几天重新看了几遍backbone的源码,才发现之前对于它的理解不够深入,只关注了它的一些部分的细节和 ...

  9. 《Entity Framework 6 Recipes》中文翻译系列 目录篇 -持续更新

    为了方便大家的阅读和学习,也是响应网友的建议,在这里为这个系列做一个目录.在目录开始这前,我先来回答之前遇到的几个问题. 1.为什么要学习EF? 这个问题很简单,项目需要.这不像学校,没人强迫你学习! ...

  10. iOS---基于对Sqlilte3的二次包装的第三次包装--->JKDBModel ,一个好用的离线缓存库

    https://github.com/Joker-King/JKDBModel 1.将FMDB和DBModel拖入项目中,然后添加libsqlite3.dylib   2. #import " ...