赞
踩
当我们的类创建的 Bean 对象,交给 Spring 容器管理以后,这个类对象就可以被赋予更多的使用能力。我们还希望可以在 Bean 初始化过程,执行一些操作。比如帮我们做一些数据的加载执行,链接注册中心暴漏RPC接口以及在Web程序关闭时执行链接断开,内存销毁等操作。如果说没有Spring我们也可以通过构造函数、静态方法以及手动调用的方式实现,但这样的处理方式终究不如把诸如此类的操作都交给 Spring 容器来管理更加合适。 因此你会看到到 spring.xml 中有如下操作:
需要满足用户可以在 xml 中配置初始化和销毁的方法,也可以通过实现类的方式处理,比如我们在使用 Spring 时用到的 InitializingBean, DisposableBean 两个接口。
第三种方法是在方法上加注解PostConstruct和PreDestroy 这种方法暂时不做实现
对于这样在 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
│ │ │ ├── factory
│ │ │ │ ├── AutowireCapableBeanFactory.java
│ │ │ │ ├── BeanDefinition.java(实体类)
初始化和销毁
│ │ │ │ ├── BeanFactoryPostProcessor.java
│ │ │ │ ├── BeanPostProcessor.java
│ │ │ │ ├── BeanReference.java
│ │ │ │ ├── ConfigurableBeanFactory.java(接口) 定义了 destroySingletons 销毁方法
│ │ │ │ └── SingletonBeanRegistry.java
│ │ │ ├── support
│ │ │ │ ├── AbstractAutowireCapableBeanFactory.java(抽象类)
继承关系:继承AbstractBeanFactory
实现AutowireCapableBeanFactory接口
主要方法:
CreateBean():创建Bean 调用registerDisposableBeanIfNecessary
initializeBean():初始化Bean,调用PostProcessor Before 处理,执行初始化方法invokeInitMethods,执行 BeanPostProcessor After 处理
│ │ │ │ ├── AbstractBeanDefinitionReader.java
│ │ │ │ ├── AbstractBeanFactory.java
│ │ │ │ ├── BeanDefinitionReader.java
│ │ │ │ ├── BeanDefinitionRegistry.java
│ │ │ │ ├── CglibSubclassingInstantiationStrategy.java
│ │ │ │ ├── DefaultListableBeanFactory.java
│ │ │ │ ├── DefaultSingletonBeanRegistry.java
实现destroySingletons 销毁方法( AbstractBeanFactory.java的父类)
│ │ │ │ ├── DisposableBeanAdapter.java
描述:销毁方法适配器
继承关系: 实现DisposableBean接口
│ │ │ │ ├── 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(抽象类)
继承关系:实现 ConfigurableApplicationContext接口
│ │ │ ├── AbstractRefreshableApplicationContext.java
│ │ │ ├── AbstractXmlApplicationContext.java
│ │ │ └── ClassPathXmlApplicationContext.java
│ │ ├── ApplicationContext.java
│ │ └── ConfigurableApplicationContext.java(接口)
主要描述:虚拟机关闭钩子注册调用销毁
继承关系:继承ApplicationContext
主要方法:
refresh():
registerShutdownHook():注册虚拟机钩子的方法
close():手动执行关闭虚拟机钩子的方法
│ ├── 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!”)));
InitializingBean
public interface InitializingBean {
/**
* Bean 处理了属性填充后调用
*
* @throws Exception
*/
void afterPropertiesSet() throws Exception;
}
DisposableBean
public interface DisposableBean {
void destroy() throws Exception;
}
InitializingBean、DisposableBean,两个接口方法还是比较常用的,在一些需要结合 Spring 实现的组件中,经常会使用这两个方法来做一些参数的初始化和销毁操作。比如接口暴漏、数据库数据读取、配置文件加载等等。
BeanDefinition
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” 操作,最终实现接口的效果是一样的。只不过一个是接口方法的直接调用,另外是一个在配置文件中读取到方法反射调用
AbstractAutowireCapableBeanFactory
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); } } }
1.抽象类 AbstractAutowireCapableBeanFactory 中的 createBean 是用来创建 Bean 对象的方法,在这个方法中我们之前已经扩展了BeanFactoryPostProcessor、BeanPostProcessor 操作,这里我们继续完善执行 Bean 对象的初始化方法的处理动作。
2.在方法 invokeInitMethods 中,主要分为两块来执行实现了 InitializingBean 接口的操作,处理 afterPropertiesSet 方法。另外一个是判断配置信息 init-method 是否存在,执行反射调用initMethod.invoke(bean)。这两种方式都可以在 Bean 对象初始化过程中进行处理加载 Bean 对象中的初始化操作,让使用者可以额外新增加自己想要的动作。
??这里的适配器模式如何理解
DisposableBeanAdapter
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 在注册虚拟机钩子后看,虚拟机关闭前执行的操作动作。
那么在销毁执行时不太希望还得关注都销毁那些类型的方法,它的使用上更希望是有一个统一的接口进行销毁,所以这里就新增了适配类,做统一处理。
AbstractAutowireCapableBeanFactory
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)); } } }
DefaultSingletonBeanRegistry
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() { ArrayList<String> beanNames = new ArrayList<>(disposableBeans.keySet()); for (String beanName : beanNames) { 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); } } } }
1.在创建 Bean 对象的实例的时候,需要把销毁方法保存起来,方便后续执行销毁动作进行调用。
2.那么这个销毁方法的具体方法信息,会被注册到 DefaultSingletonBeanRegistry 中新增加的 Map<String, DisposableBean> disposableBeans 属性中去,因为这个接口的方法最终可以被类 AbstractApplicationContext 的 close 方法通过 getBeanFactory().destroySingletons() 调用。
在注册销毁方法的时候,会根据是接口类型和配置类型统一交给 DisposableBeanAdapter 销毁适配器类来做统一处理。实现了某个接口的类可以被 instanceof 判断或者强转后调用接口方法
ConfigurableApplicationContext
public interface ConfigurableApplicationContext extends ApplicationContext {
void refresh() throws BeansException;
void registerShutdownHook();
void close();
}
AbstractApplicationContext
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();
}
}
由AbstractApplication抽象类实现ConfigurableApplicationContex接口Context这里主要体现了关于注册钩子和关闭的方法实现,上文提到过的 Runtime.getRuntime().addShutdownHook,可以尝试验证。在一些中间件和监控系统的设计中也可以用得到,比如监测服务器宕机,执行备机启动操作。
UserDAO
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); } }
UserService
实现InitializingBean, DisposableBean接口
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 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。