1、总结


其中,@PostConstruct 的调用与 BeanPostProcessor 相关。

<mark>强调:
需要根据应用的需求做出合适的决定:</mark>

  • <mark>当需要考虑可移植性问题时,使用方法回调</mark>
  • <mark>需要减少配置量时,可以使用DisposableBean接口</mark>
  • (书上没写注解的应用场景,注解似乎适合以上两种需求)

2、测试

测试类:A

package book.chapter4;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class A implements InitializingBean , DisposableBean  {
	public A() {
		System.out.println("1. construct ... ");
	}
	
	private String a ;

	public String getA() {
		return a;
	}

	public void setA(String a) {
		System.out.println("2. setting ... ");
		this.a = a;
	} 
	
	@PostConstruct
	public void postConstruct() {
		System.out.println("3. postConstruct ... ");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("4. afterPropertiesSet.afterPropertiesSet() ... ");
	}
	
	public void init() {
		System.out.println("5. init-method ... ");
	}
	public void doSomething() {
		System.out.println("-------------- do something ... ");
	}

	@PreDestroy
	public void PreDestroy() {
		System.out.println("1. PreDestroy ... ");
	}
	
	@Override
	public void destroy() throws Exception {
		System.out.println("2. DisposableBean.destroy() ... ");
	}
	
	public void destroyMethod() {
		System.out.println("3. destroy-method ... ");
	}
	
}

测试类:Demo

package book.chapter4;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.GenericXmlApplicationContext;

public class BeanDemo {
	
	@Test
	public void testXml() {
		System.out.println("###### load ##############");
		GenericXmlApplicationContext gtx = new GenericXmlApplicationContext();
		gtx.load("classpath:book/chapter4/app-context-a.xml") ;
		gtx.refresh();
		
		System.out.println("###### getBean ############");
		A bean = gtx.getBean("a" , A.class);
		bean.doSomething();
		
		System.out.println("###### close #############");
		gtx.close();
	}
	
}

测试结果

3、扩展

在 Spring 中销毁回调函数的唯一缺点是他们不会自动触发;

如果 applicationContext 的实现 是 GenericXmlApplicationContext 时候 很好解决

registerShutdownHook()

只需要 进行 销毁注册方法 registerShutdownHook()

package book.chapter4;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class BeanDemo {
	
	@Test
	public void testLoad$Close() {
		System.out.println("###### load ##############");
		GenericXmlApplicationContext gtx = new GenericXmlApplicationContext();
		gtx.load("classpath:book/chapter4/app-context-a.xml") ;
		gtx.refresh();
		
		System.out.println("###### getBean ############");
		A bean = gtx.getBean("a" , A.class);
		bean.doSomething();
		
		System.out.println("###### close #############");
		gtx.close();
	}
	@Test
	public void testRegisterShutdownHook() {
		System.out.println("###### load ##############");
		GenericXmlApplicationContext gtx = new GenericXmlApplicationContext();
		gtx.registerShutdownHook();
		gtx.load("classpath:book/chapter4/app-context-a.xml") ;
		gtx.refresh();
		
		System.out.println("###### getBean ############");
		A bean = gtx.getBean("a" , A.class);
		bean.doSomething();
		
		System.out.println("###### close #############");
	}
}

运行 测试 testRegisterShutdownHook 。发现在没有 调用 close 时候也能进行资源释放。

ApplicationContextAware 接口

最后,可以 添加一个 实现了 ApplicationContextAware 接口 的bean

会自动扫描 是否存在 GenericXmlApplicationContext ,
存在 ,就自动 执行 注册方法 registerShutdownHook()

xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	default-init-method="init" 
	default-destroy-method="destroyMethod"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

<context:annotation-config />

<bean id="a" class="book.chapter4.A"  p:a="propA"/>
<bean class="book.chapter4.ShutdownHookBean" />

</beans>

实现了 ApplicationContextAware 接口 的bean

package book.chapter4;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.GenericXmlApplicationContext;

public class ShutdownHookBean implements ApplicationContextAware {
	
	public ShutdownHookBean() {
		System.out.println("### ShutdownHookBean constructor ... ");
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		if(applicationContext instanceof GenericXmlApplicationContext) {
			GenericXmlApplicationContext gtx = (GenericXmlApplicationContext)applicationContext ;
			gtx.registerShutdownHook(); 
			System.out.println("#### registerShutdownHook() ... ");
		}
		
	}

}

Test 类

package book.chapter4;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class BeanDemoHook {
	

	@Test
	public void testHookBean() {
		System.out.println("###### load ##############");
		GenericXmlApplicationContext gtx = new GenericXmlApplicationContext();
		gtx.load("classpath:book/chapter4/app-context-xml-hook.xml") ;
		gtx.refresh();
		
		System.out.println("###### getBean ############");
		A bean = gtx.getBean("a" , A.class);
		bean.doSomething();
		
		System.out.println("###### close #############");
	}
	

	
}

结果