初始化和销毁方法

当我们的类创建的 Bean 对象,交给 Spring 容器管理以后,这个类对象就可以被赋予更多的使用能力

可以在 Bean 初始化过程,执行一些操作。比如帮我们做一些数据的加载执行,链接注册中心暴漏RPC接口以及在Web程序关闭时执行链接断开,内存销毁等操作。如果说没有Spring我们也可以通过构造函数、静态方法以及手动调用的方式实现,但这样的处理方式终究不如把诸如此类的操作都交给 Spring 容器来管理更加合适。

  • 需要满足用户可以在 xml 中配置初始化和销毁的方法,也可以通过实现类的方式处理,比如我们在使用 Spring 时用到的 InitializingBean, DisposableBean 两个接口。 -其实还可以有一种是注解的方式处理初始化操作,不过目前还没有实现到注解的逻辑,后续再完善此类功能

img

  • 在 spring.xml 配置中添加 init-method、destroy-method 两个注解,在配置文件加载的过程中,把注解配置一并定义到 BeanDefinition 的属性当中。这样在 initializeBean 初始化操作的工程中,就可以通过反射的方式来调用配置在 Bean 定义属性当中的方法信息了。另外如果是接口实现的方式,那么直接可以通过 Bean 对象调用对应接口定义的方法即可,((InitializingBean) bean).afterPropertiesSet(),两种方式达到的效果是一样的。
  • 除了在初始化做的操作外,destroy-methodDisposableBean 接口的定义,都会在 Bean 对象初始化完成阶段,执行注册销毁方法的信息到 DefaultSingletonBeanRegistry 类中的 disposableBeans 属性里,这是为了后续统一进行操作。这里还有一段适配器的使用,因为反射调用和接口直接调用,是两种方式。所以需要使用适配器进行包装

参考 DisposableBeanAdapter 的具体实现 -关于销毁方法需要在虚拟机执行关闭之前进行操作,所以这里需要用到一个注册钩子的操作,如:Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("close!")));

图 8-4

  • 以上整个类图结构描述出来的就是本次新增 Bean 实例化过程中的初始化方法和销毁方法。
  • 因为我们一共实现了两种方式的初始化和销毁方法,xml配置和定义接口,所以这里既有 InitializingBean、DisposableBean 也有需要 XmlBeanDefinitionReader 加载 spring.xml 配置信息到 BeanDefinition 中。
  • 另外接口 ConfigurableBeanFactory 定义了 destroySingletons 销毁方法,并由 AbstractBeanFactory 继承的父类 DefaultSingletonBeanRegistry 实现 ConfigurableBeanFactory 接口定义的 destroySingletons 方法。把实现接口的操作又交给继承的父类处理。是一种不错的隔离分层服务的设计方式
  • 最后就是关于向虚拟机注册钩子,保证在虚拟机关闭之前,执行销毁操作。Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("close!")));

定义初始化和销毁方法的接口

1
2
3
4
5
6
7
8
9
10
11
public interface InitializingBean {

/**
* Bean 处理了属性填充后调用
*
* @throws Exception
*/
void afterPropertiesSet() throws Exception;

}

1
2
3
4
5
6
public interface DisposableBean {

void destroy() throws Exception;

}

  • InitializingBean、DisposableBean,两个接口方法还是比较常用的,在一些需要结合 Spring 实现的组件中,经常会使用这两个方法来做一些参数的初始化和销毁操作。比如接口暴漏、数据库数据读取、配置文件加载等等

Bean属性定义新增初始化和销毁

1
2
3
4
5
6
7
8
9
10
11
12
13
public class BeanDefinition {

private Class beanClass;

private PropertyValues propertyValues;

private String initMethodName;

private String destroyMethodName;

// ...get/set
}

  • 在 BeanDefinition 新增加了两个属性:initMethodName、destroyMethodName,这两个属性是为了在 spring.xml 配置的 Bean 对象中,可以配置 init-method="initDataMethod" destroy-method="destroyDataMethod" 操作,最终实现接口的效果是一样的。只不过一个是接口方法的直接调用,另外是一个在配置文件中读取到方法反射调用

执行 Bean 对象的初始化方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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;
}

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(bean, 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);
}
}

}

  • 抽象类 AbstractAutowireCapableBeanFactory 中的 createBean 是用来创建 Bean 对象的方法,在这个方法中我们之前已经扩展了 BeanFactoryPostProcessor、BeanPostProcessor 操作,这里我们继续完善执行 Bean 对象的初始化方法的处理动作。
  • 在方法 invokeInitMethods 中,主要分为两块来执行实现了 InitializingBean 接口的操作,处理 afterPropertiesSet 方法。另外一个是判断配置信息 init-method 是否存在,执行反射调用 initMethod.invoke(bean)。这两种方式都可以在 Bean 对象初始化过程中进行处理加载 Bean 对象中的初始化操作,让使用者可以额外新增加自己想要的动作。

定义销毁方法适配器(接口和配置)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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时注册销毁方法对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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));
}
}

}

  • 在创建 Bean 对象的实例的时候,需要把销毁方法保存起来,方便后续执行销毁动作进行调用。
  • 那么这个销毁方法的具体方法信息,会被注册到 DefaultSingletonBeanRegistry 中新增加的 Map<String, DisposableBean> disposableBeans 属性中去,因为这个接口的方法最终可以被类 AbstractApplicationContext 的 close 方法通过 getBeanFactory().destroySingletons() 调用。
  • 在注册销毁方法的时候,会根据是接口类型和配置类型统一交给 DisposableBeanAdapter 销毁适配器类来做统一处理。实现了某个接口的类可以被 instanceof 判断或者强转后调用接口方法

虚拟机关闭钩子注册调用销毁方法

1
2
3
4
5
6
7
8
9
10
public interface ConfigurableApplicationContext extends ApplicationContext {

void refresh() throws BeansException;

void registerShutdownHook();

void close();

}

首先我们需要在 ConfigurableApplicationContext 接口中定义注册虚拟机钩子的方法 registerShutdownHook 和手动执行关闭的方法 close

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

// ...

@Override
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
}

@Override
public void close() {
getBeanFactory().destroySingletons();
}

}

  • 这里主要体现了关于注册钩子和关闭的方法实现

TEST

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class UserDao {

private static Map<String, String> hashMap = new HashMap<>();

public void initDataMethod(){
System.out.println("执行:init-method");
hashMap.put("10001", "zzc1");
hashMap.put("10002", "zzc2");
hashMap.put("10003", "zzc3");
}

public void destroyDataMethod(){
System.out.println("执行:destroy-method");
hashMap.clear();
}

public String queryUserName(String uId) {
return hashMap.get(uId);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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");
}

// ...get/set
}

  • UserDao,修改了之前使用 static 静态块初始化数据的方式,改为提供 initDataMethod 和 destroyDataMethod 两个更优雅的操作方式进行处理。
  • UserService,以实现接口 InitializingBean, DisposableBean 的两个方法 destroy()、afterPropertiesSet(),处理相应的初始化和销毁方法的动作。afterPropertiesSet,方法名字很好,在属性设置后执行

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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 属性中去
1
2
3
4
5
6
7
8
9
10
11
12
@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);
}

成了关于初始和销毁在使用接口定义 implements InitializingBean, DisposableBean 和在spring.xml中配置 init-method="initDataMethod" destroy-method="destroyDataMethod" 的两种具体在 AbstractAutowireCapableBeanFactory 完成初始方法和 AbstractApplicationContext 处理销毁动作的具体实现过程。

可以看到目前这个 Spring 框架对 Bean 的操作越来越完善了,可扩展性也不断的增强。你既可以在Bean注册完成实例化前进行 BeanFactoryPostProcessor 操作,也可以在Bean实例化过程中执行前置和后置操作,现在又可以执行Bean的初始化方法和销毁方法。所以一个简单的Bean对象,已经被赋予了各种扩展能力

A继承B实现C时,C的接口方法由A继承的父类B实现。可以复用到通常的业务系统开发中进行处理一些复杂逻辑的功能分层,做到程序的可扩展、易维护等特性。

实现感知容器对象

img

  • 定义接口 Aware,在 Spring 框架中它是一种感知标记性接口,具体的子类定义和实现能感知容器中的相关对象。也就是通过这个桥梁,向具体的实现类中提供容器服务
  • 继承 Aware 的接口包括:BeanFactoryAware、BeanClassLoaderAware、BeanNameAware和ApplicationContextAware

图 9-2

  • Aware 有四个继承的接口,其他这些接口的继承都是为了继承一个标记,有了标记的存在更方便类的操作和具体判断实现。
  • 另外由于 ApplicationContext 并不是在 AbstractAutowireCapableBeanFactory 中 createBean 方法下的内容,所以需要像容器中注册 addBeanPostProcessor ,再由 createBean 统一调用 applyBeanPostProcessorsBeforeInitialization 时进行操作

定义标记接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 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 一起判断使用

容器感知类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public interface BeanFactoryAware extends Aware {

void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}

public interface BeanClassLoaderAware extends Aware{

void setBeanClassLoader(ClassLoader classLoader);

}


public interface BeanNameAware extends Aware {

void setBeanName(String name);

}


public interface ApplicationContextAware extends Aware {

void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}




包装处理器(ApplicationContextAwareProcessor)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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();
}

// ...
}

  • refresh() 方法就是整个 Spring 容器的操作过程。本次新增加了关于 addBeanPostProcessor 的操作。

  • 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext

感知调用操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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;
}

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(bean, beanName);
return wrappedBean;
}



@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;
}

}

  • 首先在 initializeBean 中,通过判断 bean instanceof Aware,调用了三个接口方法,BeanFactoryAware.setBeanFactory(this)BeanClassLoaderAware.setBeanClassLoader(getBeanClassLoader())BeanNameAware.setBeanName(beanName),这样就能通知到已经实现了此接口的类。
  • 另外我们还向 BeanPostProcessor 中添加了 ApplicationContextAwareProcessor,此时在这个方法中也会被调用到具体的类实现,得到一个 ApplicationContex 属性

图 9-3

对象作用域以及FactoryBean

交给 Spring 管理的 Bean 对象,一定就是我们用类创建出来的 Bean 吗?创建出来的 Bean 就永远是单例的吗,没有可能是原型模式吗?

img

  • 整个的实现过程包括了两部分,一个解决单例还是原型对象,另外一个处理 FactoryBean 类型对象创建过程中关于获取具体调用对象的 getObject 操作

  • SCOPE_SINGLETONSCOPE_PROTOTYPE,对象类型的创建获取方式,主要区分在于 AbstractAutowireCapableBeanFactory#createBean 创建完成对象后是否放入到内存中,如果不放入则每次获取都会重新创建。

  • createBean 执行对象创建、属性填充、依赖加载、前置后置处理、初始化等操作后,就要开始做执行判断整个对象是否是一个 FactoryBean 对象,如果是这样的对象,就需要再继续执行获取 FactoryBean 具体对象中的 getObject 对象了。整个 getBean 过程中都会新增一个单例类型的判断factory.isSingleton(),用于决定是否使用内存存放对象信息。

图 10-2

  • 以上整个类关系图展示的就是添加 Bean 的实例化是单例还是原型模式以及 FactoryBean 的实现。
  • 其实整个实现的过程并不复杂,只是在现有的 AbstractAutowireCapableBeanFactory 类以及继承的抽象类 AbstractBeanFactory 中进行扩展。
  • 不过这次我们把 AbstractBeanFactory 继承的 DefaultSingletonBeanRegistry 类,中间加了一层 FactoryBeanRegistrySupport,这个类在 Spring 框架中主要是处理关于 FactoryBean 注册的支撑操作

Bean的作用范围定义和xml解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;

// ...get/set
}

  • singleton、prototype,是本次在 BeanDefinition 类中新增加的两个属性信息,用于把从 spring.xml 中解析到的 Bean 对象作用范围填充到属性中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {

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);
}

// ...

// 注册 BeanDefinition
getRegistry().registerBeanDefinition(beanName, beanDefinition);
}
}

}

  • 在解析 XML 处理类 XmlBeanDefinitionReader 中,新增加了关于 Bean 对象配置中 scope 的解析,并把这个属性信息填充到 Bean 定义中。beanDefinition.setScope(beanScope)

创建和修改对象时候判断单例和原型模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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));
}
}

// ... 其他功能
}

  • 单例模式和原型模式的区别就在于是否存放到内存中,如果是原型模式那么就不会存放到内存中,每次获取都重新创建对象,另外非 Singleton 类型的 Bean 不需要执行销毁方法。
  • 所以这里的代码会有两处修改,一处是 createBean 中判断是否添加到 addSingleton(beanName, bean);,另外一处是 registerDisposableBeanIfNecessary 销毁注册中的判断 if (!beanDefinition.isSingleton()) return;

定义 FactoryBean 接口

1
2
3
4
5
6
7
8
9
10
public interface FactoryBean<T> {

T getObject() throws Exception;

Class<?> getObjectType();

boolean isSingleton();

}

  • FactoryBean 中需要提供3个方法,获取对象、对象类型,以及是否是单例对象,如果是单例对象依然会被放到内存中。

实现一个 FactoryBean 注册服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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 进行逻辑包装

扩展 AbstractBeanFactory 创建对象逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

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;
}

// ...
}

  • 首先这里把 AbstractBeanFactory 原来继承的 DefaultSingletonBeanRegistry,修改为继承 FactoryBeanRegistrySupport。因为需要扩展出创建 FactoryBean 对象的能力,所以这就想一个链条服务上,截出一个段来处理额外的服务,并把链条再链接上。
  • 此处新增加的功能主要是在 doGetBean 方法中,添加了调用 (T) getObjectForBeanInstance(sharedInstance, name) 对获取 FactoryBean 的操作。
  • 在 getObjectForBeanInstance 方法中做具体的 instanceof 判断,另外还会从 FactoryBean 的缓存中获取对象,如果不存在则调用 FactoryBeanRegistrySupport#getObjectFromFactoryBean,执行具体的操作

TEST

1
2
3
4
5
6
public interface IUserDao {

String queryUserName(String uId);

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class UserService {

private String uId;
private String company;
private String location;
private IUserDao userDao;

public String queryUserInfo() {
return userDao.queryUserName(uId) + "," + company + "," + location;
}

// ...get/set
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class ProxyBeanFactory implements FactoryBean<IUserDao> {

@Override
public IUserDao getObject() throws Exception {
InvocationHandler handler = (proxy, method, args) -> {

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 的代理对象,当有方法调用的时候,则执行代理对象的功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@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” 这样就每次获取到的对象都应该是一个新的对象。
  • 这里判断对象是否为一个会看到打印的类对象的哈希值,所以我们把十六进制哈希打印出来
1
2
3
4
5
6
7
8
9
10
11
@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());
}

容器事件和事件监听器

如:这里需要一个注册完成事件推送消息用户下单我会发送一个MQ收到我的支付消息就可以发货了等等,都是依靠事件订阅和发布以及MQ消息这样的组件,来处理系统之间的调用解耦,最终通过解耦的方式来提升整体系统架构的负载能力。

其实解耦思路可以理解为设计模式中观察者模式的具体使用效果,在观察者模式中当对象间存在一对多关系时,则使用观察者模式,它是一种定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

在 Spring 中有一个 Event 事件功能,它可以提供事件的定义、发布以及监听事件来完成一些自定义的动作。比如你可以定义一个新用户注册的事件,当有用户执行注册完成后,在事件监听中给用户发送一些优惠券和短信提醒,这样的操作就可以把属于基本功能的注册和对应的策略服务分开,降低系统的耦合。以后在扩展注册服务,比如需要添加风控策略、添加实名认证、判断用户属性等都不会影响到依赖注册成功后执行的动作。

我们需要以观察者模式的方式,设计和实现 Spring Event 的容器事件和事件监听器功能,最终可以让我们在现有实现的 Spring 框架中可以定义、监听和发布自己的事件信息

其实事件的设计本身就是一种观察者模式的实现,它所要解决的就是一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

在功能实现上我们需要定义出事件类、事件监听、事件发布,而这些类的功能需要结合到 Spring 的 AbstractApplicationContext#refresh(),以便于处理事件初始化和注册事件监听器的操作

img

  • 在整个功能实现过程中,仍然需要在面向用户的应用上下文 AbstractApplicationContext 中添加相关事件内容,包括:初始化事件发布者、注册事件监听器、发布容器刷新完成事件。
  • 使用观察者模式定义事件类、监听类、发布类,同时还需要完成一个广播器的功能,接收到事件推送时进行分析处理符合监听事件接受者感兴趣的事件,也就是使用 isAssignableFrom 进行判断。
  • isAssignableFrom 和 instanceof 相似,不过 isAssignableFrom 是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,默认所有的类的终极父类都是Object。如果A.isAssignableFrom(B)结果是true,证明B可以转换成为A,也就是A可以由B转换而来

图 10-2

  • 以上整个类关系图以围绕实现 event 事件定义、发布、监听功能实现和把事件的相关内容使用 AbstractApplicationContext#refresh 进行注册和处理操作。
  • 在实现的过程中主要以扩展 spring context 包为主,事件的实现也是在这个包下进行扩展的,当然也可以看出来目前所有的实现内容,仍然是以IOC为主。
  • ApplicationContext 容器继承事件发布功能接口 ApplicationEventPublisher,并在实现类中提供事件监听功能。
  • ApplicationEventMulticaster 接口是注册监听器和发布事件的广播器,提供添加、移除和发布事件方法。
  • 最后是发布容器关闭事件,这个仍然需要扩展到 AbstractApplicationContext#close 方法中,由注册到虚拟机的钩子实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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,后续所有事件的类都需要继承这个类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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();
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
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 框架自己实现的两个事件类,可以用于监听刷新和关闭动作

事件广播器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 最终推送时间消息也会经过这个接口方法来处理谁该接收事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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;
}

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,方便最后确认是否为子类和父类的关系,以此证明此事件归这个符合的类处理。可以参考代码中的注释

事件发布者的定义和实现

1
2
3
4
5
6
7
8
9
10
11
12
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 是整个一个事件的发布接口,所有的事件都需要从这个接口发布出去。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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 {

// 6. 初始化事件发布者
initApplicationEventMulticaster();

// 7. 注册事件监听器
registerListeners();

// 9. 发布容器刷新完成事件
finishRefresh();
}

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 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))

TEST

创建一个事件和监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}

// ...get/set
}

  • 创建一个自定义事件,在事件类的构造函数中可以添加自己的想要的入参信息。这个事件类最终会被完成的拿到监听里,所以你添加的属性都会被获得到
1
2
3
4
5
6
7
8
9
10
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> 监听器
1
2
3
4
5
6
7
8
9
10
11
<?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 中配置了三个事件监听器,监听刷新、监控自定义事件、监听关闭事件
1
2
3
4
5
6
7
8
9
10
11
12
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,并透传了相应的参数信息