阅读完需:约 144 分钟
Bean容器创建
Spring Bean 容器是什么?
Spring 包含并管理应用对象的配置和生命周期,在这个意义上它是一种用于承载对象的容器,你可以配置你的每个 Bean 对象是如何被创建的,这些 Bean 可以创建一个单独的实例或者每次需要时都生成一个新的实例,以及它们是如何相互关联构建和使用的。
如果一个 Bean 对象交给 Spring 容器管理,那么这个 Bean 对象就应该以类似零件的方式被拆解后存放到 Bean 的定义中,这样相当于一种把对象解耦的操作,可以由 Spring 更加容易的管理,就像处理循环依赖等操作。
当一个 Bean 对象被定义存放以后,再由 Spring 统一进行装配,这个过程包括 Bean 的初始化、属性填充等,最终我们就可以完整的使用一个 Bean 实例化后的对象了。
现在目标就是定义一个简单的 Spring 容器,用于定义、存放和获取 Bean 对象。
凡是可以存放数据的具体数据结构实现,都可以称之为容器。例如:ArrayList、LinkedList、HashSet等,但在 Spring Bean 容器的场景下,我们需要一种可以用于存放和名称索引式的数据结构,所以选择 HashMap 是最合适不过的。
这里简单介绍一下 HashMap,HashMap 是一种基于扰动函数、负载因子、红黑树转换等技术内容,形成的拉链寻址的数据结构,它能让数据更加散列的分布在哈希桶以及碰撞时形成的链表和红黑树上。它的数据结构会尽可能最大限度的让整个数据读取的复杂度在 O(1) ~ O(Logn) ~O(n)之间,当然在极端情况下也会有 O(n) 链表查找数据较多的情况。不过我们经过10万数据的扰动函数再寻址验证测试,数据会均匀的散列在各个哈希桶索引上,所以 HashMap 非常适合用在 Spring Bean 的容器实现上。
另外一个简单的 Spring Bean 容器实现,还需 Bean 的定义、注册、获取三个基本步骤,简化设计如下;

- 定义:
BeanDefinition
,可能这是你在查阅 Spring 源码时经常看到的一个类,例如它会包括singleton、prototype、BeanClassName
等。但目前我们初步实现会更加简单的处理,只定义一个 Object 类型用于存放对象。 - 注册:这个过程就相当于我们把数据存放到 HashMap 中,只不过现在 HashMap 存放的是定义了的 Bean 的对象信息。
- 获取:最后就是获取对象,Bean 的名字就是key,Spring 容器初始化好 Bean 以后,就可以直接获取了。
接下来我们就按照这个设计,做一个简单的 Spring Bean 容器代码实现。编码的过程往往并不会有多复杂,但知晓设计过程却更加重要!
└── src
├── main
│ └── java
│ └── cn.bugstack.springframework
│ ├── BeanDefinition.java
│ └── BeanFactory.java
└── test
└── java
└── cn.bugstack.springframework.test
├── bean
│ └── UserService.java
└── ApiTest.java
Spring Bean 容器的整个实现内容非常简单,也仅仅是包括了一个简单的 BeanFactory
和 BeanDefinition
,这里的类名称是与 Spring 源码中一致,只不过现在的类实现会相对来说更简化一些,在后续的实现过程中再不断的添加内容。
-
BeanDefinition
,用于定义 Bean 实例化信息,现在的实现是以一个 Object 存放对象 -
BeanFactory
,代表了 Bean 对象的工厂,可以存放 Bean 定义到 Map 中以及获取。
Bean 定义
public class BeanDefinition {
private Object bean;
public BeanDefinition(Object bean) {
this.bean = bean;
}
public Object getBean() {
return bean;
}
}
- 目前的 Bean 定义中,只有一个 Object 用于存放 Bean 对象。
- 不过在后面陆续的实现中会逐步完善
BeanDefinition
相关属性的填充,例如:SCOPE_SINGLETON、SCOPE_PROTOTYPE、ROLE_APPLICATION、ROLE_SUPPORT、ROLE_INFRASTRUCTURE
以及Bean Class
信息。
Bean 工厂
public class BeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
public Object getBean(String name) {
return beanDefinitionMap.get(name).getBean();
}
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {
beanDefinitionMap.put(name, beanDefinition);
}
}
- 在 Bean 工厂的实现中,包括了 Bean 的注册,这里注册的是 Bean 的定义信息。同时在这个类中还包括了获取 Bean 的操作。
- 目前的
BeanFactory
仍然是非常简化的实现,但这种简化的实现内容也是整个 Spring 容器中关于 Bean 使用的最终体现结果,只不过实现过程只展示出基本的核心原理。在后续的补充实现中,这个会不断变得庞大。
测试
public class UserService {
public void queryUserInfo(){
System.out.println("查询用户信息");
}
}
public class ApiTest {
@Test
public void test_BeanFactory(){
// 1.初始化 BeanFactory
BeanFactory beanFactory = new BeanFactory();
// 2.注入bean
BeanDefinition beanDefinition = new BeanDefinition(new UserService());
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 3.获取bean
UserService userService = (UserService) beanFactory.getBean("userService");
userService.queryUserInfo();
}
}
- 在单测中主要包括初始化 Bean 工厂、注册 Bean、获取 Bean,三个步骤,使用效果上贴近与 Spring,但显得会更简化。
- 在 Bean 的注册中,这里是直接把 UserService 实例化后作为入参传递给 BeanDefinition 的,在后续的陆续实现中,我们会把这部分内容放入 Bean 工厂中实现。
测试结果
查询用户信息
Process finished with exit code 0
通过测试结果可以看到,目前的 Spring Bean 容器案例,已经稍有雏形。
实现 Bean 的定义、注册、获取
初步依照 Spring Bean 容器的概念,实现了一个粗糙版本的代码实现。我们需要结合已实现的 Spring Bean 容器进行功能完善,实现 Bean 容器关于 Bean 对象的注册和获取。
这一次我们把 Bean 的创建交给容器,而不是我们在调用时候传递一个实例化好的 Bean 对象,另外还需要考虑单例对象,在对象的二次获取时是可以从内存中获取对象的。此外不仅要实现功能还需要完善基础容器框架的类结构体,否则将来就很难扩容进去其他的功能了。
首先非常重要的一点是在 Bean 注册的时候只注册一个类信息,而不会直接把实例化信息注册到 Spring 容器中。那么就需要修改 BeanDefinition 中的属性 Object 为 Class,接下来在需要做的就是在获取 Bean 对象时需要处理 Bean 对象的实例化操作以及判断当前单例对象在容器中是否已经缓存起来了。

- 首先我们需要定义
BeanFactory
这样一个 Bean 工厂,提供 Bean 的获取方法getBean(String name)
,之后这个 Bean 工厂接口由抽象类AbstractBeanFactory
实现。这样使用模板模式的设计方式,可以统一收口通用核心方法的调用逻辑和标准定义,也就很好的控制了后续的实现者不用关心调用逻辑,按照统一方式执行。那么类的继承者只需要关心具体方法的逻辑实现即可。 - 那么在继承抽象类
AbstractBeanFactory
后的AbstractAutowireCapableBeanFactory
就可以实现相应的抽象方法了,因为AbstractAutowireCapableBeanFactory
本身也是一个抽象类,所以它只会实现属于自己的抽象方法,其他抽象方法由继承AbstractAutowireCapableBeanFactory
的类实现。这里就体现了类实现过程中的各司其职,你只需要关心属于你的内容,不是你的内容,不要参与。这一部分内容我们会在代码里有具体的体现 - 另外这里还有块非常重要的知识点,就是关于单例
SingletonBeanRegistry
的接口定义实现,而DefaultSingletonBeanRegistry
对接口实现后,会被抽象类AbstractBeanFactory
继承。现在AbstractBeanFactory
就是一个非常完整且强大的抽象类了,也能非常好的体现出它对模板模式的抽象定义。接下来我们就带着这些设计层面的思考,去看代码的具体实现结果
└── src
├── main
│ └── java
│ └── cn.bugstack.springframework.beans
│ ├── factory
│ │ ├── config
│ │ │ ├── BeanDefinition.java
│ │ │ └── SingletonBeanRegistry.java
│ │ ├── support
│ │ │ ├── AbstractAutowireCapableBeanFactory.java
│ │ │ ├── AbstractBeanFactory.java
│ │ │ ├── BeanDefinitionRegistry.java
│ │ │ ├── DefaultListableBeanFactory.java
│ │ │ └── DefaultSingletonBeanRegistry.java
│ │ └── BeanFactory.java
│ └── BeansException.java
└── test
└── java
└── cn.bugstack.springframework.test
├── bean
│ └── UserService.java
└── ApiTest.java

Spring Bean 容器的功能实现与 Spring 源码
中还有不少的差距,但以目前实现结果的类关系图来看,其实已经具备了一定的设计复杂性,这些复杂的类关系设计在各个接口定义和实现以及在抽象类继承中都有所体现,例如:
-
BeanFactory
的定义由AbstractBeanFactory
抽象类实现接口的getBean
方法 - 而
AbstractBeanFactory
又继承了实现了SingletonBeanRegistry
的DefaultSingletonBeanRegistry
类。这样AbstractBeanFactory
抽象类就具备了单例 Bean 的注册功能。 -
AbstractBeanFactory
中又定义了两个抽象方法:getBeanDefinition(String beanName)、createBean(String beanName, BeanDefinition beanDefinition)
,而这两个抽象方法分别由DefaultListableBeanFactory、AbstractAutowireCapableBeanFactory
实现。 - 最终
DefaultListableBeanFactory
还会继承抽象类AbstractAutowireCapableBeanFactory
也就可以调用抽象类中的createBean
方法了。
综上这一部分的类关系和实现过程还是会有一些复杂的,因为所有的实现都以职责划分、共性分离以及调用关系定义为标准搭建的类关系。这部分内容的学习,可能会丰富你在复杂业务系统开发中的设计思路。
BeanDefinition
定义
public class BeanDefinition {
private Class beanClass;
public BeanDefinition(Class beanClass) {
this.beanClass = beanClass;
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
}
- 在 Bean 定义类中已经把上一节中的 Object bean 替换为 Class,这样就可以把 Bean 的实例化操作放到容器中处理了。你会发现 Bean 的实例化操作是放在初始化调用阶段传递给
BeanDefinition
构造函数的。
单例注册接口定义和实现
public interface SingletonBeanRegistry {
Object getSingleton(String beanName);
}
- 这个类比较简单主要是定义了一个获取单例对象的接口。
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
private final Map<String, Object> singletonObjects = new HashMap<>();
@Override
public Object getSingleton(String beanName) {
return singletonObjects.get(beanName);
}
protected void addSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject);
}
}
- 在
DefaultSingletonBeanRegistry
中主要实现getSingleton
方法,同时实现了一个受保护的addSingleton
方法,这个方法可以被继承此类的其他类调用。包括:AbstractBeanFactory
以及继承的DefaultListableBeanFactory
调用。
抽象类定义模板方法(AbstractBeanFactory
)
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
public Object getBean(String name) throws BeansException {
Object bean = getSingleton(name);
if (bean != null) {
return bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return createBean(name, beanDefinition);
}
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;
}
-
AbstractBeanFactory
首先继承了DefaultSingletonBeanRegistry
,也就具备了使用单例注册类方法。 - 接下来很重要的一点是关于接口
BeanFactory
的实现,在方法getBean
的实现过程中可以看到,主要是对单例 Bean 对象的获取以及在获取不到时需要拿到 Bean 的定义做相应 Bean 实例化操作。那么 getBean 并没有自身的去实现这些方法,而是只定义了调用过程以及提供了抽象方法,由实现此抽象类的其他类做相应实现。 - 后续继承抽象类
AbstractBeanFactory
的类有两个,包括:AbstractAutowireCapableBeanFactory、DefaultListableBeanFactory
,这两个类分别做了相应的实现处理,接着往下看。
实例化Bean
类(AbstractAutowireCapableBeanFactory
)
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
Object bean;
try {
bean = beanDefinition.getBeanClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new BeansException("Instantiation of bean failed", e);
}
addSingleton(beanName, bean);
return bean;
}
}
- 在
AbstractAutowireCapableBeanFactory
类中实现了 Bean 的实例化操作newInstance
,其实这块会埋下一个坑,有构造函数入参的对象怎么处理? - 在处理完 Bean 对象的实例化后,直接调用
addSingleton
方法存放到单例对象的缓存中去。
核心类实现(DefaultListableBeanFactory
)
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {
private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
beanDefinitionMap.put(beanName, beanDefinition);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) throw new BeansException("No bean named '" + beanName + "' is defined");
return beanDefinition;
}
}
-
DefaultListableBeanFactory
在Spring
源码中也是一个非常核心的类,在我们目前的实现中也是逐步贴近于源码,与源码类名保持一致。 -
DefaultListableBeanFactory
继承了AbstractAutowireCapableBeanFactory
类,也就具备了接口BeanFactory
和AbstractBeanFactory
等一连串的功能实现。所以有时候你会看到一些类的强转,调用某些方法,也是因为你强转的类实现接口或继承了某些类。 - 除此之外这个类还实现了接口
BeanDefinitionRegistry
中的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
方法,当然你还会看到一个getBeanDefinition
的实现,这个方法我们文中提到过它是抽象类AbstractBeanFactory
中定义的抽象方法。现在注册Bean定义与获取Bean定义就可以同时使用了,是不感觉这个套路还蛮深的。接口定义了注册,抽象类定义了获取,都集中在DefaultListableBeanFactory
中的beanDefinitionMap
里
定义异常
public class BeansException extends RuntimeException {
public BeansException(String msg) {
super(msg);
}
public BeansException(String msg, Throwable cause) {
super(msg, cause);
}
}
测试
public class UserService {
public void queryUserInfo(){
System.out.println("查询用户信息");
}
}
public class ApiTest {
@Test
public void test_BeanFactory(){
// 1.初始化 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 2.注册 bean
BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 3.第一次获取 bean
UserService userService = (UserService) beanFactory.getBean("userService");
userService.queryUserInfo();
// 4.第二次获取 bean from Singleton
UserService userService_singleton = (UserService) beanFactory.getSingleton("userService");
userService_singleton.queryUserInfo();
}
}
- 在此次的单元测试中除了包括;Bean 工厂、注册 Bean、获取 Bean,三个步骤,还额外增加了一次对象的获取和调用。这里主要测试验证单例对象的是否正确的存放到了缓存中。
- 我们把
UserService.class
传递给了BeanDefinition
而不是像上一节那样直接new UserService()
操作。
结果
查询用户信息
查询用户信息
Process finished with exit code 0
在 Spring Bean 容器的实现类中要重点关注类之间的职责和关系,几乎所有的程序功能设计都离不开接口、抽象类、实现、继承,而这些不同特性类的使用就可以非常好的隔离开类的功能职责和作用范围。而这样的知识点也是在学习手写 Spring Bean 容器框架过程非常重要的知识。
基于Cglib实现含构造函数的类实例化策略
这一节的目标主要是为了解决上一章节我们埋下的坑
,那是什么坑呢?其实就是一个关于 Bean 对象在含有构造函数进行实例化的坑。
在上一节我们扩充了 Bean 容器的功能,把实例化对象交给容器来统一处理,但在我们实例化对象的代码里并没有考虑对象类是否含构造函数,也就是说如果我们去实例化一个含有构造函数的对象那么就要抛异常了。
怎么验证?其实就是把 UserService 添加一个含入参信息的构造函数就可以,如下:
public class UserService {
private String name;
public UserService() {
}
public UserService(String name) {
this.name = name;
}
public void queryUserInfo() {
System.out.println("查询用户信息:" + name);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("");
sb.append("").append(name);
return sb.toString();
}
}
java.lang.InstantiationException: cn.bugstack.springframework.test.bean.UserService
at java.lang.Class.newInstance(Class.java:427)
at cn.bugstack.springframework.test.ApiTest.test_newInstance(ApiTest.java:51)
...
发生这一现象的主要原因就是因为 beanDefinition.getBeanClass().newInstance();
实例化方式并没有考虑构造函数的入参,所以就这个坑就在这等着你了!那么我们的目标就很明显了,来把这个坑填平!
填平这个坑的技术设计主要考虑两部分,一个是串流程从哪合理的把构造函数的入参信息传递到实例化操作里,另外一个是怎么去实例化含有构造函数的对象。

- 参考
Spring Bean
容器源码的实现方式,在BeanFactory
中添加Object getBean(String name, Object... args)
接口,这样就可以在获取 Bean 时把构造函数的入参信息传递进去了。 - 另外一个核心的内容是使用什么方式来创建含有构造函数的 Bean 对象呢?这里有两种方式可以选择,一个是基于 Java 本身自带的方法
DeclaredConstructor
,另外一个是使用 Cglib 来动态创建 Bean 对象。Cglib 是基于字节码框架 ASM 实现,所以你也可以直接通过 ASM 操作指令码来创建对象
└── src
├── main
│ └── java
│ └── cn.bugstack.springframework.beans
│ ├── factory
│ │ ├── config
│ │ │ ├── BeanDefinition.java
│ │ │ └── SingletonBeanRegistry.java
│ │ ├── support
│ │ │ ├── AbstractAutowireCapableBeanFactory.java
│ │ │ ├── AbstractBeanFactory.java
│ │ │ ├── BeanDefinitionRegistry.java
│ │ │ ├── CglibSubclassingInstantiationStrategy.java
│ │ │ ├── DefaultListableBeanFactory.java
│ │ │ ├── DefaultSingletonBeanRegistry.java
│ │ │ ├── InstantiationStrategy.java
│ │ │ └── SimpleInstantiationStrategy.java
│ │ └── BeanFactory.java
│ └── BeansException.java
└── test
└── java
└── cn.bugstack.springframework.test
├── bean
│ └── UserService.java
└── ApiTest.java

主要是在现有工程中添加 InstantiationStrategy
实例化策略接口,以及补充相应的 getBean 入参信息,让外部调用时可以传递构造函数的入参并顺利实例化。
新增 getBean 接口
public interface BeanFactory {
Object getBean(String name) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
}
- BeanFactory 中我们重载了一个含有入参信息 args 的 getBean 方法,这样就可以方便的传递入参给构造函数实例化了。
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, args);
}
protected <T> T doGetBean(final String name, final Object[] args) {
Object bean = getSingleton(name);
if (bean != null) {
return (T) bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return (T) createBean(name, beanDefinition, args);
}
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException;
}
定义实例化策略接口
public interface InstantiationStrategy {
Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException;
}
- 在实例化接口
instantiate
方法中添加必要的入参信息,包括:beanDefinition、 beanName、ctor、args
- 其中
Constructor
你可能会有一点陌生,它是 java.lang.reflect 包下的 Constructor 类,里面包含了一些必要的类信息,有这个参数的目的就是为了拿到符合入参信息相对应的构造函数。 - 而 args 就是一个具体的入参信息了,最终实例化时候会用到。
JDK 实例化
public class SimpleInstantiationStrategy implements InstantiationStrategy {
@Override
public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException {
Class clazz = beanDefinition.getBeanClass();
try {
if (null != ctor) {
return clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);
} else {
return clazz.getDeclaredConstructor().newInstance();
}
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new BeansException("Failed to instantiate [" + clazz.getName() + "]", e);
}
}
}
- 首先通过
beanDefinition
获取 Class 信息,这个 Class 信息是在 Bean 定义的时候传递进去的。 - 接下来判断 ctor 是否为空,如果为空则是无构造函数实例化,否则就是需要有构造函数的实例化。
- 这里我们重点关注有构造函数的实例化,实例化方式为
clazz.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);
,把入参信息传递给 newInstance 进行实例化。
Cglib 实例化
public class CglibSubclassingInstantiationStrategy implements InstantiationStrategy {
@Override
public Object instantiate(BeanDefinition beanDefinition, String beanName, Constructor ctor, Object[] args) throws BeansException {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanDefinition.getBeanClass());
enhancer.setCallback(new NoOp() {
@Override
public int hashCode() {
return super.hashCode();
}
});
if (null == ctor) return enhancer.create();
return enhancer.create(ctor.getParameterTypes(), args);
}
}
其实 Cglib 创建有构造函数的 Bean 也非常方便,在这里我们更加简化的处理了,如果你阅读 Spring 源码还会看到 CallbackFilter
等实现,不过我们目前的方式并不会影响创建。
创建策略调用
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
Object bean = null;
try {
bean = createBeanInstance(beanDefinition, beanName, args);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
}
addSingleton(beanName, bean);
return bean;
}
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
this.instantiationStrategy = instantiationStrategy;
}
}
- 首先在
AbstractAutowireCapableBeanFactory
抽象类中定义了一个创建对象的实例化策略属性类InstantiationStrategy instantiationStrategy
,这里我们选择了Cglib
的实现类。 - 接下来抽取
createBeanInstance
方法,在这个方法中需要注意Constructor
代表了你有多少个构造函数,通过beanClass.getDeclaredConstructors()
方式可以获取到你所有的构造函数,是一个集合。 - 接下来就需要循环比对出构造函数集合与入参信息
args
的匹配情况,这里我们对比的方式比较简单,只是一个数量对比,而实际 Spring 源码中还需要比对入参类型,否则相同数量不同入参类型的情况,就会抛异常了。
其余代码与上节一致
测试
public class UserService {
private String name;
public UserService(String name) {
this.name = name;
}
public void queryUserInfo() {
System.out.println("查询用户信息:" + name);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("");
sb.append("").append(name);
return sb.toString();
}
}
- 这里唯一多在 UserService 中添加的就是一个有 name 入参的构造函数,方便我们验证这样的对象是否能被实例化。
@Test
public void test_BeanFactory() {
// 1.初始化 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 2. 注入bean
BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 3.获取bean
UserService userService = (UserService) beanFactory.getBean("userService", "enm");
userService.queryUserInfo();
}
- 在此次的单元测试中,依然包括包括三个核心步骤;初始化 BeanFactory 工厂、注册 Bean、获取 Bean,此外与上一节不同的是,在获取 Bean 对象时候,传递了一个参数名称为“enm”的入参信息,这个信息的传递将会帮我们创建出含有 String 类型构造函数的 UserService 类,而不会再出现初始化报错的问题。
结果
查询用户信息:enm
Process finished with exit code 0
- 从测试结果来看,最大的变化就是可以满足带有构造函数的对象,可以被实例化了。
- 你可以尝试分别使用两种不同的实例化策略,来进行实例化。
SimpleInstantiationStrategy
、CglibSubclassingInstantiationStrategy
无构造函数
@Test
public void test_newInstance() throws IllegalAccessException, InstantiationException {
UserService userService = UserService.class.newInstance();
System.out.println(userService);
}
- 这种方式的实例化也是我们在上一章节实现 Spring Bean 容器时直接使用的方式
验证有构造函数实例化
@Test
public void test_constructor() throws Exception {
Class<UserService> userServiceClass = UserService.class;
Constructor<UserService> declaredConstructor = userServiceClass.getDeclaredConstructor(String.class);
UserService userService = declaredConstructor.newInstance("伏伏伏");
System.out.println(userService);
}
- 从最简单的操作来看,如果有构造函数的类需要实例化时,则需要使用
getDeclaredConstructor
获取构造函数,之后在通过传递参数进行实例化。
获取构造函数信息
@Test
public void test_parameterTypes() throws Exception {
Class<UserService> beanClass = UserService.class;
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
Constructor<?> constructor = declaredConstructors[0];
Constructor<UserService> declaredConstructor = beanClass.getDeclaredConstructor(constructor.getParameterTypes());
UserService userService = declaredConstructor.newInstance("小小小");
System.out.println(userService);
- 这个案例中其实最核心的点在于获取一个类中所有的构造函数,其实也就是这个方法的使用
beanClass.getDeclaredConstructors()
Cglib 实例化
@Test
public void test_cglib() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new NoOp() {
@Override
public int hashCode() {
return super.hashCode();
}
});
Object obj = enhancer.create(new Class[]{String.class}, new Object[]{"呀呀呀"});
System.out.println(obj);
}
- 此案例演示使用非常简单,但关于 Cglib 在 Spring 容器中的使用非常多,也可以深入的学习一下 Cglib 的扩展知识。
本节的主要以完善实例化操作,增加 InstantiationStrategy
实例化策略接口,并新增了两个实例化类。这部分类的名称与实现方式基本是 Spring 框架的一个缩小版。
为Bean对象注入属性和依赖
之前构建了包括:实现一个容器 (opens new window)、定义和注册Bean (opens new window)、实例化Bean (opens new window),按照是否包含构造函数实现不同的实例化策略 (opens new window),那么在创建对象实例化这我们还缺少什么?其实还缺少一个关于类中是否有属性的问题
,如果有类中包含属性那么在实例化的时候就需要把属性信息填充上,这样才是一个完整的对象创建。
对于属性的填充不只是 int、Long、String,还包括还没有实例化的对象属性,都需要在 Bean 创建时进行填充操作。不过这里我们暂时不会考虑 Bean 的循环依赖,否则会把整个功能实现撑大。
鉴于属性填充是在 Bean 使用 newInstance
或者 Cglib
创建后,开始补全属性信息,那么就可以在类 AbstractAutowireCapableBeanFactory
的 createBean 方法中添加补全属性方法。这部分大家在实习的过程中也可以对照Spring源码学习,这里的实现也是Spring的简化版,后续对照学习会更加易于理解

- 属性填充要在类实例化创建之后,也就是需要在
AbstractAutowireCapableBeanFactory
的 createBean 方法中添加applyPropertyValues
操作。 - 由于我们需要在创建Bean时候填充属性操作,那么就需要在 bean 定义
BeanDefinition
类中,添加PropertyValues
信息。 - 另外是填充属性信息还包括了 Bean 的对象类型,也就是需要再定义一个
BeanReference
,里面其实就是一个简单的 Bean 名称,在具体的实例化操作时进行递归创建和填充,与 Spring 源码实现一样。Spring 源码中BeanReference
是一个接口
└── src
├── main
│ └── java
│ └── cn.bugstack.springframework.beans
│ ├── factory
│ │ ├── config
│ │ │ ├── BeanDefinition.java
│ │ │ ├── BeanReference.java
│ │ │ └── SingletonBeanRegistry.java
│ │ ├── support
│ │ │ ├── AbstractAutowireCapableBeanFactory.java
│ │ │ ├── AbstractBeanFactory.java
│ │ │ ├── BeanDefinitionRegistry.java
│ │ │ ├── CglibSubclassingInstantiationStrategy.java
│ │ │ ├── DefaultListableBeanFactory.java
│ │ │ ├── DefaultSingletonBeanRegistry.java
│ │ │ ├── InstantiationStrategy.java
│ │ │ └── SimpleInstantiationStrategy.java
│ │ └── BeanFactory.java
│ ├── BeansException.java
│ ├── PropertyValue.java
│ └── PropertyValues.java
└── test
└── java
└── cn.bugstack.springframework.test
├── bean
│ ├── UserDao.java
│ └── UserService.java
└── ApiTest.java

- 本章节中需要新增加3个类,
BeanReference
(类引用)、PropertyValue
(属性值)、PropertyValues
(属性集合),分别用于类和其他类型属性填充操作。 - 另外改动的类主要是
AbstractAutowireCapableBeanFactory
,在createBean
中补全属性填充部分。
定义属性
public class PropertyValue {
private final String name;
private final Object value;
public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public Object getValue() {
return value;
}
}
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<>();
public void addPropertyValue(PropertyValue pv) {
this.propertyValueList.add(pv);
}
public PropertyValue[] getPropertyValues() {
return this.propertyValueList.toArray(new PropertyValue[0]);
}
public PropertyValue getPropertyValue(String propertyName) {
for (PropertyValue pv : this.propertyValueList) {
if (pv.getName().equals(propertyName)) {
return pv;
}
}
return null;
}
}
- 这两个类的作用就是创建出一个用于传递类中属性信息的类,因为属性可能会有很多,所以还需要定义一个集合包装下。
Bean 的引用
/*
* Bean 的引用
*/
public class BeanReference {
private final String beanName;
public BeanReference(String beanName) {
this.beanName = beanName;
}
public String getBeanName() {
return beanName;
}
}
Bean定义补全
public class BeanDefinition {
private Class beanClass;
private PropertyValues propertyValues;
public BeanDefinition(Class beanClass) {
this.beanClass = beanClass;
this.propertyValues = new PropertyValues();
}
public BeanDefinition(Class beanClass, PropertyValues propertyValues) {
this.beanClass = beanClass;
this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues();
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
public PropertyValues getPropertyValues() {
return propertyValues;
}
public void setPropertyValues(PropertyValues propertyValues) {
this.propertyValues = propertyValues;
}
}
- 在 Bean 注册的过程中是需要传递 Bean 的信息,在前面几节的测试中都有所体现
new BeanDefinition(UserService.class, propertyValues);
- 所以为了把属性一定交给 Bean 定义,所以这里填充了
PropertyValues
属性,同时把两个构造函数做了一些简单的优化,避免后面 for 循环时还得判断属性填充是否为空。
Bean 属性填充
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
Object bean = null;
try {
bean = createBeanInstance(beanDefinition, beanName, args);
// 给 Bean 填充属性
applyPropertyValues(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
}
addSingleton(beanName, bean);
return bean;
}
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
}
/**
* Bean 属性填充
*/
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
try {
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
// A 依赖 B,获取 B 的实例化
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getBeanName());
}
// 属性填充
BeanUtil.setFieldValue(bean, name, value);
}
} catch (Exception e) {
throw new BeansException("Error setting property values:" + beanName);
}
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
this.instantiationStrategy = instantiationStrategy;
}
}
- 这个类的内容稍微有点长,主要包括三个方法:
createBean、createBeanInstance、applyPropertyValues
,这里我们主要关注createBean
的方法中调用的applyPropertyValues
方法。 - 在
applyPropertyValues
中,通过获取beanDefinition.getPropertyValues()
循环进行属性填充操作,如果遇到的是BeanReference
,那么就需要递归获取 Bean 实例,调用 getBean 方法。 - 当把依赖的 Bean 对象创建完成后,会递归回现在属性填充中。这里需要注意我们并没有去处理循环依赖的问题,这部分内容较大,后续补充。BeanUtil.setFieldValue(bean, name, value) 是 hutool-all 工具类中的方法,你也可以自己实现
测试
public class UserDao {
private static Map<String, String> hashMap = new HashMap<>();
static {
hashMap.put("10001", "小小小");
hashMap.put("10002", "大大大");
hashMap.put("10003", "笑嘻嘻");
}
public String queryUserName(String uId) {
return hashMap.get(uId);
}
}
public class UserService {
private String uId;
private UserDao userDao;
public void queryUserInfo() {
System.out.println("查询用户信息:" + userDao.queryUserName(uId));
}
public String getuId() {
return uId;
}
public void setuId(String uId) {
this.uId = uId;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
- Dao、Service,是我们平常开发经常使用的场景。在
UserService
中注入UserDao
,这样就能体现出Bean属性的依赖了。
public class ApiTest {
@Test
public void test_BeanFactory() {
// 1.初始化 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 2. UserDao 注册
beanFactory.registerBeanDefinition("userDao", new BeanDefinition(UserDao.class));
// 3. UserService 设置属性[uId、userDao]
PropertyValues propertyValues = new PropertyValues();
propertyValues.addPropertyValue(new PropertyValue("uId", "10001"));
propertyValues.addPropertyValue(new PropertyValue("userDao",new BeanReference("userDao")));
// 4. UserService 注入bean
BeanDefinition beanDefinition = new BeanDefinition(UserService.class, propertyValues);
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 5. UserService 获取bean
UserService userService = (UserService) beanFactory.getBean("userService");
userService.queryUserInfo();
}
}
- 与直接获取 Bean 对象不同,这次我们还需要先把 userDao 注入到 Bean 容器中。
beanFactory.registerBeanDefinition("userDao", new BeanDefinition(UserDao.class));
- 接下来就是属性填充的操作了,一种是普通属性
new PropertyValue("uId", "10001")
,另外一种是对象属性new PropertyValue("userDao",new BeanReference("userDao"))
- 接下来的操作就简单了,只不过是正常获取 userService 对象,调用方法即可。
结果
查询用户信息:小小小
Process finished with exit code 0
- 从测试结果看我们的属性填充已经起作用了,因为只有属性填充后,才能调用到Dao方法,如:
userDao.queryUserName(uId)
在本节中我们把 AbstractAutowireCapableBeanFactory
类中的创建对象功能又做了扩充,依赖于是否有构造函数的实例化策略完成后,开始补充 Bean 属性信息。当遇到 Bean 属性为 Bean 对象时,需要递归处理。最后在属性填充时需要用到反射操作,也可以使用一些工具类处理。
关于 Bean 的创建操作就开发完成了,接下来需要整个框架的基础上完成资源属性的加载,就是我们需要去动 Xml 配置了,让我们这小框架越来越像 Spring。另外在框架实现的过程中所有的类名都会参考 Spring 源码,以及相应的设计实现步骤也是与 Spring 源码中对应,只不过会简化一些流程,但你可以拿相同的类名,去搜到每一个功能在 Spring 源码中的实现。
设计与实现资源加载器xml解析和注册
在完成 Spring 的框架雏形后,现在我们可以通过单元测试进行手动操作 Bean 对象的定义、注册和属性填充,以及最终获取对象调用方法。但这里会有一个问题,就是如果实际使用这个 Spring 框架,是不太可能让用户通过手动方式创建的,而是最好能通过配置文件的方式简化创建过程。需要完成如下操作:

- 如图中我们需要把步骤:2、3、4整合到Spring框架中,通过 Spring 配置文件的方式将 Bean 对象实例化。
- 接下来我们就需要在现有的 Spring 框架中,添加能解决 Spring 配置的读取、解析、注册Bean的操作。
我们需要在现有的 Spring 框架雏形中添加一个资源解析器,也就是能读取classpath
、本地文件和云文件的配置内容。这些配置内容就是像使用 Spring 时配置的 Spring.xml 一样,里面会包括 Bean 对象的描述和属性信息。 在读取配置文件信息后,接下来就是对配置文件中的 Bean 描述信息解析后进行注册操作,把 Bean 对象注册到 Spring 容器中。整体设计结构如下图:

- 资源加载器属于相对独立的部分,它位于 Spring 框架核心包下的IO实现内容,主要用于处理Class、本地和云环境中的文件信息。
- 当资源可以加载后,接下来就是解析和注册 Bean 到 Spring 中的操作,这部分实现需要和
DefaultListableBeanFactory
核心类结合起来,因为你所有的解析后的注册动作,都会把 Bean 定义信息放入到这个类中。 - 那么在实现的时候就设计好接口的实现层级关系,包括我们需要定义出 Bean 定义的读取接口
BeanDefinitionReader
以及做好对应的实现类,在实现类中完成对 Bean 对象的解析和注册。
└── src
├── main
│ └── java
│ └── cn.bugstack.springframework
│ ├── beans
│ │ ├── factory
│ │ │ ├── config
│ │ │ │ ├── AutowireCapableBeanFactory.java
│ │ │ │ ├── BeanDefinition.java
│ │ │ │ ├── BeanReference.java
│ │ │ │ ├── ConfigurableBeanFactory.java
│ │ │ │ └── SingletonBeanRegistry.java
│ │ │ ├── support
│ │ │ │ ├── AbstractAutowireCapableBeanFactory.java
│ │ │ │ ├── AbstractBeanDefinitionReader.java
│ │ │ │ ├── AbstractBeanFactory.java
│ │ │ │ ├── BeanDefinitionReader.java
│ │ │ │ ├── BeanDefinitionRegistry.java
│ │ │ │ ├── CglibSubclassingInstantiationStrategy.java
│ │ │ │ ├── DefaultListableBeanFactory.java
│ │ │ │ ├── DefaultSingletonBeanRegistry.java
│ │ │ │ ├── InstantiationStrategy.java
│ │ │ │ └── SimpleInstantiationStrategy.java
│ │ │ ├── support
│ │ │ │ └── XmlBeanDefinitionReader.java
│ │ │ ├── BeanFactory.java
│ │ │ ├── ConfigurableListableBeanFactory.java
│ │ │ ├── HierarchicalBeanFactory.java
│ │ │ └── ListableBeanFactory.java
│ │ ├── BeansException.java
│ │ ├── PropertyValue.java
│ │ └── PropertyValues.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

- 本节为了能把 Bean 的定义、注册和初始化交给 Spring.xml 配置化处理,那么就需要实现两大块内容,分别是:资源加载器、xml资源处理类,实现过程主要以对接口
Resource
、ResourceLoader
的实现,而另外BeanDefinitionReader
接口则是对资源的具体使用,将配置信息注册到 Spring 容器中去。 - 在
Resource
的资源加载器的实现中包括了,ClassPath
、系统文件、云配置文件,这三部分与 Spring 源码中的设计和实现保持一致,最终在DefaultResourceLoader
中做具体的调用。 - 接口:
BeanDefinitionReader
、抽象类:AbstractBeanDefinitionReader
、实现类:XmlBeanDefinitionReader
,这三部分内容主要是合理清晰的处理了资源读取后的注册 Bean 容器操作。接口管定义,抽象类处理非接口功能外的注册Bean组件填充,最终实现类即可只关心具体的业务实现
本节还参考 Spring 源码,做了相应接口的集成和实现的关系,虽然这些接口目前还并没有太大的作用,但随着框架的逐步完善,它们也会发挥作用。
-
BeanFactory
,已经存在的 Bean 工厂接口用于获取 Bean 对象,这次新增加了按照类型获取 Bean 的方法:<T> T getBean(String name, Class<T> requiredType)
-
ListableBeanFactory
,是一个扩展 Bean 工厂接口的接口,新增加了getBeansOfType
、getBeanDefinitionNames()
方法,在 Spring 源码中还有其他扩展方法。 -
HierarchicalBeanFactory
,在 Spring 源码中它提供了可以获取父类BeanFactory
方法,属于是一种扩展工厂的层次子接口。Sub-interface implemented by bean factories that can be part of a hierarchy. -
AutowireCapableBeanFactory
,是一个自动化处理Bean工厂配置的接口,目前案例工程中还没有做相应的实现,后续逐步完善。 -
ConfigurableBeanFactory
,可获取BeanPostProcessor
、BeanClassLoader
等的一个配置化接口。 -
ConfigurableListableBeanFactory
,提供分析和修改Bean以及预先实例化的操作接口,不过目前只有一个getBeanDefinition
方法。
public interface BeanFactory {
Object getBean(String name) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
}
public interface AutowireCapableBeanFactory extends BeanFactory {
}
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
}
因为BeanFactory
增加了按照类型获取 Bean 的方法所以AbstractBeanFactory
这里也要增加
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, args);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return (T) getBean(name);
}
protected <T> T doGetBean(final String name, final Object[] args) {
Object bean = getSingleton(name);
if (bean != null) {
return (T) bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return (T) createBean(name, beanDefinition, args);
}
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException;
}
新增Bean的定义接口
public interface BeanDefinitionRegistry {
/**
* 向注册表中注册 BeanDefinition
*
* @param beanName
* @param beanDefinition
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
/**
* 使用Bean名称查询BeanDefinition
*
* @param beanName
* @return
* @throws BeansException
*/
BeanDefinition getBeanDefinition(String beanName) throws BeansException;
/**
* 判断是否包含指定名称的BeanDefinition
* @param beanName
* @return
*/
boolean containsBeanDefinition(String beanName);
/**
* Return the names of all beans defined in this registry.
*
* 返回注册表中所有的Bean名称
*/
String[] getBeanDefinitionNames();
}
public interface HierarchicalBeanFactory extends BeanFactory {
}
public interface ListableBeanFactory extends BeanFactory{
/**
* 按照类型返回 Bean 实例
* @param type
* @param <T>
* @return
* @throws BeansException
*/
<T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;
/**
* Return the names of all beans defined in this registry.
*
* 返回注册表中所有的Bean名称
*/
String[] getBeanDefinitionNames();
}
public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
BeanDefinition getBeanDefinition(String beanName) throws BeansException;
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry, ConfigurableListableBeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
beanDefinitionMap.put(beanName, beanDefinition);
}
@Override
public boolean containsBeanDefinition(String beanName) {
return beanDefinitionMap.containsKey(beanName);
}
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
Map<String, T> result = new HashMap<>();
beanDefinitionMap.forEach((beanName, beanDefinition) -> {
Class beanClass = beanDefinition.getBeanClass();
if (type.isAssignableFrom(beanClass)) {
result.put(beanName, (T) getBean(beanName));
}
});
return result;
}
@Override
public String[] getBeanDefinitionNames() {
return beanDefinitionMap.keySet().toArray(new String[0]);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) throw new BeansException("No bean named '" + beanName + "' is defined");
return beanDefinition;
}
}
上面是一些对上节代码的调整和添加起到这里的辅助作用
资源加载接口定义和实现
public interface Resource {
InputStream getInputStream() throws IOException;
}
- 在 Spring 框架下创建
core.io
核心包,在这个包中主要用于处理资源加载流。 - 定义
Resource
接口,提供获取InputStream
流的方法,接下来再分别实现三种不同的流文件操作:classPath、FileSystem、URL
public class ClassPathResource implements Resource {
private final String path;
private ClassLoader classLoader;
public ClassPathResource(String path) {
this(path, (ClassLoader) null);
}
public ClassPathResource(String path, ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
this.path = path;
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
@Override
public InputStream getInputStream() throws IOException {
InputStream is = classLoader.getResourceAsStream(path);
if (is == null) {
throw new FileNotFoundException(
this.path + " cannot be opened because it does not exist");
}
return is;
}
}
public class ClassUtils {
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back to system class loader...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
}
return cl;
}
}
- 这一部分的实现是用于通过
ClassLoader
读取ClassPath
下的文件信息,具体的读取过程主要是:classLoader.getResourceAsStream(path)
public class FileSystemResource implements Resource {
private final File file;
private final String path;
public FileSystemResource(File file) {
this.file = file;
this.path = file.getPath();
}
public FileSystemResource(String path) {
this.file = new File(path);
this.path = path;
}
@Override
public InputStream getInputStream() throws IOException {
return new FileInputStream(this.file);
}
public final String getPath() {
return this.path;
}
}
- 通过指定文件路径的方式读取文件信息,这部分大家肯定还是非常熟悉的,经常会读取一些txt、excel文件输出到控制台。
public class UrlResource implements Resource{
private final URL url;
public UrlResource(URL url) {
Assert.notNull(url,"URL must not be null");
this.url = url;
}
@Override
public InputStream getInputStream() throws IOException {
URLConnection con = this.url.openConnection();
try {
return con.getInputStream();
}
catch (IOException ex){
if (con instanceof HttpURLConnection){
((HttpURLConnection) con).disconnect();
}
throw ex;
}
}
}
- 通过 HTTP 的方式读取云服务的文件,我们也可以把配置文件放到 GitHub 或者 Gitee 上。
包装资源加载器
按照资源加载的不同方式,资源加载器可以把这些方式集中到统一的类服务下进行处理,外部用户只需要传递资源地址即可,简化使用。
public interface ResourceLoader {
/**
* Pseudo URL prefix for loading from the class path: "classpath:"
*/
String CLASSPATH_URL_PREFIX = "classpath:";
Resource getResource(String location);
}
- 定义获取资源接口,里面传递 location 地址即可。
public class DefaultResourceLoader implements ResourceLoader {
@Override
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()));
}
else {
try {
URL url = new URL(location);
return new UrlResource(url);
} catch (MalformedURLException e) {
return new FileSystemResource(location);
}
}
}
}
- 在获取资源的实现中,主要是把三种不同类型的资源处理方式进行了包装,分为:判断是否为
ClassPath、URL
以及文件。 - 虽然
DefaultResourceLoader
类实现的过程简单,但这也是设计模式约定的具体结果,像是这里不会让外部调用放知道过多的细节,而是仅关心具体调用结果即可。
Bean定义读取接口
public interface BeanDefinitionReader {
BeanDefinitionRegistry getRegistry();
ResourceLoader getResourceLoader();
void loadBeanDefinitions(Resource resource) throws BeansException;
void loadBeanDefinitions(Resource... resources) throws BeansException;
void loadBeanDefinitions(String location) throws BeansException;
}
- 这是一个
Simple interface for bean definition readers.
其实里面无非定义了几个方法,包括:getRegistry()、getResourceLoader()
,以及三个加载Bean定义的方法。 - 这里需要注意
getRegistry()、getResourceLoader()
,都是用于提供给后面三个方法的工具,加载和注册,这两个方法的实现会包装到抽象类中,以免污染具体的接口实现方法。
Bean定义抽象类实现
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
private final BeanDefinitionRegistry registry;
private ResourceLoader resourceLoader;
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, new DefaultResourceLoader());
}
public AbstractBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
this.registry = registry;
this.resourceLoader = resourceLoader;
}
@Override
public BeanDefinitionRegistry getRegistry() {
return registry;
}
@Override
public ResourceLoader getResourceLoader() {
return resourceLoader;
}
}
- 抽象类把
BeanDefinitionReader
接口的前两个方法全部实现完了,并提供了构造函数,让外部的调用使用方,把Bean定义注入类,传递进来。 - 这样在接口
BeanDefinitionReader
的具体实现类中,就可以把解析后的 XML 文件中的 Bean 信息,注册到 Spring 容器去了。以前我们是通过单元测试使用,调用 BeanDefinitionRegistry 完成Bean的注册,现在可以放到 XMl 中操作了
解析XML处理Bean注册
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
super(registry, resourceLoader);
}
@Override
public void loadBeanDefinitions(Resource resource) throws BeansException {
try {
try (InputStream inputStream = resource.getInputStream()) {
doLoadBeanDefinitions(inputStream);
}
} catch (IOException | ClassNotFoundException e) {
throw new BeansException("IOException parsing XML document from " + resource, e);
}
}
@Override
public void loadBeanDefinitions(Resource... resources) throws BeansException {
for (Resource resource : resources) {
loadBeanDefinitions(resource);
}
}
@Override
public void loadBeanDefinitions(String location) throws BeansException {
ResourceLoader resourceLoader = getResourceLoader();
Resource resource = resourceLoader.getResource(location);
loadBeanDefinitions(resource);
}
protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {
Document doc = XmlUtil.readXML(inputStream);
Element root = doc.getDocumentElement();
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
// 判断元素
if (!(childNodes.item(i) instanceof Element)) continue;
// 判断对象
if (!"bean".equals(childNodes.item(i).getNodeName())) continue;
// 解析标签
Element bean = (Element) childNodes.item(i);
String id = bean.getAttribute("id");
String name = bean.getAttribute("name");
String className = bean.getAttribute("class");
// 获取 Class,方便获取类中的名称
Class<?> clazz = Class.forName(className);
// 优先级 id > name
String beanName = StrUtil.isNotEmpty(id) ? id : name;
if (StrUtil.isEmpty(beanName)) {
beanName = StrUtil.lowerFirst(clazz.getSimpleName());
}
// 定义Bean
BeanDefinition beanDefinition = new BeanDefinition(clazz);
// 读取属性并填充
for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
if (!(bean.getChildNodes().item(j) instanceof Element)) continue;
if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) continue;
// 解析标签:property
Element property = (Element) bean.getChildNodes().item(j);
String attrName = property.getAttribute("name");
String attrValue = property.getAttribute("value");
String attrRef = property.getAttribute("ref");
// 获取属性值:引入对象、值对象
Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
// 创建属性信息
PropertyValue propertyValue = new PropertyValue(attrName, value);
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
if (getRegistry().containsBeanDefinition(beanName)) {
throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
}
// 注册 BeanDefinition
getRegistry().registerBeanDefinition(beanName, beanDefinition);
}
}
}
XmlBeanDefinitionReader
类最核心的内容就是对 XML 文件的解析,把我们本来在代码中的操作放到了通过解析 XML 自动注册的方式。
-
loadBeanDefinitions
方法,处理资源加载,这里新增加了一个内部方法:doLoadBeanDefinitions
,它主要负责解析 xml - 在
doLoadBeanDefinitions
方法中,主要是对xml的读取XmlUtil.readXML(inputStream)
和元素 Element 解析。在解析的过程中通过循环操作,以此获取 Bean 配置以及配置中的 id、name、class、value、ref 信息。 - 最终把读取出来的配置信息,创建成
BeanDefinition
以及PropertyValue
,最终把完整的 Bean 定义内容注册到 Bean 容器:getRegistry().registerBeanDefinition(beanName, beanDefinition)
测试
public class UserDao {
private static Map<String, String> hashMap = new HashMap<>();
static {
hashMap.put("10001", "小小小");
hashMap.put("10002", "大大大");
hashMap.put("10003", "啊啊啊");
}
public String queryUserName(String uId) {
return hashMap.get(uId);
}
}
public class UserService {
private String uId;
private UserDao userDao;
public String queryUserInfo() {
return userDao.queryUserName(uId);
}
public String getuId() {
return uId;
}
public void setuId(String uId) {
this.uId = uId;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
- Dao、Service,是我们平常开发经常使用的场景。在 UserService 中注入 UserDao,这样就能体现出Bean属性的依赖了。
配置文件important.properties
# Config File
system.key=OLpj9823dZ
spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="userDao" class="cn.bugstack.springframework.test.bean.UserDao"/>
<bean id="userService" class="cn.bugstack.springframework.test.bean.UserService">
<property name="uId" value="10001"/>
<property name="userDao" ref="userDao"/>
</bean>
</beans>
- 这里有两份配置文件,一份用于测试资源加载器,另外 spring.xml 用于测试整体的 Bean 注册功能。
单元测试(资源加载)
private DefaultResourceLoader resourceLoader;
@Before
public void init() {
resourceLoader = new DefaultResourceLoader();
}
@Test
public void test_classpath() throws IOException {
Resource resource = resourceLoader.getResource("classpath:important.properties");
InputStream inputStream = resource.getInputStream();
String content = IoUtil.readUtf8(inputStream);
System.out.println(content);
}
@Test
public void test_file() throws IOException {
Resource resource = resourceLoader.getResource("src/test/resources/important.properties");
InputStream inputStream = resource.getInputStream();
String content = IoUtil.readUtf8(inputStream);
System.out.println(content);
}
@Test
public void test_url() throws IOException {
Resource resource = resourceLoader.getResource("https://github.com/fuzhengwei/small-spring/important.properties"
InputStream inputStream = resource.getInputStream();
String content = IoUtil.readUtf8(inputStream);
System.out.println(content);
}
结果
# Config File
system.key=OLpj9823dZ
Process finished with exit code 0
- 这三个方法:test_classpath、test_file、test_url,分别用于测试加载 ClassPath、FileSystem、Url 文件,URL文件在Github,可能加载时会慢
单元测试(配置文件注册Bean)
@Test
public void test_xml() {
// 1.初始化 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 2. 读取配置文件&注册Bean
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("classpath:spring.xml");
// 3. 获取Bean对象调用方法
UserService userService = beanFactory.getBean("userService", UserService.class);
String result = userService.queryUserInfo();
System.out.println("测试结果:" + result);
}
测试结果
测试结果:小小小
Process finished with exit code 0
- 在上面的测试案例中可以看到,我们把以前通过手动注册 Bean 以及配置属性信息的内容,交给了
new XmlBeanDefinitionReader(beanFactory)
类读取 Spring.xml 的方式来处理,并通过了测试验证。
此时的工程结构已经越来越有 Spring 框架的味道了,以配置文件为入口解析和注册 Bean 信息,最终再通过 Bean 工厂获取 Bean 以及做相应的调用操作。
实现应用上下文,自动识别、资源加载、扩展机制
如果你在自己的实际工作中开发过基于 Spring 的技术组件,或者学习过关于 SpringBoot 中间件设计和开发等内容。那么你一定会继承或者实现了 Spring 对外暴露的类或接口,在接口的实现中获取了 BeanFactory 以及 Bean 对象的获取等内容,并对这些内容做一些操作,例如:修改 Bean 的信息,添加日志打印、处理数据库路由对数据源的切换、给 RPC 服务连接注册中心等。
在对容器中 Bean 的实例化过程添加扩展机制的同时,还需要把目前关于 Spring.xml 初始化和加载策略进行优化,因为我们不太可能让面向 Spring 本身开发的 DefaultListableBeanFactory
服务,直接给予用户使用。修改点如下:

-
DefaultListableBeanFactory、XmlBeanDefinitionReader
,是我们在目前 Spring 框架中对于服务功能测试的使用方式,它能很好的体现出 Spring 是如何对 xml 加载以及注册Bean对象的操作过程,但这种方式是面向 Spring 本身的,还不具备一定的扩展性。 - 就像我们现在需要提供出一个可以在 Bean 初始化过程中,完成对 Bean 对象的扩展时,就很难做到自动化处理。所以我们要把 Bean 对象扩展机制功能和对 Spring 框架上下文的包装融合起来,对外提供完整的服务。
为了能满足于在 Bean 对象从注册到实例化的过程中执行用户的自定义操作,就需要在 Bean 的定义和初始化过程中插入接口类,这个接口再有外部去实现自己需要的服务。那么在结合对 Spring 框架上下文的处理能力,就可以满足我们的目标需求了。整体设计结构如下图:

- 满足于对 Bean 对象扩展的两个接口,其实也是 Spring 框架中非常具有重量级的两个接口:
BeanFactoryPostProcess
和BeanPostProcessor
,也几乎是大家在使用 Spring 框架额外新增开发自己组建需求的两个必备接口。 -
BeanFactoryPostProcessor
,是由 Spring 框架组建提供的容器扩展机制,允许在 Bean 对象注册后但未实例化之前,对 Bean 的定义信息BeanDefinition
执行修改操作。 -
BeanPostProcessor
,也是 Spring 提供的扩展机制,不过BeanPostProcessor
是在 Bean 对象实例化之后修改 Bean 对象,也可以替换 Bean 对象。这部分与后面要实现的 AOP 有着密切的关系。 - 同时如果只是添加这两个接口,不做任何包装,那么对于使用者来说还是非常麻烦的。我们希望于开发 Spring 的上下文操作类,把相应的 XML 加载 、注册、实例化以及新增的修改和扩展都融合进去,让 Spring 可以自动扫描到我们的新增服务,便于用户使用。
└── 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
│ │ │ │ ├── InstantiationStrategy.java
│ │ │ │ └── SimpleInstantiationStrategy.java
│ │ │ ├── support
│ │ │ │ └── XmlBeanDefinitionReader.java
│ │ │ ├── BeanFactory.java
│ │ │ ├── ConfigurableListableBeanFactory.java
│ │ │ ├── HierarchicalBeanFactory.java
│ │ │ └── ListableBeanFactory.java
│ │ ├── BeansException.java
│ │ ├── PropertyValue.java
│ │ └── PropertyValues.java
│ ├── context
│ │ ├── support
│ │ │ ├── AbstractApplicationContext.java
│ │ │ ├── AbstractRefreshableApplicationContext.java
│ │ │ ├── AbstractXmlApplicationContext.java
│ │ │ └── ClassPathXmlApplicationContext.java
│ │ ├── ApplicationContext.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
├── common
│ ├── MyBeanFactoryPostProcessor.java
│ └── MyBeanPostProcessor.java
└── ApiTest.java

- 主要体现出来的是关于 Spring 应用上下文以及对 Bean 对象扩展机制的实现。
- 以继承了
ListableBeanFactory
接口的ApplicationContext
接口开始,扩展出一系列应用上下文的抽象实现类,并最终完成ClassPathXmlApplicationContext
类的实现。而这个类就是最后交给用户使用的类。 - 同时在实现应用上下文的过程中,通过定义接口:
BeanFactoryPostProcessor
、BeanPostProcessor
两个接口,把关于对 Bean 的扩展机制串联进去了。
修改一些之前的代码
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
}
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
/** BeanPostProcessors to apply in createBean */
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, args);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return (T) getBean(name);
}
protected <T> T doGetBean(final String name, final Object[] args) {
Object bean = getSingleton(name);
if (bean != null) {
return (T) bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return (T) createBean(name, beanDefinition, args);
}
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException;
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor){
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
}
/**
* Return the list of BeanPostProcessors that will get applied
* to beans created with this factory.
*/
public List<BeanPostProcessor> getBeanPostProcessors() {
return this.beanPostProcessors;
}
}
public interface BeanDefinitionReader {
BeanDefinitionRegistry getRegistry();
ResourceLoader getResourceLoader();
void loadBeanDefinitions(Resource resource) throws BeansException;
void loadBeanDefinitions(Resource... resources) throws BeansException;
void loadBeanDefinitions(String location) throws BeansException;
void loadBeanDefinitions(String... locations) throws BeansException;
}
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
super(registry, resourceLoader);
}
@Override
public void loadBeanDefinitions(Resource resource) throws BeansException {
try {
try (InputStream inputStream = resource.getInputStream()) {
doLoadBeanDefinitions(inputStream);
}
} catch (IOException | ClassNotFoundException e) {
throw new BeansException("IOException parsing XML document from " + resource, e);
}
}
@Override
public void loadBeanDefinitions(Resource... resources) throws BeansException {
for (Resource resource : resources) {
loadBeanDefinitions(resource);
}
}
@Override
public void loadBeanDefinitions(String location) throws BeansException {
ResourceLoader resourceLoader = getResourceLoader();
Resource resource = resourceLoader.getResource(location);
loadBeanDefinitions(resource);
}
@Override
public void loadBeanDefinitions(String... locations) throws BeansException {
for (String location : locations) {
loadBeanDefinitions(location);
}
}
protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {
Document doc = XmlUtil.readXML(inputStream);
Element root = doc.getDocumentElement();
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
// 判断元素
if (!(childNodes.item(i) instanceof Element)) continue;
// 判断对象
if (!"bean".equals(childNodes.item(i).getNodeName())) continue;
// 解析标签
Element bean = (Element) childNodes.item(i);
String id = bean.getAttribute("id");
String name = bean.getAttribute("name");
String className = bean.getAttribute("class");
// 获取 Class,方便获取类中的名称
Class<?> clazz = Class.forName(className);
// 优先级 id > name
String beanName = StrUtil.isNotEmpty(id) ? id : name;
if (StrUtil.isEmpty(beanName)) {
beanName = StrUtil.lowerFirst(clazz.getSimpleName());
}
// 定义Bean
BeanDefinition beanDefinition = new BeanDefinition(clazz);
// 读取属性并填充
for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
if (!(bean.getChildNodes().item(j) instanceof Element)) continue;
if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) continue;
// 解析标签:property
Element property = (Element) bean.getChildNodes().item(j);
String attrName = property.getAttribute("name");
String attrValue = property.getAttribute("value");
String attrRef = property.getAttribute("ref");
// 获取属性值:引入对象、值对象
Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
// 创建属性信息
PropertyValue propertyValue = new PropertyValue(attrName, value);
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
if (getRegistry().containsBeanDefinition(beanName)) {
throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
}
// 注册 BeanDefinition
getRegistry().registerBeanDefinition(beanName, beanDefinition);
}
}
}
public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
BeanDefinition getBeanDefinition(String beanName) throws BeansException;
void preInstantiateSingletons() throws BeansException;
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry, ConfigurableListableBeanFactory {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
beanDefinitionMap.put(beanName, beanDefinition);
}
@Override
public boolean containsBeanDefinition(String beanName) {
return beanDefinitionMap.containsKey(beanName);
}
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
Map<String, T> result = new HashMap<>();
beanDefinitionMap.forEach((beanName, beanDefinition) -> {
Class beanClass = beanDefinition.getBeanClass();
if (type.isAssignableFrom(beanClass)) {
result.put(beanName, (T) getBean(beanName));
}
});
return result;
}
@Override
public String[] getBeanDefinitionNames() {
return beanDefinitionMap.keySet().toArray(new String[0]);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) throw new BeansException("No bean named '" + beanName + "' is defined");
return beanDefinition;
}
@Override
public void preInstantiateSingletons() throws BeansException {
beanDefinitionMap.keySet().forEach(this::getBean);
}
}
定义 BeanFactoryPostProcessor
public interface BeanFactoryPostProcessor {
/**
* 在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制
*
* @param beanFactory
* @throws BeansException
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
- 在 Spring 源码中有这样一段描述
Allows for custom modification of an application context's bean definitions,adapting the bean property values of the context's underlying bean factory.
其实也就是说这个接口是满足于在所有的BeanDefinition
加载完成后,实例化 Bean 对象之前,提供修改BeanDefinition
属性的机制。
定义 BeanPostProcessor
public interface BeanPostProcessor {
/**
* 在 Bean 对象执行初始化方法之前,执行此方法
*
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
/**
* 在 Bean 对象执行初始化方法之后,执行此方法
*
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
- 在 Spring 源码中有这样一段描述
Factory hook that allows for custom modification of new bean instances,e.g. checking for marker interfaces or wrapping them with proxies.
也就是提供了修改新实例化 Bean 对象的扩展点。 - 另外此接口提供了两个方法:
postProcessBeforeInitialization
用于在 Bean 对象执行初始化方法之前,执行此方法、postProcessAfterInitialization
用于在 Bean 对象执行初始化方法之后,执行此方法。
定义上下文接口
public interface ApplicationContext extends ListableBeanFactory {
}
-
context
是本次实现应用上下文功能新增的服务包 -
ApplicationContext
,继承于ListableBeanFactory
,也就继承了关于BeanFactory
方法,比如一些getBean
的方法。另外ApplicationContext
本身是Central
接口,但目前还不需要添加一些获取ID和父类上下文,所以暂时没有接口方法的定义。
public interface ConfigurableApplicationContext extends ApplicationContext {
/**
* 刷新容器
*
* @throws BeansException
*/
void refresh() throws BeansException;
}
-
ConfigurableApplicationContext
继承自ApplicationContext
,并提供了refresh
这个核心方法。如果你有看过一些 Spring 源码,那么一定会看到这个方法。 接下来也是需要在上下文的实现中完成刷新容器的操作过程。
应用上下文抽象类实现
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException {
// 1. 创建 BeanFactory,并加载 BeanDefinition
refreshBeanFactory();
// 2. 获取 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 3. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
invokeBeanFactoryPostProcessors(beanFactory);
// 4. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
registerBeanPostProcessors(beanFactory);
// 5. 提前实例化单例Bean对象
beanFactory.preInstantiateSingletons();
}
protected abstract void refreshBeanFactory() throws BeansException;
protected abstract ConfigurableListableBeanFactory getBeanFactory();
private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
}
}
private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
beanFactory.addBeanPostProcessor(beanPostProcessor);
}
}
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
return getBeanFactory().getBeansOfType(type);
}
@Override
public String[] getBeanDefinitionNames() {
return getBeanFactory().getBeanDefinitionNames();
}
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return getBeanFactory().getBean(name, args);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(name, requiredType);
}
}
-
AbstractApplicationContext
继承DefaultResourceLoader
是为了处理spring.xml
配置资源的加载。 - 之后是在
refresh()
定义实现过程,包括:- 创建
BeanFactory
,并加载BeanDefinition
- 获取
BeanFactory
- 在
Bean
实例化之前,执行BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
-
BeanPostProcessor
需要提前于其他 Bean 对象实例化之前执行注册操作 - 提前实例化单例
Bean
对象
- 创建
- 另外把定义出来的抽象方法,
refreshBeanFactory()、getBeanFactory()
由后面的继承此抽象类的其他抽象类实现。
获取Bean工厂和加载资源
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
private DefaultListableBeanFactory beanFactory;
@Override
protected void refreshBeanFactory() throws BeansException {
DefaultListableBeanFactory beanFactory = createBeanFactory();
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
private DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory();
}
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory);
@Override
protected ConfigurableListableBeanFactory getBeanFactory() {
return beanFactory;
}
}
- 在 refreshBeanFactory() 中主要是获取了
DefaultListableBeanFactory
的实例化以及对资源配置的加载操作loadBeanDefinitions(beanFactory)
,在加载完成后即可完成对 spring.xml 配置文件中 Bean 对象的定义和注册,同时也包括实现了接口 BeanFactoryPostProcessor、BeanPostProcessor 的配置 Bean 信息。 - 但此时资源加载还只是定义了一个抽象类方法
loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
,继续由其他抽象类继承实现。
上下文中对配置信息的加载
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext {
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory, this);
String[] configLocations = getConfigLocations();
if (null != configLocations){
beanDefinitionReader.loadBeanDefinitions(configLocations);
}
}
protected abstract String[] getConfigLocations();
}
- 在
AbstractXmlApplicationContext
抽象类的loadBeanDefinitions
方法实现中,使用XmlBeanDefinitionReader
类,处理了关于 XML 文件配置信息的操作。 - 同时这里又留下了一个抽象类方法,
getConfigLocations()
,此方法是为了从入口上下文类,拿到配置信息的地址描述。
应用上下文实现类(ClassPathXmlApplicationContext
)
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
private String[] configLocations;
public ClassPathXmlApplicationContext() {
}
/**
* 从 XML 中加载 BeanDefinition,并刷新上下文
*
* @param configLocations
* @throws BeansException
*/
public ClassPathXmlApplicationContext(String configLocations) throws BeansException {
this(new String[]{configLocations});
}
/**
* 从 XML 中加载 BeanDefinition,并刷新上下文
* @param configLocations
* @throws BeansException
*/
public ClassPathXmlApplicationContext(String[] configLocations) throws BeansException {
this.configLocations = configLocations;
refresh();
}
@Override
protected String[] getConfigLocations() {
return configLocations;
}
}
-
ClassPathXmlApplicationContext
,是具体对外给用户提供的应用上下文方法。 - 在继承了
AbstractXmlApplicationContext
以及层层抽象类的功能分离实现后,在此类ClassPathXmlApplicationContext
的实现中就简单多了,主要是对继承抽象类中方法的调用和提供了配置文件地址信息。
在Bean创建时完成前置和后置处理
public interface AutowireCapableBeanFactory extends BeanFactory {
/**
* 执行 BeanPostProcessors 接口实现类的 postProcessBeforeInitialization 方法
*
* @param existingBean
* @param beanName
* @return
* @throws BeansException
*/
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;
/**
* 执行 BeanPostProcessors 接口实现类的 postProcessorsAfterInitialization 方法
*
* @param existingBean
* @param beanName
* @return
* @throws BeansException
*/
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
}
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected 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);
}
addSingleton(beanName, bean);
return bean;
}
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
}
/**
* Bean 属性填充
*/
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
try {
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
// A 依赖 B,获取 B 的实例化
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getBeanName());
}
// 属性填充
BeanUtil.setFieldValue(bean, name, value);
}
} catch (Exception e) {
throw new BeansException("Error setting property values:" + beanName);
}
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
this.instantiationStrategy = instantiationStrategy;
}
private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
// 1. 执行 BeanPostProcessor Before 处理
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
// 待完成内容:invokeInitMethods(beanName, wrappedBean, beanDefinition);
invokeInitMethods(beanName, wrappedBean, beanDefinition);
// 2. 执行 BeanPostProcessor After 处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
private void invokeInitMethods(String beanName, Object wrappedBean, BeanDefinition beanDefinition) {
}
@Override
public 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;
}
@Override
public 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;
}
}
- 实现
BeanPostProcessor
接口后,会涉及到两个接口方法,postProcessBeforeInitialization
、postProcessAfterInitialization
,分别作用于 Bean 对象执行初始化前后的额外处理。 - 也就是需要在创建
Bean
对象时,在createBean
方法中添加initializeBean(beanName, bean, beanDefinition);
操作。而这个操作主要主要是对于方法applyBeanPostProcessorsBeforeInitialization
、applyBeanPostProcessorsAfterInitialization
的使用。 - 另外需要提一下,
applyBeanPostProcessorsBeforeInitialization
、applyBeanPostProcessorsAfterInitialization
两个方法是在接口类AutowireCapableBeanFactory
中新增加的。
测试
public class UserDao {
private static Map<String, String> hashMap = new HashMap<>();
static {
hashMap.put("10001", "小小小");
hashMap.put("10002", "大大大");
hashMap.put("10003", "啊啊啊");
}
public String queryUserName(String uId) {
return hashMap.get(uId);
}
}
public class UserService {
private String uId;
private String company;
private String location;
private UserDao userDao;
public String queryUserInfo() {
return userDao.queryUserName(uId) + "," + company + "," + location;
}
public String getuId() {
return uId;
}
public void setuId(String uId) {
this.uId = uId;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
- Dao、Service,是我们平常开发经常使用的场景。在 UserService 中注入 UserDao,这样就能体现出Bean属性的依赖了。
- 另外这里新增加了
company、location
,两个属性信息,便于测试BeanPostProcessor、BeanFactoryPostProcessor
两个接口对 Bean 属性信息扩展的作用。
实现 BeanPostProcessor
和 BeanFactoryPostProcessor
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
PropertyValues propertyValues = beanDefinition.getPropertyValues();
propertyValues.addPropertyValue(new PropertyValue("company", "改为:飞飞飞飞"));
}
}
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
UserService userService = (UserService) bean;
userService.setLocation("改为:浙江");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
- 如果你在 Spring 中做过一些组件的开发那么一定非常熟悉这两个类,本文的测试也是实现了这两个类,对实例化过程中的 Bean 对象做一些操作。
配置文件
基础配置,无BeanFactoryPostProcessor、BeanPostProcessor
,实现类
spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="userDao" class="cn.bugstack.springframework.test.bean.UserDao"/>
<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>
增强配置,有BeanFactoryPostProcessor、BeanPostProcessor
,实现类
springPostProcessor.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="userDao" class="cn.bugstack.springframework.test.bean.UserDao"/>
<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>
<bean class="cn.bugstack.springframework.test.common.MyBeanPostProcessor"/>
<bean class="cn.bugstack.springframework.test.common.MyBeanFactoryPostProcessor"/>
</beans>
- 这里提供了两个配置文件,一个是不包含
BeanFactoryPostProcessor
、BeanPostProcessor
,另外一个是包含的。之所以这样配置主要对照验证,在运用 Spring 新增加的应用上下文和不使用的时候,都是怎么操作的。
不用应用上下文
@Test
public void test_BeanFactoryPostProcessorAndBeanPostProcessor(){
// 1.初始化 BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 2. 读取配置文件&注册Bean
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("classpath:spring.xml");
// 3. BeanDefinition 加载完成 & Bean实例化之前,修改 BeanDefinition 的属性值
MyBeanFactoryPostProcessor beanFactoryPostProcessor = new MyBeanFactoryPostProcessor();
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
// 4. Bean实例化之后,修改 Bean 属性信息
MyBeanPostProcessor beanPostProcessor = new MyBeanPostProcessor();
beanFactory.addBeanPostProcessor(beanPostProcessor);
// 5. 获取Bean对象调用方法
UserService userService = beanFactory.getBean("userService", UserService.class);
String result = userService.queryUserInfo();
System.out.println("测试结果:" + result);
}
-
DefaultListableBeanFactory
创建beanFactory
并使用XmlBeanDefinitionReader
加载配置文件的方式,还是比较熟悉的。 - 接下来就是对
MyBeanFactoryPostProcessor
和MyBeanPostProcessor
的处理,一个是在BeanDefinition
加载完成 & Bean实例化之前,修改BeanDefinition
的属性值,另外一个是在Bean实例化之后,修改 Bean 属性信息。
结果
测试结果:小小小,改为:飞飞飞飞,改为:浙江
Process finished with exit code 0
- 通过测试结果可以看到,我们配置的属性信息已经与 spring.xml 配置文件中不一样了。
使用应用上下文
@Test
public void test_xml() {
// 1.初始化 BeanFactory
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:springPostProcessor.xml");
// 2. 获取Bean对象调用方法
UserService userService = applicationContext.getBean("userService", UserService.class);
String result = userService.queryUserInfo();
System.out.println("测试结果:" + result);
}
- 另外使用新增加的
ClassPathXmlApplicationContext
应用上下文类,再操作起来就方便多了,这才是面向用户使用的类,在这里可以一步把配置文件交给ClassPathXmlApplicationContext
,也不需要管理一些自定义实现的 Spring 接口的类。
结果
测试结果:小小小,改为:飞飞飞飞,改为:浙江
Process finished with exit code 0
- 这与不用应用上下文的测试结果是一样,不过现在的方式更加方便了。
主要新增了 Spring 框架中两个非常重要的接口 BeanFactoryPostProcess、BeanPostProcessor
同时还添加了关于应用上下文的实现,ApplicationContext
接口的定义是继承 BeanFactory
外新增加功能的接口,它可以满足于自动识别、资源加载、容器事件、监听器等功能,同时例如一些国际化支持、单例Bean自动初始化等,也是可以在这个类里实现和扩充的。
通过本文的实现一定会非常了解 BeanFactoryPostProcess
、BeanPostProcessor
,以后再做一些关于 Spring 中间件的开发时,如果需要用到 Bean 对象的获取以及修改一些属性信息,那么就可以使用这两个接口了。同时 BeanPostProcessor
也是实现 AOP 切面技术的关键所在。
实现Bean对象的初始化和销毁方法
当我们的类创建的 Bean 对象,交给 Spring 容器管理以后,这个类对象就可以被赋予更多的使用能力。就像我们在上节已经给类对象添加了修改注册Bean定义未实例化前的属性信息修改和初始化过程中的前置和后置处理,这些额外能力的实现,都可以让我们对现有工程中的类对象做相应的扩展处理。
那么除此之外我们还希望可以在 Bean 初始化过程,执行一些操作。比如帮我们做一些数据的加载执行,链接注册中心暴漏RPC接口以及在Web程序关闭时执行链接断开,内存销毁等操作。如果说没有Spring我们也可以通过构造函数、静态方法以及手动调用的方式实现,但这样的处理方式终究不如把诸如此类的操作都交给 Spring 容器来管理更加合适。 因此你会看到到 spring.xml 中有如下操作:

- 需要满足用户可以在 xml 中配置初始化和销毁的方法,也可以通过实现类的方式处理,比如我们在使用 Spring 时用到的
InitializingBean
,DisposableBean
两个接口。 其实还可以有一种是注解的方式处理初始化操作,不过目前还没有实现到注解的逻辑,后续再完善此类功能。
可能面对像 Spring 这样庞大的框架,对外暴露的接口定义使用或者xml配置,完成的一系列扩展性操作,都让 Spring 框架看上去很神秘。其实对于这样在 Bean 容器初始化过程中额外添加的处理操作,无非就是预先执行了一个定义好的接口方法或者是反射调用类中xml中配置的方法,最终你只要按照接口定义实现,就会有 Spring 容器在处理的过程中进行调用而已。整体设计结构如下图:

- 在 spring.xml 配置中添加
init-method、destroy-method
两个注解,在配置文件加载的过程中,把注解配置一并定义到BeanDefinition
的属性当中。这样在initializeBean
初始化操作的工程中,就可以通过反射的方式来调用配置在 Bean 定义属性当中的方法信息了。另外如果是接口实现的方式,那么直接可以通过 Bean 对象调用对应接口定义的方法即可,((InitializingBean) bean).afterPropertiesSet()
,两种方式达到的效果是一样的。 - 除了在初始化做的操作外,
destroy-method
和DisposableBean
接口的定义,都会在 Bean 对象初始化完成阶段,执行注册销毁方法的信息到DefaultSingletonBeanRegistry
类中的disposableBeans
属性里,这是为了后续统一进行操作。这里还有一段适配器的使用,因为反射调用和接口直接调用,是两种方式。所以需要使用适配器进行包装,下文代码讲解中参考DisposableBeanAdapter
的具体实现 -关于销毁方法需要在虚拟机执行关闭之前进行操作,所以这里需要用到一个注册钩子的操作,如:Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("close!")));
这段代码你可以执行测试,另外你可以使用手动调用ApplicationContext.close
方法关闭容器。
└── 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
│ │ │ ├── BeanFactory.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
│ │ │ └── ClassPathXmlApplicationContext.java
│ │ ├── ApplicationContext.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

- 本次新增 Bean 实例化过程中的初始化方法和销毁方法。
- 因为我们一共实现了两种方式的初始化和销毁方法,xml配置和定义接口,所以这里既有
InitializingBean、DisposableBean
也有需要XmlBeanDefinitionReader
加载spring.xml
配置信息到BeanDefinition
中。 - 另外接口
ConfigurableBeanFactory
定义了destroySingletons
销毁方法,并由AbstractBeanFactory
继承的父类DefaultSingletonBeanRegistry
实现ConfigurableBeanFactory
接口定义的destroySingletons
方法。这种方式的设计可能数程序员是没有用过的,都是用的谁实现接口谁完成实现类,而不是把实现接口的操作又交给继承的父类处理。所以这块还是蛮有意思的,是一种不错的隔离分层服务的设计方式 - 最后就是关于向虚拟机注册钩子,保证在虚拟机关闭之前,执行销毁操作。
Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("close!")));
对之前的代码内容做一些修改
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
/**
* 销毁单例对象
*/
void destroySingletons();
}
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
private Map<String, Object> singletonObjects = new HashMap<>();
private final Map<String, DisposableBean> disposableBeans = new HashMap<>();
@Override
public Object getSingleton(String beanName) {
return singletonObjects.get(beanName);
}
protected void addSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject);
}
public void registerDisposableBean(String beanName, DisposableBean bean) {
disposableBeans.put(beanName, bean);
}
public void destroySingletons() {
Set<String> keySet = this.disposableBeans.keySet();
Object[] disposableBeanNames = keySet.toArray();
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
Object beanName = disposableBeanNames[i];
DisposableBean disposableBean = disposableBeans.remove(beanName);
try {
disposableBean.destroy();
} catch (Exception e) {
throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
}
}
}
}
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
super(registry, resourceLoader);
}
@Override
public void loadBeanDefinitions(Resource resource) throws BeansException {
try {
try (InputStream inputStream = resource.getInputStream()) {
doLoadBeanDefinitions(inputStream);
}
} catch (IOException | ClassNotFoundException e) {
throw new BeansException("IOException parsing XML document from " + resource, e);
}
}
@Override
public void loadBeanDefinitions(Resource... resources) throws BeansException {
for (Resource resource : resources) {
loadBeanDefinitions(resource);
}
}
@Override
public void loadBeanDefinitions(String location) throws BeansException {
ResourceLoader resourceLoader = getResourceLoader();
Resource resource = resourceLoader.getResource(location);
loadBeanDefinitions(resource);
}
@Override
public void loadBeanDefinitions(String... locations) throws BeansException {
for (String location : locations) {
loadBeanDefinitions(location);
}
}
protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {
Document doc = XmlUtil.readXML(inputStream);
Element root = doc.getDocumentElement();
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
// 判断元素
if (!(childNodes.item(i) instanceof Element)) continue;
// 判断对象
if (!"bean".equals(childNodes.item(i).getNodeName())) continue;
// 解析标签
Element bean = (Element) childNodes.item(i);
String id = bean.getAttribute("id");
String name = bean.getAttribute("name");
String className = bean.getAttribute("class");
String initMethod = bean.getAttribute("init-method");
String destroyMethodName = bean.getAttribute("destroy-method");
// 获取 Class,方便获取类中的名称
Class<?> clazz = Class.forName(className);
// 优先级 id > name
String beanName = StrUtil.isNotEmpty(id) ? id : name;
if (StrUtil.isEmpty(beanName)) {
beanName = StrUtil.lowerFirst(clazz.getSimpleName());
}
// 定义Bean
BeanDefinition beanDefinition = new BeanDefinition(clazz);
beanDefinition.setInitMethodName(initMethod);
beanDefinition.setDestroyMethodName(destroyMethodName);
// 读取属性并填充
for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
if (!(bean.getChildNodes().item(j) instanceof Element)) continue;
if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) continue;
// 解析标签:property
Element property = (Element) bean.getChildNodes().item(j);
String attrName = property.getAttribute("name");
String attrValue = property.getAttribute("value");
String attrRef = property.getAttribute("ref");
// 获取属性值:引入对象、值对象
Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
// 创建属性信息
PropertyValue propertyValue = new PropertyValue(attrName, value);
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
if (getRegistry().containsBeanDefinition(beanName)) {
throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
}
// 注册 BeanDefinition
getRegistry().registerBeanDefinition(beanName, beanDefinition);
}
}
}
定义初始化和销毁方法的接口
public interface InitializingBean {
/**
* Bean 处理了属性填充后调用
*
* @throws Exception
*/
void afterPropertiesSet() throws Exception;
}
public interface DisposableBean {
void destroy() throws Exception;
}
-
InitializingBean、DisposableBean
,两个接口方法还是比较常用的,在一些需要结合 Spring 实现的组件中,经常会使用这两个方法来做一些参数的初始化和销毁操作。比如接口暴漏、数据库数据读取、配置文件加载等等。
Bean属性定义新增初始化和销毁
public class BeanDefinition {
private Class beanClass;
private PropertyValues propertyValues;
private String initMethodName;
private String destroyMethodName;
public BeanDefinition(Class beanClass) {
this.beanClass = beanClass;
this.propertyValues = new PropertyValues();
}
public BeanDefinition(Class beanClass, PropertyValues propertyValues) {
this.beanClass = beanClass;
this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues();
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
public PropertyValues getPropertyValues() {
return propertyValues;
}
public void setPropertyValues(PropertyValues propertyValues) {
this.propertyValues = propertyValues;
}
public String getInitMethodName() {
return initMethodName;
}
public void setInitMethodName(String initMethodName) {
this.initMethodName = initMethodName;
}
public String getDestroyMethodName() {
return destroyMethodName;
}
public void setDestroyMethodName(String destroyMethodName) {
this.destroyMethodName = destroyMethodName;
}
}
- 在
BeanDefinition
新增加了两个属性:initMethodName、destroyMethodName
,这两个属性是为了在spring.xml
配置的 Bean 对象中,可以配置init-method="initDataMethod" destroy-method="destroyDataMethod"
操作,最终实现接口的效果是一样的。只不过一个是接口方法的直接调用,另外是一个在配置文件中读取到方法反射调用
执行 Bean 对象的初始化方法
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected 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;
}
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
}
}
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
}
/**
* Bean 属性填充
*/
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
try {
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
// A 依赖 B,获取 B 的实例化
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getBeanName());
}
// 属性填充
BeanUtil.setFieldValue(bean, name, value);
}
} catch (Exception e) {
throw new BeansException("Error setting property values:" + beanName);
}
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
this.instantiationStrategy = instantiationStrategy;
}
private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
// 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(wrappedBean, beanName);
return wrappedBean;
}
private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
// 1. 实现接口 InitializingBean
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 2. 注解配置 init-method {判断是为了避免二次执行初始化}
String initMethodName = beanDefinition.getInitMethodName();
if (StrUtil.isNotEmpty(initMethodName) && !(bean instanceof InitializingBean)) {
Method initMethod = beanDefinition.getBeanClass().getMethod(initMethodName);
if (null == initMethod) {
throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
}
initMethod.invoke(bean);
}
}
@Override
public 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;
}
@Override
public 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;
}
}
- 抽象类
AbstractAutowireCapableBeanFactory
中的createBean
是用来创建 Bean 对象的方法,在这个方法中我们之前已经扩展了BeanFactoryPostProcessor、BeanPostProcessor
操作,这里我们继续完善执行 Bean 对象的初始化方法的处理动作。 - 在方法
invokeInitMethods
中,主要分为两块来执行实现了InitializingBean
接口的操作,处理afterPropertiesSet
方法。另外一个是判断配置信息init-method
是否存在,执行反射调用initMethod.invoke(bean)
。这两种方式都可以在 Bean 对象初始化过程中进行处理加载 Bean 对象中的初始化操作,让使用者可以额外新增加自己想要的动作。
定义销毁方法适配器(接口和配置)
public class DisposableBeanAdapter implements DisposableBean {
private final Object bean;
private final String beanName;
private String destroyMethodName;
public DisposableBeanAdapter(Object bean, String beanName, BeanDefinition beanDefinition) {
this.bean = bean;
this.beanName = beanName;
this.destroyMethodName = beanDefinition.getDestroyMethodName();
}
@Override
public void destroy() throws Exception {
// 1. 实现接口 DisposableBean
if (bean instanceof DisposableBean) {
((DisposableBean) bean).destroy();
}
// 2. 注解配置 destroy-method {判断是为了避免二次执行销毁}
if (StrUtil.isNotEmpty(destroyMethodName) && !(bean instanceof DisposableBean && "destroy".equals(this.destroyMethodName))) {
Method destroyMethod = bean.getClass().getMethod(destroyMethodName);
if (null == destroyMethod) {
throw new BeansException("Couldn't find a destroy method named '" + destroyMethodName + "' on bean with name '" + beanName + "'");
}
destroyMethod.invoke(bean);
}
}
}
- 可能你会想这里怎么有一个适配器的类呢,因为销毁方法有两种甚至多种方式,目前有
实现接口 DisposableBean
、配置信息 destroy-method
,两种方式。而这两种方式的销毁动作是由AbstractApplicationContext
在注册虚拟机钩子后看,虚拟机关闭前执行的操作动作。 - 那么在销毁执行时不太希望还得关注都销毁那些类型的方法,它的使用上更希望是有一个统一的接口进行销毁,所以这里就新增了适配类,做统一处理。
创建Bean时注册销毁方法对象
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected 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;
}
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
}
}
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
}
/**
* Bean 属性填充
*/
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
try {
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
// A 依赖 B,获取 B 的实例化
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getBeanName());
}
// 属性填充
BeanUtil.setFieldValue(bean, name, value);
}
} catch (Exception e) {
throw new BeansException("Error setting property values:" + beanName);
}
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
this.instantiationStrategy = instantiationStrategy;
}
private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
// 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(wrappedBean, beanName);
return wrappedBean;
}
private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
// 1. 实现接口 InitializingBean
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 2. 注解配置 init-method {判断是为了避免二次执行初始化}
String initMethodName = beanDefinition.getInitMethodName();
if (StrUtil.isNotEmpty(initMethodName) && !(bean instanceof InitializingBean)) {
Method initMethod = beanDefinition.getBeanClass().getMethod(initMethodName);
if (null == initMethod) {
throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
}
initMethod.invoke(bean);
}
}
@Override
public 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;
}
@Override
public 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;
}
}
- 在创建 Bean 对象的实例的时候,需要把销毁方法保存起来,方便后续执行销毁动作进行调用。
- 那么这个销毁方法的具体方法信息,会被注册到
DefaultSingletonBeanRegistry
中新增加的Map<String, DisposableBean> disposableBeans
属性中去,因为这个接口的方法最终可以被类AbstractApplicationContext
的close
方法通过getBeanFactory().destroySingletons()
调用。 - 在注册销毁方法的时候,会根据是接口类型和配置类型统一交给
DisposableBeanAdapter
销毁适配器类来做统一处理。实现了某个接口的类可以被instanceof
判断或者强转后调用接口方法
虚拟机关闭钩子注册调用销毁方法
public interface ConfigurableApplicationContext extends ApplicationContext {
/**
* 刷新容器
*
* @throws BeansException
*/
void refresh() throws BeansException;
void registerShutdownHook();
void close();
}
- 首先我们需要在
ConfigurableApplicationContext
接口中定义注册虚拟机钩子的方法registerShutdownHook
和手动执行关闭的方法close
。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException {
// 1. 创建 BeanFactory,并加载 BeanDefinition
refreshBeanFactory();
// 2. 获取 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 3. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
invokeBeanFactoryPostProcessors(beanFactory);
// 4. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
registerBeanPostProcessors(beanFactory);
// 5. 提前实例化单例Bean对象
beanFactory.preInstantiateSingletons();
}
protected abstract void refreshBeanFactory() throws BeansException;
protected abstract ConfigurableListableBeanFactory getBeanFactory();
private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
}
}
private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
beanFactory.addBeanPostProcessor(beanPostProcessor);
}
}
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
return getBeanFactory().getBeansOfType(type);
}
@Override
public String[] getBeanDefinitionNames() {
return getBeanFactory().getBeanDefinitionNames();
}
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return getBeanFactory().getBean(name, args);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(name, requiredType);
}
@Override
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
}
@Override
public void close() {
getBeanFactory().destroySingletons();
}
}
- 这里主要体现了关于注册钩子和关闭的方法实现,上文提到过的
Runtime.getRuntime().addShutdownHook
,可以尝试验证。在一些中间件和监控系统的设计中也可以用得到,比如监测服务器宕机,执行备机启动操作。
测试
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 InitializingBean, DisposableBean {
private String uId;
private String company;
private String location;
private UserDao userDao;
@Override
public void destroy() throws Exception {
System.out.println("执行:UserService.destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行:UserService.afterPropertiesSet");
}
public String queryUserInfo() {
return userDao.queryUserName(uId) + "," + company + "," + location;
}
public String getuId() {
return uId;
}
public void setuId(String uId) {
this.uId = uId;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
- UserDao,修改了之前使用 static 静态块初始化数据的方式,改为提供
initDataMethod
和destroyDataMethod
两个更优雅的操作方式进行处理。 - UserService,以实现接口
InitializingBean, DisposableBean
的两个方法destroy()、afterPropertiesSet()
,处理相应的初始化和销毁方法的动作。afterPropertiesSet
,方法名字很好,在属性设置后执行
配置文件
基础配置,无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>
- 配置文件中主要是新增了,
init-method="initDataMethod" destroy-method="destroyDataMethod"
,这样两个配置。从源码的学习中可以知道,这两个配置是为了加入到BeanDefinition
定义类之后写入到类DefaultListableBeanFactory
中的beanDefinitionMap
属性中去。
单元测试
@Test
public void test_xml() {
// 1.初始化 BeanFactory
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.registerShutdownHook();
// 2. 获取Bean对象调用方法
UserService userService = applicationContext.getBean("userService", UserService.class);
String result = userService.queryUserInfo();
System.out.println("测试结果:" + result);
}
- 测试方法中新增加了一个,注册钩子的动作。
applicationContext.registerShutdownHook();
结果
执行:init-method
执行:UserService.afterPropertiesSet
测试结果:小小小,大大大,小小小
执行:UserService.destroy
执行:destroy-method
Process finished with exit code 0
主要完成了关于初始和销毁在使用接口定义 implements InitializingBean, DisposableBean
和在spring.xml中配置 init-method="initDataMethod" destroy-method="destroyDataMethod"
的两种具体在 AbstractAutowireCapableBeanFactory
完成初始方法和 AbstractApplicationContext
处理销毁动作的具体实现过程。
可以看到目前这个 Spring 框架对 Bean 的操作越来越完善了,可扩展性也不断的增强。你既可以在Bean注册完成实例化前进行 BeanFactoryPostProcessor
操作,也可以在Bean实例化过程中执行前置和后置操作,现在又可以执行Bean的初始化方法和销毁方法。所以一个简单的Bean对象,已经被赋予了各种扩展能力。
Aware接口,实现感知容器对象
目前已实现的 Spring 框架,在 Bean 操作上能提供出的能力,包括:Bean 对象的定义和注册,以及在操作 Bean 对象过程中执行的,BeanFactoryPostProcessor、BeanPostProcessor、InitializingBean、DisposableBean
,以及在 XML 新增的一些配置处理,让我们可以 Bean 对象有更强的操作性。
那么,如果我们想获得 Spring 框架提供的 BeanFactory、ApplicationContext、BeanClassLoader
等这些能力做一些扩展框架的使用时该怎么操作呢。所以我们本节希望在 Spring 框架中提供一种能感知容器操作的接口,如果谁实现了这样的一个接口,就可以获取接口入参中的各类能力。
如果说我希望拿到 Spring 框架中一些提供的资源,那么首先需要考虑以一个什么方式去获取,之后你定义出来的获取方式,在 Spring 框架中该怎么去承接,实现了这两项内容,就可以扩展出你需要的一些属于 Spring 框架本身的能力了。
在关于 Bean 对象实例化阶段我们操作过一些额外定义、属性、初始化和销毁的操作,其实我们如果像获取 Spring 一些如 BeanFactory、ApplicationContext
时,也可以通过此类方式进行实现。那么我们需要定义一个标记性的接口,这个接口不需要有方法,它只起到标记作用就可以,而具体的功能由继承此接口的其他功能性接口定义具体方法,最终这个接口就可以通过 instanceof
进行判断和调用了。整体设计结构如下图:

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

- 关于 Aware 感知的定义和对容器感知的实现。
- Aware 有四个继承的接口,其他这些接口的继承都是为了继承一个标记,有了标记的存在更方便类的操作和具体判断实现。
- 另外由于
ApplicationContext
并不是在AbstractAutowireCapableBeanFactory
中 createBean 方法下的内容,所以需要像容器中注册addBeanPostProcessor
,再由 createBean 统一调用applyBeanPostProcessorsBeforeInitialization
时进行操作。
对上面的代码做一些辅助修改
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
/** ClassLoader to resolve bean class names with, if necessary */
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
/** BeanPostProcessors to apply in createBean */
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, args);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return (T) getBean(name);
}
protected <T> T doGetBean(final String name, final Object[] args) {
Object bean = getSingleton(name);
if (bean != null) {
return (T) bean;
}
BeanDefinition beanDefinition = getBeanDefinition(name);
return (T) createBean(name, beanDefinition, args);
}
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException;
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor){
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
}
/**
* Return the list of BeanPostProcessors that will get applied
* to beans created with this factory.
*/
public List<BeanPostProcessor> getBeanPostProcessors() {
return this.beanPostProcessors;
}
public ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
}
定义标记接口
/**
* 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 {
}
-
在 Spring 中有特别多类似这样的标记接口的设计方式,它们的存在就像是一种标签一样,可以方便统一摘取出属于此类接口的实现类,通常会有
instanceof
一起判断使用。
容器感知类
BeanFactoryAware
/**
* Interface to be implemented by beans that wish to be aware of their
* owning {@link BeanFactory}.
*
* 实现此接口,既能感知到所属的 BeanFactory
*/
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
- Interface to be implemented by beans that wish to be aware of their owning {@link BeanFactory}.
- 实现此接口,既能感知到所属的 BeanFactory
BeanClassLoaderAware
public interface BeanClassLoaderAware extends Aware{
void setBeanClassLoader(ClassLoader classLoader);
}
- Callback that allows a bean to be aware of the bean{@link ClassLoader class loader}; that is, the class loader used by the present bean factory to load bean classes.
- 实现此接口,既能感知到所属的 ClassLoader
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
ApplicationContextAware
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
- Interface to be implemented by any object that wishes to be notifiedof the {@link ApplicationContext} that it runs in.
- 实现此接口,既能感知到所属的 ApplicationContext
包装处理器(ApplicationContextAwareProcessor
)
public class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ApplicationContext applicationContext;
public ApplicationContextAwareProcessor(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ApplicationContextAware){
((ApplicationContextAware) bean).setApplicationContext(applicationContext);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
- 由于
ApplicationContext
的获取并不能直接在创建 Bean 时候就可以拿到,所以需要在refresh
操作时,把ApplicationContext
写入到一个包装的BeanPostProcessor
中去,再由AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization
方法调用。
注册 BeanPostProcessor
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException {
// 1. 创建 BeanFactory,并加载 BeanDefinition
refreshBeanFactory();
// 2. 获取 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 3. 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
beanFactory.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();
}
protected abstract void refreshBeanFactory() throws BeansException;
protected abstract ConfigurableListableBeanFactory getBeanFactory();
private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
}
}
private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
beanFactory.addBeanPostProcessor(beanPostProcessor);
}
}
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
return getBeanFactory().getBeansOfType(type);
}
@Override
public String[] getBeanDefinitionNames() {
return getBeanFactory().getBeanDefinitionNames();
}
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return getBeanFactory().getBean(name, args);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(name, requiredType);
}
@Override
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
}
@Override
public void close() {
getBeanFactory().destroySingletons();
}
}
-
refresh()
方法就是整个 Spring 容器的操作过程,与上一章节对比,本次新增加了关于addBeanPostProcessor
的操作。 - 添加
ApplicationContextAwareProcessor
,让继承自ApplicationContextAware
的 Bean 对象都能感知所属的ApplicationContext
。
感知调用操作
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected 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;
}
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
}
}
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
}
/**
* Bean 属性填充
*/
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
try {
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
// A 依赖 B,获取 B 的实例化
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getBeanName());
}
// 属性填充
BeanUtil.setFieldValue(bean, name, value);
}
} catch (Exception e) {
throw new BeansException("Error setting property values:" + beanName);
}
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
this.instantiationStrategy = instantiationStrategy;
}
private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
// invokeAwareMethods
if (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(wrappedBean, beanName);
return wrappedBean;
}
private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
// 1. 实现接口 InitializingBean
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 2. 注解配置 init-method {判断是为了避免二次执行销毁}
String initMethodName = beanDefinition.getInitMethodName();
if (StrUtil.isNotEmpty(initMethodName)) {
Method initMethod = beanDefinition.getBeanClass().getMethod(initMethodName);
if (null == initMethod) {
throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
}
initMethod.invoke(bean);
}
}
@Override
public 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;
}
@Override
public 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;
}
}
- 这里我们去掉了一些类的内容,只保留关于本次
Aware
感知接口的操作。 - 首先在
initializeBean
中,通过判断bean instanceof Aware
,调用了三个接口方法,BeanFactoryAware.setBeanFactory(this)
、BeanClassLoaderAware.setBeanClassLoader(getBeanClassLoader())
、BeanNameAware.setBeanName(beanName)
,这样就能通知到已经实现了此接口的类。 - 另外我们还向
BeanPostProcessor
中添加了ApplicationContextAwareProcessor
,此时在这个方法中也会被调用到具体的类实现,得到一个ApplicationContex
属性。
测试
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;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void setBeanName(String name) {
System.out.println("Bean Name is:" + name);
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("ClassLoader:" + classLoader);
}
public String queryUserInfo() {
return userDao.queryUserName(uId) + "," + company + "," + location;
}
public String getuId() {
return uId;
}
public void setuId(String uId) {
this.uId = uId;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
}
- UserDao 本次并没有什么改变,还是提供了关于初始化的方法,并在 Spring.xml 中提供 init-method、destroy-method 配置信息。
- UserService 新增加,BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware,四个感知的实现类,并在类中实现相应的接口方法。
配置文件
基础配置,无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>
- 本章节中并没有额外新增加配置信息,与上一章节内容相同。
@Test
public void test_xml() {
// 1.初始化 BeanFactory
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.registerShutdownHook();
// 2. 获取Bean对象调用方法
UserService userService = applicationContext.getBean("userService", UserService.class);
String result = userService.queryUserInfo();
System.out.println("测试结果:" + result);
System.out.println("ApplicationContextAware:"+userService.getApplicationContext());
System.out.println("BeanFactoryAware:"+userService.getBeanFactory());
}
- 测试方法中主要是添加了一写关于新增 Aware 实现的调用,其他不需要调用的也打印了相应的日志信息,可以在测试结果中看到。
测试结果
执行:init-method
ClassLoader:sun.misc.Launcher$AppClassLoader@18b4aac2
Bean Name is:userService
测试结果:小小小,小小小,大大大
ApplicationContextAware:cn.bugstack.springframework.context.support.ClassPathXmlApplicationContext@5e025e70
BeanFactoryAware:cn.bugstack.springframework.beans.factory.support.DefaultListableBeanFactory@1fbc7afb
执行:destroy-method
Process finished with exit code 0
- 从测试结果可以看到,本章节新增加的感知接口对应的具体实现
(BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware)
,已经可以如期输出结果了。
目前关于 Spring 框架的实现中,某些功能点已经越来趋向于完整,尤其是 Bean 对象的生命周期,已经有了很多的体现。整体总结如图 9-3

关于 Aware
的感知接口的四个继承接口 BeanNameAware, BeanClassLoaderAware, ApplicationContextAware, BeanFactoryAware
的实现,又扩展了 Spring
的功能。如果你有做过关于 Spring 中间件的开发那么一定会大量用到这些类。
Bean对象作用域以及FactoryBean的实现
交给 Spring 管理的 Bean 对象,一定就是我们用类创建出来的 Bean 吗?创建出来的 Bean 就永远是单例的吗,没有可能是原型模式吗?
在集合 Spring 框架下,我们使用的 MyBatis 框架中,它的核心作用是可以满足用户不需要实现 Dao 接口类,就可以通过 xml 或者注解配置的方式完成对数据库执行 CRUD 操作,那么在实现这样的 ORM 框架中,是怎么把一个数据库操作的 Bean 对象交给 Spring 管理的呢。
因为我们在使用 Spring、MyBatis 框架的时候都可以知道,并没有手动的去创建任何操作数据库的 Bean 对象,有的仅仅是一个接口定义,而这个接口定义竟然可以被注入到其他需要使用 Dao 的属性中去了,那么这一过程最核心待解决的问题,就是需要完成把复杂且以代理方式动态变化的对象,注册到 Spring 容器中。而为了满足这样的一个扩展组件开发的需求,就需要我们在现有手写的 Spring 框架中,添加这一能力。
关于提供一个能让使用者定义复杂的 Bean 对象,功能点非常不错,意义也非常大,因为这样做了之后 Spring 的生态种子孵化箱就此提供了,谁家的框架都可以在此标准上完成自己服务的接入。
但这样的功能逻辑设计上并不复杂,因为整个 Spring 框架在开发的过程中就已经提供了各项扩展能力的接茬
,你只需要在合适的位置提供一个接茬的处理接口调用和相应的功能逻辑实现即可,像这里的目标实现就是对外提供一个可以二次从 FactoryBean 的 getObject 方法中获取对象的功能即可,这样所有实现此接口的对象类,就可以扩充自己的对象功能了。MyBatis 就是实现了一个 MapperFactoryBean 类,在 getObject 方法中提供 SqlSession 对执行 CRUD 方法的操作 整体设计结构如下图:

- 整个的实现过程包括了两部分,一个解决单例还是原型对象,另外一个处理
FactoryBean
类型对象创建过程中关于获取具体调用对象的getObject
操作。 -
SCOPE_SINGLETON
、SCOPE_PROTOTYPE
,对象类型的创建获取方式,主要区分在于AbstractAutowireCapableBeanFactory#createBean
创建完成对象后是否放入到内存中,如果不放入则每次获取都会重新创建。 -
createBean
执行对象创建、属性填充、依赖加载、前置后置处理、初始化等操作后,就要开始做执行判断整个对象是否是一个FactoryBean
对象,如果是这样的对象,就需要再继续执行获取FactoryBean
具体对象中的getObject
对象了。整个 getBean 过程中都会新增一个单例类型的判断factory.isSingleton()
,用于决定是否使用内存存放对象信息。
└── 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
│ │ │ │ ├── FactoryBeanRegistrySupport.java
│ │ │ │ ├── InstantiationStrategy.java
│ │ │ │ └── SimpleInstantiationStrategy.java
│ │ │ ├── support
│ │ │ │ └── XmlBeanDefinitionReader.java
│ │ │ ├── Aware.java
│ │ │ ├── BeanClassLoaderAware.java
│ │ │ ├── BeanFactory.java
│ │ │ ├── BeanFactoryAware.java
│ │ │ ├── BeanNameAware.java
│ │ │ ├── ConfigurableListableBeanFactory.java
│ │ │ ├── DisposableBean.java
│ │ │ ├── FactoryBean.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

- 添加 Bean 的实例化是单例还是原型模式以及 FactoryBean 的实现。
- 其实整个实现的过程并不复杂,只是在现有的
AbstractAutowireCapableBeanFactory
类以及继承的抽象类AbstractBeanFactory
中进行扩展。 - 不过这次我们把
AbstractBeanFactory
继承的DefaultSingletonBeanRegistry
类,中间加了一层FactoryBeanRegistrySupport
,这个类在 Spring 框架中主要是处理关于FactoryBean
注册的支撑操作。
Bean的作用范围定义和xml解析
public class BeanDefinition {
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
private Class beanClass;
private PropertyValues propertyValues;
private String initMethodName;
private String destroyMethodName;
private String scope = SCOPE_SINGLETON;
private boolean singleton = true;
private boolean prototype = false;
public BeanDefinition(Class beanClass) {
this(beanClass, null);
}
public BeanDefinition(Class beanClass, PropertyValues propertyValues) {
this.beanClass = beanClass;
this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues();
}
public void setScope(String scope) {
this.scope = scope;
this.singleton = SCOPE_SINGLETON.equals(scope);
this.prototype = SCOPE_PROTOTYPE.equals(scope);
}
public boolean isSingleton() {
return singleton;
}
public boolean isPrototype() {
return prototype;
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
public PropertyValues getPropertyValues() {
return propertyValues;
}
public void setPropertyValues(PropertyValues propertyValues) {
this.propertyValues = propertyValues;
}
public String getInitMethodName() {
return initMethodName;
}
public void setInitMethodName(String initMethodName) {
this.initMethodName = initMethodName;
}
public String getDestroyMethodName() {
return destroyMethodName;
}
public void setDestroyMethodName(String destroyMethodName) {
this.destroyMethodName = destroyMethodName;
}
}
-
singleton、prototype
,是本次在BeanDefinition
类中新增加的两个属性信息,用于把从 spring.xml 中解析到的 Bean 对象作用范围填充到属性中。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
super(registry, resourceLoader);
}
@Override
public void loadBeanDefinitions(Resource resource) throws BeansException {
try {
try (InputStream inputStream = resource.getInputStream()) {
doLoadBeanDefinitions(inputStream);
}
} catch (IOException | ClassNotFoundException e) {
throw new BeansException("IOException parsing XML document from " + resource, e);
}
}
@Override
public void loadBeanDefinitions(Resource... resources) throws BeansException {
for (Resource resource : resources) {
loadBeanDefinitions(resource);
}
}
@Override
public void loadBeanDefinitions(String location) throws BeansException {
ResourceLoader resourceLoader = getResourceLoader();
Resource resource = resourceLoader.getResource(location);
loadBeanDefinitions(resource);
}
@Override
public void loadBeanDefinitions(String... locations) throws BeansException {
for (String location : locations) {
loadBeanDefinitions(location);
}
}
protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {
Document doc = XmlUtil.readXML(inputStream);
Element root = doc.getDocumentElement();
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
// 判断元素
if (!(childNodes.item(i) instanceof Element)) continue;
// 判断对象
if (!"bean".equals(childNodes.item(i).getNodeName())) continue;
// 解析标签
Element bean = (Element) childNodes.item(i);
String id = bean.getAttribute("id");
String name = bean.getAttribute("name");
String className = bean.getAttribute("class");
String initMethod = bean.getAttribute("init-method");
String destroyMethodName = bean.getAttribute("destroy-method");
String beanScope = bean.getAttribute("scope");
// 获取 Class,方便获取类中的名称
Class<?> clazz = Class.forName(className);
// 优先级 id > name
String beanName = StrUtil.isNotEmpty(id) ? id : name;
if (StrUtil.isEmpty(beanName)) {
beanName = StrUtil.lowerFirst(clazz.getSimpleName());
}
// 定义Bean
BeanDefinition beanDefinition = new BeanDefinition(clazz);
beanDefinition.setInitMethodName(initMethod);
beanDefinition.setDestroyMethodName(destroyMethodName);
if (StrUtil.isNotEmpty(beanScope)) {
beanDefinition.setScope(beanScope);
}
// 读取属性并填充
for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
if (!(bean.getChildNodes().item(j) instanceof Element)) continue;
if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) continue;
// 解析标签:property
Element property = (Element) bean.getChildNodes().item(j);
String attrName = property.getAttribute("name");
String attrValue = property.getAttribute("value");
String attrRef = property.getAttribute("ref");
// 获取属性值:引入对象、值对象
Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
// 创建属性信息
PropertyValue propertyValue = new PropertyValue(attrName, value);
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
if (getRegistry().containsBeanDefinition(beanName)) {
throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
}
// 注册 BeanDefinition
getRegistry().registerBeanDefinition(beanName, beanDefinition);
}
}
}
- 在解析 XML 处理类
XmlBeanDefinitionReader
中,新增加了关于 Bean 对象配置中scope
的解析,并把这个属性信息填充到 Bean 定义中。beanDefinition.setScope(beanScope)
创建和修改对象时候判断单例和原型模式
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
@Override
protected 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);
// 判断 SCOPE_SINGLETON、SCOPE_PROTOTYPE
if (beanDefinition.isSingleton()) {
addSingleton(beanName, bean);
}
return bean;
}
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
// 非 Singleton 类型的 Bean 不执行销毁方法
if (!beanDefinition.isSingleton()) return;
if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
}
}
protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
Constructor constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
}
/**
* Bean 属性填充
*/
protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
try {
PropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
// A 依赖 B,获取 B 的实例化
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getBeanName());
}
// 属性填充
BeanUtil.setFieldValue(bean, name, value);
}
} catch (Exception e) {
throw new BeansException("Error setting property values:" + beanName);
}
}
public InstantiationStrategy getInstantiationStrategy() {
return instantiationStrategy;
}
public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
this.instantiationStrategy = instantiationStrategy;
}
private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
// invokeAwareMethods
if (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(wrappedBean, beanName);
return wrappedBean;
}
private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
// 1. 实现接口 InitializingBean
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 2. 注解配置 init-method {判断是为了避免二次执行销毁}
String initMethodName = beanDefinition.getInitMethodName();
if (StrUtil.isNotEmpty(initMethodName)) {
Method initMethod = beanDefinition.getBeanClass().getMethod(initMethodName);
if (null == initMethod) {
throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
}
initMethod.invoke(bean);
}
}
@Override
public 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;
}
@Override
public 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;
}
}
- 单例模式和原型模式的区别就在于是否存放到内存中,如果是原型模式那么就不会存放到内存中,每次获取都重新创建对象,另外非 Singleton 类型的 Bean 不需要执行销毁方法。
- 所以这里的代码会有两处修改,一处是 createBean 中判断是否添加到
addSingleton(beanName, bean);
,另外一处是registerDisposableBeanIfNecessary
销毁注册中的判断if (!beanDefinition.isSingleton()) return;
。
定义 FactoryBean
接口
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
-
FactoryBean
中需要提供3个方法,获取对象、对象类型,以及是否是单例对象,如果是单例对象依然会被放到内存中。
实现一个 FactoryBean
注册服务
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
/**
* Cache of singleton objects created by FactoryBeans: FactoryBean name --> object
*/
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<String, Object>();
protected Object getCachedObjectForFactoryBean(String beanName) {
Object object = this.factoryBeanObjectCache.get(beanName);
return (object != NULL_OBJECT ? object : null);
}
protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName) {
if (factory.isSingleton()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
return (object != NULL_OBJECT ? object : null);
} else {
return doGetObjectFromFactoryBean(factory, beanName);
}
}
private Object doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName){
try {
return factory.getObject();
} catch (Exception e) {
throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", e);
}
}
}
-
FactoryBeanRegistrySupport
类主要处理的就是关于FactoryBean
此类对象的注册操作,之所以放到这样一个单独的类里,就是希望做到不同领域模块下只负责各自需要完成的功能,避免因为扩展导致类膨胀到难以维护。 - 同样这里也定义了缓存操作
factoryBeanObjectCache
,用于存放单例类型的对象,避免重复创建。在日常使用用,基本也都是创建的单例对象 -
doGetObjectFromFactoryBean
是具体的获取FactoryBean#getObject()
方法,因为既有缓存的处理也有对象的获取,所以额外提供了getObjectFromFactoryBean
进行逻辑包装,这部分的操作方式是不和你日常做的业务逻辑开发非常相似。从Redis取数据,如果为空就从数据库获取并写入Redis
扩展 AbstractBeanFactory
创建对象逻辑
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
/**
* ClassLoader to resolve bean class names with, if necessary
*/
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
/**
* BeanPostProcessors to apply in createBean
*/
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, args);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return (T) getBean(name);
}
protected <T> T doGetBean(final String name, final Object[] args) {
Object sharedInstance = getSingleton(name);
if (sharedInstance != null) {
// 如果是 FactoryBean,则需要调用 FactoryBean#getObject
return (T) getObjectForBeanInstance(sharedInstance, name);
}
BeanDefinition beanDefinition = getBeanDefinition(name);
Object bean = createBean(name, beanDefinition, args);
return (T) getObjectForBeanInstance(bean, name);
}
private Object getObjectForBeanInstance(Object beanInstance, String beanName) {
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = getCachedObjectForFactoryBean(beanName);
if (object == null) {
FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
object = getObjectFromFactoryBean(factoryBean, beanName);
}
return object;
}
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException;
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
}
/**
* Return the list of BeanPostProcessors that will get applied
* to beans created with this factory.
*/
public List<BeanPostProcessor> getBeanPostProcessors() {
return this.beanPostProcessors;
}
public ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
}
- 首先这里把
AbstractBeanFactory
原来继承的DefaultSingletonBeanRegistry
,修改为继承FactoryBeanRegistrySupport
。因为需要扩展出创建FactoryBean
对象的能力,所以这就想一个链条服务上,截出一个段来处理额外的服务,并把链条再链接上。 - 此处新增加的功能主要是在
doGetBean
方法中,添加了调用(T) getObjectForBeanInstance(sharedInstance, name)
对获取 FactoryBean 的操作。 - 在
getObjectForBeanInstance
方法中做具体的instanceof
判断,另外还会从FactoryBean
的缓存中获取对象,如果不存在则调用FactoryBeanRegistrySupport#getObjectFromFactoryBean
,执行具体的操作。
测试
public interface IUserDao {
String queryUserName(String uId);
}
- 这个节我们删掉 UserDao,定义一个 IUserDao 接口,之所这样做是为了通过 FactoryBean 做一个自定义对象的代理操作。
public class UserService {
private String uId;
private String company;
private String location;
private IUserDao userDao;
public String queryUserInfo() {
return userDao.queryUserName(uId) + "," + company + "," + location;
}
public String getuId() {
return uId;
}
public void setuId(String uId) {
this.uId = uId;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public IUserDao getUserDao() {
return userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
}
- 在 UserService 新修改了一个原有 UserDao 属性为 IUserDao,后面我们会给这个属性注入代理对象。
定义 FactoryBean 对象
public class ProxyBeanFactory implements FactoryBean<IUserDao> {
@Override
public IUserDao getObject() throws Exception {
InvocationHandler handler = (proxy, method, args) -> {
// 添加排除方法
if ("toString".equals(method.getName())) return this.toString();
Map<String, String> hashMap = new HashMap<>();
hashMap.put("10001", "小小小");
hashMap.put("10002", "大大大");
hashMap.put("10003", "啊啊啊");
return "你被代理了 " + method.getName() + ":" + hashMap.get(args[0].toString());
};
return (IUserDao) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IUserDao.class}, handler);
}
@Override
public Class<?> getObjectType() {
return IUserDao.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
- 这是一个实现接口
FactoryBean
的代理类ProxyBeanFactory
名称,主要是模拟了UserDao
的原有功能,类似于 MyBatis 框架中的代理操作。 - getObject() 中提供的就是一个
InvocationHandler
的代理对象,当有方法调用的时候,则执行代理对象的功能。
配置文件
spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="userService" class="cn.bugstack.springframework.test.bean.UserService" scope="prototype">
<property name="uId" value="10001"/>
<property name="company" value="腾讯"/>
<property name="location" value="深圳"/>
<property name="userDao" ref="proxyUserDao"/>
</bean>
<bean id="proxyUserDao" class="cn.bugstack.springframework.test.bean.ProxyBeanFactory"/>
</beans>
- 在配置文件中,我们把 proxyUserDao 这个代理对象,注入到 userService 的 userDao 中。与上节相比,去掉了 UserDao 实现类,转而用代理类替换
单元测试(单例&原型)
@Test
public void test_prototype() {
// 1.初始化 BeanFactory
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.registerShutdownHook();
// 2. 获取Bean对象调用方法
UserService userService01 = applicationContext.getBean("userService", UserService.class);
UserService userService02 = applicationContext.getBean("userService", UserService.class);
// 3. 配置 scope="prototype/singleton"
System.out.println(userService01);
System.out.println(userService02);
// 4. 打印十六进制哈希
System.out.println(userService01 + " 十六进制哈希:" + Integer.toHexString(userService01.hashCode()));
System.out.println(ClassLayout.parseInstance(userService01).toPrintable());
}
- 在 spring.xml 配置文件中,设置了 scope=”prototype” 这样就每次获取到的对象都应该是一个新的对象。
- 这里判断对象是否为一个会看到打印的类对象的哈希值,所以我们把十六进制哈希打印出来。
结果
/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/bin/java -ea -Didea.test.cyclic.buffer.size=1048576 -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=57942:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar:/Applications/IntelliJ IDEA.app/Contents/plugins/junit/lib/junit5-rt.jar:/Applications/IntelliJ IDEA.app/Contents/plugins/junit/lib/junit-rt.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext/legacy8ujsse.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext/openjsse.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/lib/tools.jar:/Users/xujiahui/Me/bugstack/small-spring/small-spring-step-09/target/test-classes:/Users/xujiahui/Me/bugstack/small-spring/small-spring-step-09/target/classes:/Users/xujiahui/Me/maven/jar/cglib/cglib/3.3.0/cglib-3.3.0.jar:/Users/xujiahui/Me/maven/jar/org/ow2/asm/asm/7.1/asm-7.1.jar:/Users/xujiahui/Me/maven/jar/cn/hutool/hutool-all/5.5.0/hutool-all-5.5.0.jar:/Users/xujiahui/Me/maven/jar/org/openjdk/jol/jol-cli/0.14/jol-cli-0.14.jar:/Users/xujiahui/Me/maven/jar/org/openjdk/jol/jol-core/0.14/jol-core-0.14.jar:/Users/xujiahui/Me/maven/jar/net/sf/jopt-simple/jopt-simple/4.6/jopt-simple-4.6.jar:/Users/xujiahui/Me/maven/jar/junit/junit/4.7/junit-4.7.jar com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 cn.bugstack.springframework.test.ApiTest,test_prototype
cn.bugstack.springframework.test.bean.UserService$$EnhancerByCGLIB$$4cabb984@7d417077
cn.bugstack.springframework.test.bean.UserService$$EnhancerByCGLIB$$4cabb984@7dc36524
cn.bugstack.springframework.test.bean.UserService$$EnhancerByCGLIB$$4cabb984@7d417077 十六进制哈希:7d417077
# WARNING: Unable to attach Serviceability Agent. Unable to attach even with module exceptions: [org.openjdk.jol.vm.sa.SASupportException: Sense failed., org.openjdk.jol.vm.sa.SASupportException: Sense failed., org.openjdk.jol.vm.sa.SASupportException: Sense failed.]
cn.bugstack.springframework.test.bean.UserService$$EnhancerByCGLIB$$4cabb984 object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 77 70 41 (00000001 01110111 01110000 01000001) (1097889537)
4 4 (object header) 7d 00 00 00 (01111101 00000000 00000000 00000000) (125)
8 4 (object header) f0 0e 0f 00 (11110000 00001110 00001111 00000000) (986864)
12 4 java.lang.String UserService.uId (object)
16 4 java.lang.String UserService.company (object)
20 4 java.lang.String UserService.location (object)
24 4 cn.bugstack.springframework.test.bean.IUserDao UserService.userDao (object)
28 1 boolean UserService$$EnhancerByCGLIB$$4cabb984.CGLIB$BOUND true
29 3 (alignment/padding gap)
32 4 net.sf.cglib.proxy.NoOp UserService$$EnhancerByCGLIB$$4cabb984.CGLIB$CALLBACK_0 (object)
36 4 (loss due to the next object alignment)
Instance size: 40 bytes
Space losses: 3 bytes internal + 4 bytes external = 7 bytes total
Process finished with exit code 0

- 对象后面的这一小段字符串就是16进制哈希值,在对象头哈希值存放的结果上看,也有对应的数值。只不过这个结果是倒过来的。
- 这两个对象的结尾16进制哈希值并不一样,所以我们的原型模式是生效的。
单元测试(代理对象)
@Test
public void test_factory_bean() {
// 1.初始化 BeanFactory
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.registerShutdownHook();
// 2. 调用代理方法
UserService userService = applicationContext.getBean("userService", UserService.class);
System.out.println("测试结果:" + userService.queryUserInfo());
}
- 关于 FactoryBean 的调用并没有太多不一样,因为所有的不同都已经被 spring.xml 配置进去了。当然你可以直接调用 spring.xml 配置的对象
cn.bugstack.springframework.test.bean.ProxyBeanFactory
结果
测试结果:你被代理了 queryUserName:小小小,腾讯,深圳
Process finished with exit code 0
- 从测试结果来看,我们的代理类 ProxyBeanFactory 已经完美替换掉了 UserDao 的功能。
在 Spring 框架整个开发的过程中,前期的各个功能接口类扩展的像膨胀了似的,但到后期在完善功能时,就没有那么难了,反而深入理解后会觉得功能的补充,都比较简单。只需要再所遇领域范围内进行扩展相应的服务实现即可。
当你仔细阅读完关于 FactoryBean 的实现以及测试过程的使用,以后再需要使用 FactoryBean 开发相应的组件时候,一定会非常清楚它是如何创建自己的复杂 Bean 对象以及在什么时候初始化和调用的。遇到问题也可以快速的排查、定位和解决。
容器事件和事件监听器
在 Spring 中有一个 Event 事件功能,它可以提供事件的定义、发布以及监听事件来完成一些自定义的动作。比如你可以定义一个新用户注册的事件,当有用户执行注册完成后,在事件监听中给用户发送一些优惠券和短信提醒,这样的操作就可以把属于基本功能的注册和对应的策略服务分开,降低系统的耦合。以后在扩展注册服务,比如需要添加风控策略、添加实名认证、判断用户属性等都不会影响到依赖注册成功后执行的动作。
那么在本章节我们需要以观察者模式的方式,设计和实现 Spring Event 的容器事件和事件监听器功能,最终可以让我们在现有实现的 Spring 框架中可以定义、监听和发布自己的事件信息。
其实事件的设计本身就是一种观察者模式的实现,它所要解决的就是一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
在功能实现上我们需要定义出事件类、事件监听、事件发布,而这些类的功能需要结合到 Spring 的 AbstractApplicationContext#refresh()
,以便于处理事件初始化和注册事件监听器的操作。整体设计结构如下图:

- 在整个功能实现过程中,仍然需要在面向用户的应用上下文
AbstractApplicationContext
中添加相关事件内容,包括:初始化事件发布者、注册事件监听器、发布容器刷新完成事件。 -
使用观察者模式定义事件类、监听类、发布类,同时还需要完成一个广播器的功能,接收到事件推送时进行分析处理符合监听事件接受者感兴趣的事件,也就是使用
isAssignableFrom
进行判断。 -
isAssignableFrom
和instanceof
相似,不过isAssignableFrom
是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,默认所有的类的终极父类都是Object。如果A.isAssignableFrom(B)结果是true,证明B可以转换成为A,也就是A可以由B转换而来。
└── 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
│ │ │ │ ├── FactoryBeanRegistrySupport.java
│ │ │ │ ├── InstantiationStrategy.java
│ │ │ │ └── SimpleInstantiationStrategy.java
│ │ │ ├── support
│ │ │ │ └── XmlBeanDefinitionReader.java
│ │ │ ├── Aware.java
│ │ │ ├── BeanClassLoaderAware.java
│ │ │ ├── BeanFactory.java
│ │ │ ├── BeanFactoryAware.java
│ │ │ ├── BeanNameAware.java
│ │ │ ├── ConfigurableListableBeanFactory.java
│ │ │ ├── DisposableBean.java
│ │ │ ├── FactoryBean.java
│ │ │ ├── HierarchicalBeanFactory.java
│ │ │ ├── InitializingBean.java
│ │ │ └── ListableBeanFactory.java
│ │ ├── BeansException.java
│ │ ├── PropertyValue.java
│ │ └── PropertyValues.java
│ ├── context
│ │ ├── event
│ │ │ ├── AbstractApplicationEventMulticaster.java
│ │ │ ├── ApplicationContextEvent.java
│ │ │ ├── ApplicationEventMulticaster.java
│ │ │ ├── ContextClosedEvent.java
│ │ │ ├── ContextRefreshedEvent.java
│ │ │ └── SimpleApplicationEventMulticaster.java
│ │ ├── support
│ │ │ ├── AbstractApplicationContext.java
│ │ │ ├── AbstractRefreshableApplicationContext.java
│ │ │ ├── AbstractXmlApplicationContext.java
│ │ │ ├── ApplicationContextAwareProcessor.java
│ │ │ └── ClassPathXmlApplicationContext.java
│ │ ├── ApplicationContext.java
│ │ ├── ApplicationContextAware.java
│ │ ├── ApplicationEvent.java
│ │ ├── ApplicationEventPublisher.java
│ │ ├── ApplicationListener.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
├── event
│ ├── ContextClosedEventListener.java
│ ├── ContextRefreshedEventListener.java
│ ├── CustomEvent.java
│ └── CustomEventListener.java
└── ApiTest.java


-
围绕实现 event 事件定义、发布、监听功能实现和把事件的相关内容使用
AbstractApplicationContext#refresh
进行注册和处理操作。 - 在实现的过程中主要以扩展 spring context 包为主,事件的实现也是在这个包下进行扩展的,当然也可以看出来目前所有的实现内容,仍然是以IOC为主。
-
ApplicationContext
容器继承事件发布功能接口ApplicationEventPublisher
,并在实现类中提供事件监听功能。 -
ApplicationEventMulticaster
接口是注册监听器和发布事件的广播器,提供添加、移除和发布事件方法。 - 最后是发布容器关闭事件,这个仍然需要扩展到
AbstractApplicationContext#close
方法中,由注册到虚拟机的钩子实现。
对之前的代码做一些辅助修改
public interface ApplicationContext extends ListableBeanFactory, HierarchicalBeanFactory, ResourceLoader, ApplicationEventPublisher {
}
/**
* 单例注册表
*/
public interface SingletonBeanRegistry {
Object getSingleton(String beanName);
void registerSingleton(String beanName, Object singletonObject);
}
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
/**
* Internal marker for a null singleton object:
* used as marker value for concurrent Maps (which don't support null values).
*/
protected static final Object NULL_OBJECT = new Object();
private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
private final Map<String, DisposableBean> disposableBeans = new LinkedHashMap<>();
@Override
public Object getSingleton(String beanName) {
return singletonObjects.get(beanName);
}
public void registerSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject);
}
public void registerDisposableBean(String beanName, DisposableBean bean) {
disposableBeans.put(beanName, bean);
}
public void destroySingletons() {
Set<String> keySet = this.disposableBeans.keySet();
Object[] disposableBeanNames = keySet.toArray();
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
Object beanName = disposableBeanNames[i];
DisposableBean disposableBean = disposableBeans.remove(beanName);
try {
disposableBean.destroy();
} catch (Exception e) {
throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
}
}
}
}
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
定义和实现事件
public abstract class ApplicationEvent extends EventObject {
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public ApplicationEvent(Object source) {
super(source);
}
}
- 以继承
java.util.EventObject
定义出具备事件功能的抽象类ApplicationEvent
,后续所有事件的类都需要继承这个类。
public class ApplicationContextEvent extends ApplicationEvent {
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public ApplicationContextEvent(Object source) {
super(source);
}
/**
* Get the <code>ApplicationContext</code> that the event was raised for.
*/
public final ApplicationContext getApplicationContext() {
return (ApplicationContext) getSource();
}
}
public class ContextClosedEvent extends ApplicationContextEvent{
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public ContextClosedEvent(Object source) {
super(source);
}
}
public class ContextRefreshedEvent extends ApplicationContextEvent{
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public ContextRefreshedEvent(Object source) {
super(source);
}
}
-
ApplicationContextEvent
是定义事件的抽象类,所有的事件包括关闭、刷新,以及用户自己实现的事件,都需要继承这个类。 -
ContextClosedEvent、ContextRefreshedEvent
,分别是 Spring 框架自己实现的两个事件类,可以用于监听刷新和关闭动作。
事件广播器
public interface ApplicationEventMulticaster {
/**
* Add a listener to be notified of all events.
* @param listener the listener to add
*/
void addApplicationListener(ApplicationListener<?> listener);
/**
* Remove a listener from the notification list.
* @param listener the listener to remove
*/
void removeApplicationListener(ApplicationListener<?> listener);
/**
* Multicast the given application event to appropriate listeners.
* @param event the event to multicast
*/
void multicastEvent(ApplicationEvent event);
}
- 在事件广播器中定义了添加监听和删除监听的方法以及一个广播事件的方法
multicastEvent
最终推送时间消息也会经过这个接口方法来处理谁该接收事件。
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {
public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet<>();
private BeanFactory beanFactory;
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
}
@Override
public void removeApplicationListener(ApplicationListener<?> listener) {
applicationListeners.remove(listener);
}
@Override
public final void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
/**
* Return a Collection of ApplicationListeners matching the given
* event type. Non-matching listeners get excluded early.
* @param event the event to be propagated. Allows for excluding
* non-matching listeners early, based on cached matching information.
* @return a Collection of ApplicationListeners
* @see cn.bugstack.springframework.context.ApplicationListener
*/
protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
for (ApplicationListener<ApplicationEvent> listener : applicationListeners) {
if (supportsEvent(listener, event)) allListeners.add(listener);
}
return allListeners;
}
/**
* 监听器是否对该事件感兴趣
*/
protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();
// 按照 CglibSubclassingInstantiationStrategy、SimpleInstantiationStrategy 不同的实例化类型,需要判断后获取目标 class
Class<?> targetClass = ClassUtils.isCglibProxyClass(listenerClass) ? listenerClass.getSuperclass() : listenerClass;
Type genericInterface = targetClass.getGenericInterfaces()[0];
Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
String className = actualTypeArgument.getTypeName();
Class<?> eventClassName;
try {
eventClassName = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new BeansException("wrong event class name: " + className);
}
// 判定此 eventClassName 对象所表示的类或接口与指定的 event.getClass() 参数所表示的类或接口是否相同,或是否是其超类或超接口。
// isAssignableFrom是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,默认所有的类的终极父类都是Object。如果A.isAssignableFrom(B)结果是true,证明B可以转换成为A,也就是A可以由B转换而来。
return eventClassName.isAssignableFrom(event.getClass());
}
}
-
AbstractApplicationEventMulticaster
是对事件广播器的公用方法提取,在这个类中可以实现一些基本功能,避免所有直接实现接口放还需要处理细节。 - 除了像
addApplicationListener、removeApplicationListener
,这样的通用方法,这里这个类中主要是对getApplicationListeners
和supportsEvent
的处理。 -
getApplicationListeners
方法主要是摘取符合广播事件中的监听处理器,具体过滤动作在supportsEvent
方法中。 - 在
supportsEvent
方法中,主要包括对Cglib、Simple
不同实例化需要获取目标Class,Cglib代理类需要获取父类的Class,普通实例化的不需要。接下来就是通过提取接口和对应的ParameterizedType
和eventClassName
,方便最后确认是否为子类和父类的关系,以此证明此事件归这个符合的类处理。可以参考代码中的注释
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}
@SuppressWarnings("unchecked")
@Override
public void multicastEvent(final ApplicationEvent event) {
for (final ApplicationListener listener : getApplicationListeners(event)) {
listener.onApplicationEvent(event);
}
}
}
事件发布者的定义和实现
public interface ApplicationEventPublisher {
/**
* Notify all listeners registered with this application of an application
* event. Events may be framework events (such as RequestHandledEvent)
* or application-specific events.
* @param event the event to publish
*/
void publishEvent(ApplicationEvent event);
}
-
ApplicationEventPublisher
是整个一个事件的发布接口,所有的事件都需要从这个接口发布出去。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
private ApplicationEventMulticaster applicationEventMulticaster;
@Override
public void refresh() throws BeansException {
// 1. 创建 BeanFactory,并加载 BeanDefinition
refreshBeanFactory();
// 2. 获取 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 3. 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 4. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor (Invoke factory processors registered as beans in the context.)
invokeBeanFactoryPostProcessors(beanFactory);
// 5. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
registerBeanPostProcessors(beanFactory);
// 6. 初始化事件发布者
initApplicationEventMulticaster();
// 7. 注册事件监听器
registerListeners();
// 8. 提前实例化单例Bean对象
beanFactory.preInstantiateSingletons();
// 9. 发布容器刷新完成事件
finishRefresh();
}
protected abstract void refreshBeanFactory() throws BeansException;
protected abstract ConfigurableListableBeanFactory getBeanFactory();
private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
}
}
private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
beanFactory.addBeanPostProcessor(beanPostProcessor);
}
}
private void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
}
private void registerListeners() {
Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
for (ApplicationListener listener : applicationListeners) {
applicationEventMulticaster.addApplicationListener(listener);
}
}
private void finishRefresh() {
publishEvent(new ContextRefreshedEvent(this));
}
@Override
public void publishEvent(ApplicationEvent event) {
applicationEventMulticaster.multicastEvent(event);
}
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
return getBeanFactory().getBeansOfType(type);
}
@Override
public String[] getBeanDefinitionNames() {
return getBeanFactory().getBeanDefinitionNames();
}
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return getBeanFactory().getBean(name, args);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(name, requiredType);
}
@Override
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
}
@Override
public void close() {
// 发布容器关闭事件
publishEvent(new ContextClosedEvent(this));
// 执行销毁单例bean的销毁方法
getBeanFactory().destroySingletons();
}
}
- 在抽象应用上下文
AbstractApplicationContext#refresh
中,主要新增了初始化事件发布者
、注册事件监听器
、发布容器刷新完成事件
,三个方法用于处理事件操作。 - 初始化事件发布者(
initApplicationEventMulticaster
),主要用于实例化一个SimpleApplicationEventMulticaster
,这是一个事件广播器。 - 注册事件监听器(
registerListeners
),通过getBeansOfType
方法获取到所有从 spring.xml 中加载到的事件配置 Bean 对象。 - 发布容器刷新完成事件(
finishRefresh
),发布了第一个服务器启动完成后的事件,这个事件通过publishEvent
发布出去,其实也就是调用了applicationEventMulticaster.multicastEvent(event);
方法。 - 最后是一个 close 方法中,新增加了发布一个容器关闭事件。
publishEvent(new ContextClosedEvent(this));
测试
创建一个事件和监听器
public class CustomEvent extends ApplicationContextEvent {
private Long id;
private String message;
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public CustomEvent(Object source, Long id, String message) {
super(source);
this.id = id;
this.message = message;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
- 创建一个自定义事件,在事件类的构造函数中可以添加自己的想要的入参信息。这个事件类最终会被完成的拿到监听里,所以你添加的属性都会被获得到。
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("收到:" + event.getSource() + "消息;时间:" + new Date());
System.out.println("消息:" + event.getId() + ":" + event.getMessage());
}
}
- 这个是一个用于监听
CustomEvent
事件的监听器,这里你可以处理自己想要的操作,比如一些用户注册后发送优惠券和短信通知等。 - 另外是关于
ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent>
、ContextClosedEventListener implements ApplicationListener<ContextClosedEvent>
监听器,可以参考下源码。
配置文件
spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean class="cn.bugstack.springframework.test.event.ContextRefreshedEventListener"/>
<bean class="cn.bugstack.springframework.test.event.CustomEventListener"/>
<bean class="cn.bugstack.springframework.test.event.ContextClosedEventListener"/>
</beans>
- 在 spring.xml 中配置了三个事件监听器,监听刷新、监控自定义事件、监听关闭事件。
单元测试
public class ApiTest {
@Test
public void test_event() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.publishEvent(new CustomEvent(applicationContext, 1019129009086763L, "成功了!"));
applicationContext.registerShutdownHook();
}
}
- 通过使用
applicationContext
新增加的发布事件接口方法,发布一个自定义事件CustomEvent
,并透传了相应的参数信息。
结果
刷新事件:cn.bugstack.springframework.test.event.ContextRefreshedEventListener$$EnhancerByCGLIB$$440a36f5
收到:cn.bugstack.springframework.context.support.ClassPathXmlApplicationContext@4ec6a292消息;时间:Tue Jun 14 14:42:58 CST 2022
消息:1019129009086763:成功了!
关闭事件:cn.bugstack.springframework.test.event.ContextClosedEventListener$$EnhancerByCGLIB$$f4d4b18d
Process finished with exit code 0
- 从测试结果可以看到,我们自己定义的事件和监听,以及监听系统的事件信息,都可以在控制台完整的输出出来了。你也可以尝试增加一些其他事件行为。
整个手写 Spring 框架的学习过程中,可以逐步看到很多设计模式的使用,比如:简单工厂BeanFactory、工厂方法FactoryBean、策略模式访问资源,现在又实现了一个观察者模式的具体使用。所以学习 Spring 的过程中,要更加注意关于设计模式的运用。
本节关于观察者模式的实现过程,主要包括了事件的定义、事件的监听和发布事件,发布完成后根据匹配策略,监听器就会收到属于自己的事件内容,并做相应的处理动作,这样的观察者模式其实日常我们也经常使用,不过在结合 Spring 以后,除了设计模式的学习,还可以学到如何把相应观察者的实现和应用上下文结合。
Bean的生命周期
