一、目标

目前已实现的 Spring 框架,在 Bean 操作上能提供出的能力,包括:Bean 对象的定义和注册,以及在操作 Bean 对象过程中执行的,BeanFactoryPostProcessor、BeanPostProcessor、InitializingBean、DisposableBean,以及在 XML 新增的一些配置处理,让我们可以 Bean 对象有更强的操作性。那么,如果我们想获得 Spring 框架提供的 BeanFactory、ApplicationContext、BeanClassLoader等这些能力做一些扩展框架的使用时该怎么操作呢。所以我们本章节希望在 Spring 框架中提供一种能感知容器操作的接口,如果谁实现了这样的一个接口,就可以获取接口入参中的各类能力。

二、设计

如果说我希望拿到 Spring 框架中一些提供的资源,那么首先需要考虑以一个什么方式去获取,之后你定义出来的获取方式,在 Spring 框架中该怎么去承接,实现了这两项内容,就可以扩展出你需要的一些属于 Spring 框架本身的能力了。在关于 Bean 对象实例化阶段我们操作过一些额外定义、属性、初始化和销毁的操作,其实我们如果像获取 Spring 一些如 BeanFactory、ApplicationContext 时,也可以通过此类方式进行实现。那么我们需要定义一个标记性的接口,这个接口不需要有方法,它只起到标记作用就可以,而具体的功能由继承此接口的其他功能性接口定义具体方法,最终这个接口就可以通过 instanceof 进行判断和调用了。整体设计结构如下图:

  1. 定义接口Aware,在Spring框架中它是一种感知标记性接口,具体的子类定义和实现能感知容器中的相关对象。也就是通过这个桥梁,向具体的实现类中提供容器服务。
  2. 继承 Aware的接口包括:BeanFactoryAware、BeanClassLoaderAware、BeanNameAware和ApplicationContextAware,当然在Spring 源码中还有一些其他关于注解的,不过目前我们还是用不到。
  3. 在具体的接口实现过程中你可以看到,一部分(BeanFactoryAware、BeanClassLoaderAware、BeanNameAware)在factory 的 support 文件夹下,另外 ApplicationContextAware 是在 context 的 support中,这是因为不同的内容获取需要在不同的包下提供。所以,在 AbstractApplicationContext 的具体实现中会用到向 beanFactory 添加 BeanPostProcessor 内容的 ApplicationContextAwareProcessor 操作,最后由 AbstractAutowireCapableBeanFactory 创建 createBean 时处理相应的调用操作。关于applyBeanPostProcessorsBeforeInitialization 已经在前面章节中实现过,如果忘记可以往前翻翻

三、实现

  1. 工程结构
small-spring-step-08
└── src├── main│   └── java│       └── cn.bugstack.springframework│           ├── beans│           │   ├── factory│           │   │   ├── config│           │   │   │   ├── AutowireCapableBeanFactory.java│           │   │   │   ├── BeanDefinition.java│           │   │   │   ├── BeanFactoryPostProcessor.java│           │   │   │   ├── BeanPostProcessor.java│           │   │   │   ├── BeanReference.java│           │   │   │   ├── ConfigurableBeanFactory.java│           │   │   │   └── SingletonBeanRegistry.java│           │   │   ├── support│           │   │   │   ├── AbstractAutowireCapableBeanFactory.java│           │   │   │   ├── AbstractBeanDefinitionReader.java│           │   │   │   ├── AbstractBeanFactory.java│           │   │   │   ├── BeanDefinitionReader.java│           │   │   │   ├── BeanDefinitionRegistry.java│           │   │   │   ├── CglibSubclassingInstantiationStrategy.java│           │   │   │   ├── DefaultListableBeanFactory.java│           │   │   │   ├── DefaultSingletonBeanRegistry.java│           │   │   │   ├── DisposableBeanAdapter.java│           │   │   │   ├── InstantiationStrategy.java│           │   │   │   └── SimpleInstantiationStrategy.java  │           │   │   ├── support│           │   │   │   └── XmlBeanDefinitionReader.java│           │   │   ├── Aware.java│           │   │   ├── BeanClassLoaderAware.java│           │   │   ├── BeanFactory.java│           │   │   ├── BeanFactoryAware.java│           │   │   ├── BeanNameAware.java│           │   │   ├── ConfigurableListableBeanFactory.java│           │   │   ├── DisposableBean.java│           │   │   ├── HierarchicalBeanFactory.java│           │   │   ├── InitializingBean.java│           │   │   └── ListableBeanFactory.java│           │   ├── BeansException.java│           │   ├── PropertyValue.java│           │   └── PropertyValues.java │           ├── context│           │   ├── support│           │   │   ├── AbstractApplicationContext.java │           │   │   ├── AbstractRefreshableApplicationContext.java │           │   │   ├── AbstractXmlApplicationContext.java │           │   │   ├── ApplicationContextAwareProcessor.java │           │   │   └── ClassPathXmlApplicationContext.java │           │   ├── ApplicationContext.java │           │   ├── ApplicationContextAware.java │           │   └── ConfigurableApplicationContext.java│           ├── core.io│           │   ├── ClassPathResource.java │           │   ├── DefaultResourceLoader.java │           │   ├── FileSystemResource.java │           │   ├── Resource.java │           │   ├── ResourceLoader.java │           │   └── UrlResource.java│           └── utils│               └── ClassUtils.java└── test└── java└── cn.bugstack.springframework.test├── bean│   ├── UserDao.java│   └── UserService.java└── ApiTest.java
  1. 类依赖关系
  1. 以上整个类关系就是关于 Aware 感知的定义和对容器感知的实现。
  2. Aware 有四个继承的接口,其他这些接口的继承都是为了继承一个标记,有了标记的存在更方便类的操作和具体判断实现。
  3. 另外由于 ApplicationContext 并不是在 AbstractAutowireCapableBeanFactory 中 createBean 方法下的内容,所以需要像容器中注册 addBeanPostProcessor ,再由 createBean 统一调用 applyBeanPostProcessorsBeforeInitialization 时进行操作。
  1. 定义标记接口
/*** Marker superinterface indicating that a bean is eligible to be* notified by the Spring container of a particular framework object* through a callback-style method.  Actual method signature is* determined by individual subinterfaces, but should typically* consist of just one void-returning method that accepts a single* argument.** 标记类接口,实现该接口可以被Spring容器感知**/
public interface Aware {}
  1. 在 Spring 中有特别多类似这样的标记接口的设计方式,它们的存在就像是一种标签一样,可以方便统一摘取出属于此类接口的实现类,通常会有 instanceof 一起判断使用。
  1. 容器感知类
  • 3.1 BeanFactoryAware
public interface BeanFactoryAware extends Aware {void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
  1. Interface to be implemented by beans that wish to be aware of theirowning {@link BeanFactory}.
  2. 实现此接口,既能感知到所属的 BeanFactory
  • 3.2 BeanClassLoaderAware
public interface BeanClassLoaderAware extends Aware{void setBeanClassLoader(ClassLoader classLoader);
}
  1. Callback that allows a bean to be aware of the bean{@link ClassLoader class loader}; that is, the class loader used by the present beanfactory to load bean classes.
  2. 实现此接口,既能感知到所属的 ClassLoader
  • 3.3 BeanNameAware
public interface BeanNameAware extends Aware {void setBeanName(String name);
}
  • Interface to be implemented by beans that want to be aware of their bean name in a bean factory.
  • 实现此接口,既能感知到所属的 BeanName

3.4 ApplicationContextAware

public interface ApplicationContextAware extends Aware {void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
  • Interface to be implemented by any object that wishes to be notified of the {@link ApplicationContext} that it runs in.
  • 实现此接口,既能感知到所属的ApplicationContext
  1. 包装处理器(ApplicationContextAwareProcessor)
public class ApplicationContextAwareProcessor implements BeanPostProcessor {private final ApplicationContext applicationContext;public ApplicationContextAwareProcessor(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof ApplicationContextAware){((ApplicationContextAware) bean).setApplicationContext(applicationContext);}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}
  • 由于 ApplicationContext 的获取并不能直接在创建 Bean 时候就可以拿到,所以需要在 refresh 操作时,把ApplicationContext 写入到一个包装的 BeanPostProcessor 中去,由AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization方法调用。
  1. 注册 BeanPostProcessor
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {@Overridepublic void refresh() throws BeansException {// 1. 创建 BeanFactory,并加载 BeanDefinitionrefreshBeanFactory();// 2. 获取 BeanFactoryConfigurableListableBeanFactory beanFactory = getBeanFactory();// 3. 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContextbeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 4. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)invokeBeanFactoryPostProcessors(beanFactory);// 5. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作registerBeanPostProcessors(beanFactory);// 6. 提前实例化单例Bean对象beanFactory.preInstantiateSingletons();}// ...
}

refresh() 方法就是整个 Spring 容器的操作过程,与上一章节对比,本次新增加了关于 addBeanPostProcessor 的操作。添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext。

  1. 感知调用操作
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();@Overrideprotected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {Object bean = null;try {bean = createBeanInstance(beanDefinition, beanName, args);// 给 Bean 填充属性applyPropertyValues(beanName, bean, beanDefinition);// 执行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置处理方法bean = initializeBean(beanName, bean, beanDefinition);} catch (Exception e) {throw new BeansException("Instantiation of bean failed", e);}// 注册实现了 DisposableBean 接口的 Bean 对象registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);addSingleton(beanName, bean);return bean;}private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {// invokeAwareMethodsif (bean instanceof Aware) {if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(this);}if (bean instanceof BeanClassLoaderAware){((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());}if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}}// 1. 执行 BeanPostProcessor Before 处理Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);// 执行 Bean 对象的初始化方法try {invokeInitMethods(beanName, wrappedBean, beanDefinition);} catch (Exception e) {throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);}// 2. 执行 BeanPostProcessor After 处理wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);return wrappedBean;}@Overridepublic Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessBeforeInitialization(result, beanName);if (null == current) return result;result = current;}return result;}@Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (null == current) return result;result = current;}return result;}
}
  1. 这里我们去掉了一些类的内容,只保留关于本次 Aware 感知接口的操作。首先在 initializeBean 中,通过判断 bean
    instanceof Aware,调用了三个接口方法,
  • BeanFactoryAware.setBeanFactory(this)
  • BeanClassLoaderAware.setBeanClassLoader(getBeanClassLoader())、
  • BeanNameAware.setBeanName(beanName),

这样就能通知到已经实现了此接口的类。另外我们还向 BeanPostProcessor 中添加了ApplicationContextAwareProcessor,此时在这个方法中也会被调用到具体的类实现,得到一个ApplicationContex 属性。

四、测试

  1. 事先准备
public class UserDao {private static Map<String, String> hashMap = new HashMap<>();public void initDataMethod(){System.out.println("执行:init-method");hashMap.put("10001", "小傅哥");hashMap.put("10002", "八杯水");hashMap.put("10003", "阿毛");}public void destroyDataMethod(){System.out.println("执行:destroy-method");hashMap.clear();}public String queryUserName(String uId) {return hashMap.get(uId);}
}
public class UserService implements BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware {private ApplicationContext applicationContext;private BeanFactory beanFactory;private String uId;private String company;private String location;private UserDao userDao;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}@Overridepublic void setBeanName(String name) {System.out.println("Bean Name is:" + name);}@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {System.out.println("ClassLoader:" + classLoader);}// ...get/set
}
  • UserDao 本次并没有什么改变,还是提供了关于初始化的方法,并在 Spring.xml 中提供init-method、destroy-method 配置信息。
  • UserService 新增加,BeanNameAware,BeanClassLoaderAware, ApplicationContextAware,BeanFactoryAware,四个感知的实现类,并在类中实现相应的接口方法。
  1. 配置文件
    基础配置,无BeanFactoryPostProcessor、BeanPostProcessor,实现类
<?xml version="1.0" encoding="UTF-8"?>
<beans><bean id="userDao" class="cn.bugstack.springframework.test.bean.UserDao" init-method="initDataMethod" destroy-method="destroyDataMethod"/><bean id="userService" class="cn.bugstack.springframework.test.bean.UserService"><property name="uId" value="10001"/><property name="company" value="腾讯"/><property name="location" value="深圳"/><property name="userDao" ref="userDao"/></bean>
</beans>

五、总结

目前关于 Spring 框架的实现中,某些功能点已经越来趋向于完整,尤其是 Bean 对象的生命周期,已经有了很多的体现。整体总结如图

  1. 本章节关于 Aware 的感知接口的四个继承接口 BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware 的实现,又扩展了 Spring 的功能。如果你有做过关于 Spring中间件的开发那么一定会大量用到这些类,现在你不只是用过,而且还知道他们都是什么时候触达的,在以后想排查类的实例化顺序也可以有一个清晰的思路了。
  2. 每一章节内容的实现都是在以设计模式为核心的结构上填充各项模块的功能,单纯的操作编写代码并不会有太多收获,一定是要理解为什么这么设计,这么设计的好处是什么,怎么就那么多接口和抽象类的应用,这些才是Spring 框架学习的核心所在。

手写简版spring --8--Aware感知容器对象Aware感知容器对象相关推荐

  1. 手写简版spring --5--资源加载器解析文件注册对象

    一.目标 在完成 Spring 的框架雏形后,现在我们可以通过单元测试进行手动操作Bean对象的定义.注册和属性填充,以及最终获取对象调用方法.但这里会有一个问题,就是如果实际使用这个 Spring ...

  2. 手写简版spring --10--容器事件和事件监听器

    一.降低耦合 解耦场景在互联网开发的设计中使用的也是非常频繁,如:这里需要一个注册完成事件推送消息.用户下单我会发送一个MQ.收到我的支付消息就可以发货了等等,都是依靠事件订阅和发布以及MQ消息这样的 ...

  3. 手写简版spring --9--对象作用域和FactoryBean

    一.目标 交给 Spring 管理的 Bean 对象,一定就是我们用类创建出来的 Bean 吗?创建出来的 Bean 就永远是单例的吗,没有可能是原型模式吗?在集合 Spring 框架下,我们使用的 ...

  4. 手写简版spring --2--实现Bean的定义、注册、获取

    一.目标 在上一章节我们初步依照 Spring Bean 容器的概念,实现了一个粗糙版本的代码实现.那么本章节我们需要结合已实现的 Spring Bean 容器进行功能完善,实现 Bean 容器关于 ...

  5. 手写简版spring --1--创建简单的Bean容器

    一.声明 这个系列是我自己的学习笔记,为了在学习的过程中巩固知识而记录的,好强迫自己用心拜读,而不是进收藏夹.本系列都是基于小缚哥的文章和代码的,想要深入了解,请移步小缚哥博客 二.spring-Be ...

  6. 手写简版spring --7--初始化方法和销毁方法

    一.目标 当我们的类创建的 Bean 对象,交给 Spring 容器管理以后,这个类对象就可以被赋予更多的使用能力.就像我们在上一章节已经给类对象添加了修改注册Bean定义未实例化前的属性信息修改和实 ...

  7. 手写简版spring --6--应用上下文(BeanPostProcessor 和 BeanFactoryPostProcessor)

    一.目标 如果你在自己的实际工作中开发过基于 Spring 的技术组件,或者学习过关于SpringBoot 中间件设计和开发等内容.那么你一定会继承或者实现了 Spring对外暴露的类或接口,在接口的 ...

  8. 手写简版spring --4--注入属性和依赖对象

    一.目标 首先我们回顾下这几章节都完成了什么,包括:实现一个容器.定义和注册Bean.实例化Bean,按照是否包含构造函数实现不同的实例化策略,那么在创建对象实例化这我们还缺少什么?其实还缺少一个关于 ...

  9. 手写简版spring --3--对象实例化策略

    一.目标 这一章节的目标主要是为了解决上一章节我们埋下的坑,那是什么坑呢?其实就是一个关于 Bean 对象在含有构造函数进行实例化的坑.在上一章节我们扩充了 Bean 容器的功能,把实例化对象交给容器 ...

最新文章

  1. 错误sudo: pip: command not found解决方案
  2. 9个用来爬取网络站点的 Python 库
  3. POJ 1637 Sightseeing tour 混合图欧拉回路存在性判断
  4. 【C语言简单说】六:取模运算符以及变量的扩展
  5. 前端学习(2185):tabberitem的颜色动态
  6. ds排序--希尔排序_排序算法 - 希尔排序分析及优化
  7. XML SOAP应用简介
  8. ****阿里云使用+快速运维总结(不断更新)
  9. 2017 年,阿里巴巴开源的那些事儿
  10. Pycharm连接远程服务器环境搭建
  11. C语言中关于二级指针的笔试题
  12. matlab运算放大器仿真,利用Matlab分析运算放大器电路.doc
  13. 行走在古道间,看时光深处,
  14. MEM/MBA 写作-论证有效性分析(09)逻辑缺陷-误用百分数滑坡谬误
  15. word2vec的原理及实现(附github代码)
  16. 基于Python pyqt5的随机抽号机源代码 ,可设置抽号器的人数及刷新间隔
  17. xampp下载太慢了,这里有下载好的(mac)
  18. LibZXing二维码工具
  19. 2020计算机应用基础历年真题,2020北京自考计算机应用基础真题及答案
  20. 【DBC专题】-7-在DBC中创建一个Signal Group信号组

热门文章

  1. leetcode-654-最大二叉树
  2. .Net高并发解决思路(转)
  3. 001.Amoeba读写分离部署
  4. centos 6.5 启动时卡在进度条位置无法进入系统解决办法。
  5. hdu 3018 Ant Trip
  6. 1 Orchard 入门篇-Orchard 基本概念
  7. ChartDirector资料小结
  8. 用自动阈值话处理SVM棋盘
  9. 有趣的MS Live Labs
  10. Git学习笔记;Git bash 库同步问题