本文是学习《Spring 手撸专栏》第 8 章笔记,主要记录我的一些debug调试过程,方便后期复习。具体学习,大家可以去看一下这个专栏,强烈推荐。
当我们的类创建的 Bean 对象,交给 Spring 容器管理以后,这个类对象就可以被赋予更多的使用能力。
那么除此之外我们还希望可以在 Bean 初始化过程,执行一些操作。如果说没有Spring我们也可以通过构造函数、静态方法以及手动调用的方式实现,但这样的处理方式终究不如把诸如此类的操作都交给 Spring 容器来管理更加合适。 因此你会看到到 spring.xml 中有如下操作:
其实对于这样在 Bean 容器初始化过程中额外添加的处理操作,无非就是预先执行了一个定义好的接口方法或者是反射调用类中xml中配置的方法,最终你只要按照接口定义实现,就会有 Spring 容器在处理的过程中进行调用而已。整体设计结构如下图:
主线
public void test_xml() {
// 1.初始化 BeanFactory (1)
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.registerShutdownHook();//(7)
// 2. 获取Bean对象调用方法
UserService userService = applicationContext.getBean("userService", UserService.class);
String result = userService.queryUserInfo();
System.out.println("测试结果:" + result);
}
先所注册bean操作
这里前面已经提到很多了,这里就不再重复调试了,我说一下不一样的地方
(1)AbstractAutowireCapableBeanFactory 主线分支1
给Bean填充属性时,会把我们xml文件中的配置填充进去(我们后文的UserDao的destroyDataMethod属性就是在这里填充的)
在这里执行Bean 的初始化方法,注意他是在填充了属性之后再调用的。
注册实现了DisposableBean 接口的Bean对象
//利用反射进行bean的实例化
@Override
protected Object creatBean(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);//(2)
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed",e);
}
//注册实现了DisposableBean 接口的Bean对象
registerDisposableBeanIfNecessary(beanName,bean,beanDefinition);//(5)
addSingleton(beanName,bean);
return bean;
}
(2) AbstractAutowireCapableBeanFactory
private Object initializeBean(String beanName,Object bean,BeanDefinition beanDefinition){
//1 执行BeanPostProcessor Before处理
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
try {
invokeInitMethods(beanName, wrappedBean, beanDefinition);//(3)
}catch (Exception e){
throw new BeansException("Invocation of init method of bean["+beanName+"] failed",e);
}
//2 执行BeanPostProcessor After处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
return wrappedBean;
}
(3) AbstractAutowireCapableBeanFactory
就是在这里调用我们自己实现了InitializingBean的类中的afterPropertiesSet方法的。
private void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
//这两种方式都可以在 Bean 对象初始化过程中进行处理加载 Bean 对象中的初始化操作,让使用者可以额外新增加自己想要的动作。
//1 实现了接口InitializingBean
if (bean instanceof InitializingBean){
((InitializingBean)bean).afterPropertiesSet();//(4)
}
//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);
}
}
(4)UserService implements InitializingBean, DisposableBean
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行:UserService.afterPropertiesSet");
}
(5)AbstractAutowireCapableBeanFactory
把继承了DisposableBean接口的,或者在xml配置了destroyMethodName的bean注册进去
protected void registerDisposableBeanIfNecessary(String beanName,Object bean,BeanDefinition beanDefinition){
if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())){
//(6)
registerDisposableBean(beanName,new DisposableBeanAdapter(bean,beanName,beanDefinition));
}
}
(6)DefaultSingletonBeanRegistry
这里其实就是把需要执行销毁方法的bean放入链表中,后面注销是从这里拿出来即可
private final Map<String, DisposableBean> disposableBeans = new HashMap<>();
public void registerDisposableBean(String beanName,DisposableBean bean){
disposableBeans.put(beanName,bean);
}
(7) AbstractApplicationContext 主线分支2
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
}
@Override
public void close() {
getBeanFactory().destroySingletons(); //(8)
}
(8)DefaultSingletonBeanRegistry
把之前注册进disposableBeans的disposableBean取出,然后disposableBean.destroy();
private final Map<String, DisposableBean> disposableBeans = new HashMap<>();
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(); //(9)
}catch (Exception e){
throw new BeansException("Destroy method on bean with name '"+beanName+"'threw an exception",e);
}
}
}
(9) DisposableBeanAdapter
无论是实现了接口的,还是通过xml配置的,统一在这个适配器中进行销毁处理,这样就不用单独再实现两个类进行处理了
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);
}
}