Spring_Spring bean 通過實現 InitializingBean ,DisposableBean 介面實現初始化方法和銷燬前操作
via: http://blog.csdn.net/topwqp/article/details/8681573
Spring bean 通過實現 InitializingBean ,DisposableBean 介面實現初始化方法和銷燬前操作
關於在spring 容器初始化 bean 和銷燬前所做的操作定義方式有三種:
第一種:通過@PostConstruct 和 @PreDestroy 方法 實現初始化和銷燬bean之前進行的操作
第二種是:通過 在xml中定義init-method 和 destory-method方法
第三種是: 通過bean實現InitializingBean和 DisposableBean介面
1:定義相應類實現InitializingBean ,DisposableBean 介面
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class PersonService implements InitializingBean,DisposableBean{
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public void destroy() throws Exception {
System.out.println("I'm init method using implements DisposableBean interface...."+message);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("I'm init method using implements InitializingBean interface...."+message);
}
}
2:定義相應的配置檔案:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="personService" class="com.myapp.core.annotation.init.PersonService">
<property name="message" value="123"></property>
</bean>
</beans>
3:測試類:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("resource/annotation.xml");
PersonService personService = (PersonService)context.getBean("personService");
context.registerShutdownHook();
}
}
via: http://blog.csdn.net/hikvision_java_gyh/article/details/38346827?utm_source=tuicool
spring的InitializingBean的 afterPropertiesSet 方法 和 init-method配置的 區別聯絡
InitializingBean
Spirng的InitializingBean為bean提供了定義初始化方法的方式。InitializingBean是一個介面,它僅僅包含一個方法:afterPropertiesSet()。
Bean實現這個介面,在afterPropertiesSet()中編寫初始化程式碼:
import org.springframework.beans.factory.InitializingBean;
public class LifeCycleBean implements InitializingBean{
public void afterPropertiesSet() throws Exception {
System.out.println("LifeCycleBean initializing...");
}
}
在xml配置檔案中並不需要對bean進行特殊的配置:
xml version="1.0" encoding="UTF-8"?>DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="lifeBean" class="research.spring.beanfactory.ch4.LifeCycleBean">
</bean>
</beans>
編寫測試程式進行測試:
package research.spring.beanfactory.ch4;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class LifeCycleTest {
public static void main(String[] args) {
XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource("research/spring/beanfactory/ch4/context.xml"));
factory.getBean("lifeBean");
}
}
執行上面的程式我們會看到:“LifeCycleBean initializing...”,這說明bean的afterPropertiesSet已經被Spring呼叫了。
Spring在設定完一個bean所有的合作者後,會檢查bean是否實現了InitializingBean介面,如果實現就呼叫bean的afterPropertiesSet方法。
init-method
Spring雖然可以通過InitializingBean完成一個bean初始化後對這個bean的回撥,但是這種方式要求bean實現 InitializingBean介面。一但bean實現了InitializingBean介面,那麼這個bean的程式碼就和Spring耦合到一起了。通常情況下我不鼓勵bean直接實現InitializingBean,可以使用Spring提供的init-method的功能來執行一個bean 子定義的初始化方法。
寫一個java class,這個類不實現任何Spring的介面。定義一個沒有引數的方法init()。
package research.spring.beanfactory.ch4;
publicclass LifeCycleBean{
publicvoid init(){
System.out.println("LifeCycleBean.init...");
}
}
在Spring中配置這個bean:
xml version="1.0" encoding="UTF-8"?>DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd"><beans><bean name="lifeBean" class="research.spring.beanfactory.ch4.LifeCycleBean"
init-method="init">bean>beans>
當Spring例項化lifeBean時,你會在控制檯上看到” LifeCycleBean.init...”。
Spring要求init-method是一個無引數的方法,如果init-method指定的方法中有引數,那麼Spring將會丟擲java.lang.NoSuchMethodException
init-method指定的方法可以是public、protected以及private的,並且方法也可以是final的。
init-method指定的方法可以是宣告為丟擲異常的,就像這樣:
final protected void init() throws Exception{
System.out.println("init method...");
if(true) throw new Exception("init exception");
}
如果在init-method方法中丟擲了異常,那麼Spring將中止這個Bean的後續處理,並且丟擲一個org.springframework.beans.factory.BeanCreationException異常。
InitializingBean和init-method可以一起使用,Spring會先處理InitializingBean再處理init-method。
org.springframework.beans.factory.support. AbstractAutowireCapableBeanFactory完成一個Bean初始化方法的呼叫工作。 AbstractAutowireCapableBeanFactory是XmlBeanFactory的超類,再 AbstractAutowireCapableBeanFactory的invokeInitMethods方法中實現呼叫一個Bean初始化方法:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.java:
//……
//在一個bean的合作者裝置完成後,執行一個bean的初始化方法。protectedvoid invokeInitMethods(String beanName, Object bean, RootBeanDefinition mergedBeanDefinition)
throws Throwable {
//判斷bean是否實現了InitializingBean介面if (bean instanceof InitializingBean) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '"+ beanName +"'");
}
//呼叫afterPropertiesSet方法
((InitializingBean) bean).afterPropertiesSet();
}
//判斷bean是否定義了init-methodif(mergedBeanDefinition!=null&&mergedBeanDefinition.getInitMethodName() !=null) {
//呼叫invokeCustomInitMethod方法來執行init-method定義的方法
invokeCustomInitMethod(beanName, bean, mergedBeanDefinition.getInitMethodName());
}
}
//執行一個bean定義的init-method方法protectedvoid invokeCustomInitMethod(String beanName, Object bean, String initMethodName)
throws Throwable {
if (logger.isDebugEnabled()) {
logger.debug("Invoking custom init method '"+ initMethodName +"' on bean with name '"+ beanName +"'");
}
//使用方法名,反射Method物件
Method initMethod = BeanUtils.findMethod(bean.getClass(), initMethodName, null);
if (initMethod ==null) {
thrownew NoSuchMethodException(
"Couldn't find an init method named '"+ initMethodName +"' on bean with name '"+ beanName +"'");
}
//判斷方法是否是publicif (!Modifier.isPublic(initMethod.getModifiers())) {
//設定accessible為true,可以訪問private方法。
initMethod.setAccessible(true);
}
try {
//反射執行這個方法
initMethod.invoke(bean, (Object[]) null);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
通過分析上面的原始碼我們可以看到,init-method是通過反射執行的,而afterPropertiesSet是直接執行的。所以 afterPropertiesSet的執行效率比init-method要高,不過init-method消除了bean對Spring依賴。在實際使用時我推薦使用init-method。
需要注意的是Spring總是先處理bean定義的InitializingBean,然後才處理init-method。如果在Spirng處理InitializingBean時出錯,那麼Spring將直接丟擲異常,不會再繼續處理init-method。
如果一個bean被定義為非單例的,那麼afterPropertiesSet和init-method在bean的每一個例項被建立時都會執行。單例 bean的afterPropertiesSet和init-method只在bean第一次被例項時呼叫一次。大多數情況下 afterPropertiesSet和init-method都應用在單例的bean上。