1. 程式人生 > >Spring_Spring bean 通過實現 InitializingBean ,DisposableBean 介面實現初始化方法和銷燬前操作

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上。