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

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

  1. public class Fruit implements BeanFactoryAware {
  2. private BeanFactory beanFactory;
  3.  
  4. @Override
  5. public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  6. this.beanFactory = beanFactory;
  7. }
  8. }

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

  1. protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
  2. // 判断对象实现的接口类型,处理特定的三种接口类型:BeanNameAware、BeanClassLoaderAware和BeanFactoryAware。
  3. if (bean instanceof BeanNameAware) {
  4. ((BeanNameAware) bean).setBeanName(beanName);
  5. }
  6.  
  7. if (bean instanceof BeanClassLoaderAware) {
  8. ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
  9. }
  10.  
  11. if (bean instanceof BeanFactoryAware) {
  12. ((BeanFactoryAware) bean).setBeanFactory(this);
  13. }
  14. // 开始Bean初始化前处理、初始化、初始化后处理
  15. Object wrappedBean = bean;
  16. if (mbd == null || !mbd.isSynthetic()) {
  17. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  18. }
  19.  
  20. try {
  21. invokeInitMethods(beanName, wrappedBean, mbd);
  22. }
  23. catch (Throwable ex) {
  24. throw new BeanCreationException(
  25. (mbd != null ? mbd.getResourceDescription() : null),
  26. beanName, "Invocation of init method failed", ex);
  27. }
  28.  
  29. if (mbd == null || !mbd.isSynthetic()) {
  30. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  31. }
  32. return wrappedBean;
  33. }

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

  1. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  2. if (bean instanceof ResourceLoaderAware) {
  3. ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
  4. }
  5. if (bean instanceof ApplicationEventPublisherAware) {
  6. ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
  7. }
  8. if (bean instanceof MessageSourceAware) {
  9. ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
  10. }
  11. if (bean instanceof ApplicationContextAware) {
  12. ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
  13. }
  14. return bean;
  15. }

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

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

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

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

  1. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  2. if (bean instanceof ProductionModeAware) {
  3. ((ProductionModeAware) bean).setProductionMode(configuration.isProductionMode());
  4. }
  5.  
  6. return bean;
  7. }

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

三、自定义aware接口实现

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

  1. public interface AppleAware {
  2. void setApple(Apple a);
  3. }

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

  1. public class AppleAwarePostProcessor implements BeanPostProcessor {
  2.  
  3. private Apple a;
  4.  
  5. public AppleAwarePostProcessor(Apple a) {
  6. this.a = a;
  7. }
  8.  
  9. /* (non-Javadoc)
  10. * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
  11. */
  12. @Override
  13. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  14. if(bean instanceof AppleAware) {
  15. ((AppleAware) bean).setApple(a);
  16. }
  17. return bean;
  18. }
  19.  
  20. /* (non-Javadoc)
  21. * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
  22. */
  23. @Override
  24. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  25. // TODO Auto-generated method stub
  26. return bean;
  27. }
  28.  
  29. }

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

  1. public class Market implements AppleAware {
  2.  
  3. private Apple a;
  4.  
  5. @Override
  6. public void setApple(Apple a) {
  7. this.a = a;
  8. }
  9.  
  10. public String getName() {
  11. return a.getName();
  12. }
  13.  
  14. }

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

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

四、

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. UML图中经常用到几种的关系图例

    学习这个东西挺奇怪的,时间一长就容易忘记,或者记不清楚.今天看到一些UML图的关系,发现有些出入了,索性就写下来,以后再忘记的时候过来看看. 在UML的类图中,常见的有以下几种关系: 继承(Gener ...

  2. 常用 meta 整理

    <!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 --> <meta name="HandheldFriendly" con ...

  3. VS2015墙内创建ionic2 【利用nrm更换源,完美!】

    STEP 1 设置cnpm npm install -g cnpm --registry=https://registry.npm.taobao.org   一句话建立cnpm STEP 2 安装nr ...

  4. mac下生成ssh keys 并上传github仓储

    使用github仓储需要本机生成一个公钥key 添加到自己的git账户SSH keys中   mac 生成方法:   1. 打开终端 输入   ssh-keygen 然后系统提示输入文件保存位置等信息 ...

  5. 在Linux和Windows平台上操作MemoryMappedFile(简称MMF)

    操作系统很早就开始使用内存映射文件(Memory Mapped File)来作为进程间的共享存储区,这是一种非常高效的进程通讯手段..NET 4.0新增加了一个System.IO. MemoryMap ...

  6. C#开源实现MJPEG流传输

    本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 许久以前写了篇文章<基于.NET打造IP智能网络视频监控系统>,记录和介绍了自己几年来积 ...

  7. wx.onMenuShareTimeline使用注意事项

    我在开发测试过程中,发现使用wx.onMenuShareTimeline无效果,没有显示我定义的图片.title和链接,经过调试发现原因如下: 1.图片大小要大于300pix才能显示 2.这个方法必须 ...

  8. CSharpGL(35)用ViewPort实现类似3DMax那样的把一个场景渲染到4个视口

    CSharpGL(35)用ViewPort实现类似3DMax那样的把一个场景渲染到4个视口 开始 像下面这样的四个视口的功能是很常用的,所以我花了几天时间在CSharpGL中集成了这个功能. 在CSh ...

  9. SQL Server 服务器磁盘测试之SQLIO篇(二)

    上次放出了一篇文章,针对磁盘卷簇大小默认4KB和自定义64KB进行了测试,测试内容为随机和顺序读写,大小为8KB和64KB,有人觉得这并没有照顾到SQL Server所有的IO使用情景.这篇测试文章, ...

  10. 微信小程序开发调试工具

    为了帮助开发者简单和高效地开发微信小程序,我们推出了全新的 开发者工具 ,集成了开发调试.代码编辑及程序发布等功能. 扫码登录 启动工具时,开发者需要使用已在后台绑定成功的微信号扫描二维码登录,后续所 ...