當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
【Spring源码】从源码实现的角度解析spring的InitializingBean的afterPropertiesSet方法和init-method区别和应用
生活随笔
收集整理的這篇文章主要介紹了
【Spring源码】从源码实现的角度解析spring的InitializingBean的afterPropertiesSet方法和init-method区别和应用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
InitializingBean
? ? spring的InitializingBean為bean提供了定義初始化方法的方式。InitializingBean是一個接口,只包含一個方法:afterPropertiesSet():
<beans><bean name ="lifeBean" class ="com.spring.LifeCycleBean"></beans > </beans> 編寫測試程序進行測試:
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("com/spring/applicationcontext.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子定義的初始化方法。 bean實現:
package com.spring;public class LifeCycleBean{publicvoid init(){System. out .println("LifeCycleBean.init...");} } 在Spring配置文件中配置這個bean:
<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的父類DefaultListableBeanFactory的父類,也就是XmlBeanFactory的超類,在AbstractAutowireCapableBeanFactory的invokeInitMethods方法中實現了一個調用Bean初始化的方法: 源代碼如下:
//bean裝配完成之后,執行bean初始化方法protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)throws Throwable{//判斷bean是否實現了InitializingBean接口boolean isInitializingBean = bean instanceof InitializingBean;if(isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))){if(logger.isDebugEnabled())logger.debug((new StringBuilder()).append("Invoking afterPropertiesSet() on bean with name '").append(beanName).append("'").toString());if(System.getSecurityManager() != null)try{AccessController.doPrivileged(new PrivilegedExceptionAction() {public Object run()throws Exception{//調用afterPropertiesSet方法((InitializingBean)bean).afterPropertiesSet();return null;}final Object val$bean;final AbstractAutowireCapableBeanFactory this$0;{this.this$0 = AbstractAutowireCapableBeanFactory.this;bean = obj;super();}} , getAccessControlContext());}catch(PrivilegedActionException pae){throw pae.getException();}else((InitializingBean)bean).afterPropertiesSet();調用afterPropertiesSet方法}if(mbd != null){//判斷bean是否定義了init-method方法String initMethodName = mbd.getInitMethodName();if(initMethodName != null && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName))//調用invokeCustomInitMethod方法來執行init-method定義的方法invokeCustomInitMethod(beanName, bean, mbd);}}//執行bean定義的init-method方法protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)throws Throwable{String initMethodName = mbd.getInitMethodName();//使用方法名,反射Method對象final Method initMethod = mbd.isNonPublicAccessAllowed() ? BeanUtils.findMethod(bean.getClass(), initMethodName, new Class[0]) : ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName, new Class[0]);if(initMethod == null){if(mbd.isEnforceInitMethod())throw new BeanDefinitionValidationException((new StringBuilder()).append("Couldn't find an init method named '").append(initMethodName).append("' on bean with name '").append(beanName).append("'").toString());if(logger.isDebugEnabled())logger.debug((new StringBuilder()).append("No default init method named '").append(initMethodName).append("' found on bean with name '").append(beanName).append("'").toString());return;}if(logger.isDebugEnabled())logger.debug((new StringBuilder()).append("Invoking init method '").append(initMethodName).append("' on bean with name '").append(beanName).append("'").toString());if(System.getSecurityManager() != null){AccessController.doPrivileged(new PrivilegedExceptionAction() {public Object run()throws Exception{ReflectionUtils.makeAccessible(initMethod);return null;}final Method val$initMethod;final AbstractAutowireCapableBeanFactory this$0;{this.this$0 = AbstractAutowireCapableBeanFactory.this;initMethod = method;super();}} );try{AccessController.doPrivileged(new PrivilegedExceptionAction() {public Object run()throws Exception{initMethod.invoke(bean, new Object[0]);//反射執行init-method方法return null;}final Method val$initMethod;final Object val$bean;final AbstractAutowireCapableBeanFactory this$0;{this.this$0 = AbstractAutowireCapableBeanFactory.this;initMethod = method;bean = obj;super();}} , getAccessControlContext());}catch(PrivilegedActionException pae){InvocationTargetException ex = (InvocationTargetException)pae.getException();throw ex.getTargetException();}} else{try{ReflectionUtils.makeAccessible(initMethod);initMethod.invoke(bean, new Object[0]);//反射執行init-method方法}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上。
可以借助這個InitializingBean方法來完成一些需要在bean初始化時完成的工作。 示例場景: 一個bean在初始化時需要讀取項目目錄中某個文件夾下的配置文件。 bean配置: <bean id="testServiceConfig" class="com.lmb.client.TestlServiceConfigImpl"><property name="folderName" value="test_config" /> </bean> 調用代碼:
//bean初始化之后調用afterPropertiesSet方法根據配置目錄,讀取相應目錄下的配置文件 public class TestServiceConfigImpl implements InitializingBean {private String folderName;@Overridepublic void afterPropertiesSet()throws Exception{folderName = folderName != null ? folderName : "test_config";reload(folderName);}//根據文件目錄加載配置文件public void reload(String fileName) throws Exception {fileName = fileName.startsWith("/") ? fileName.substring(1) : fileName;//根據文件名稱獲取相應的文件File file = ResourceUtils.getFile("classpath:" + fileName);if (file.isDirectory()) {File[] files = file.listFiles();for (File configFile : files) {//加載文件……}}} }
總結
以上是生活随笔為你收集整理的【Spring源码】从源码实现的角度解析spring的InitializingBean的afterPropertiesSet方法和init-method区别和应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【JMS】JMS详解
- 下一篇: 【RPC】你应该知道的 RPC 原理