stone2083

          編程方式實現SpringBean LazyInit

          Tags:
          Spring  LazyInit DocumentDefaultsDefinition ReaderEventListener AbstractXmlApplicationContext

          背景:
          工程單元測試希望和生產環境應用共用一份Spring配置文件.
          生產環境應用為了客戶體驗使用非LazyInit模式,但是單元測試下為了當前測試提高響應時間,希望設置LazyInit.

          分析源代碼,得知,Spring在解析XML時,會將Bean默認配置,放入到DocumentDefaultsDefinition對象中,其中包含lazyInit.
          DocumentDefaultsDefinition注釋如下:
          Simple JavaBean that holds the defaults specified at the <beans> level in a standard Spring XML bean definition document: default-lazy-init, default-autowire, etc

          Spring是否提供了入口點,進行DocumentDefaultsDefinition的修改呢?
          詳見:ReaderEventListener,注釋如下:
          Interface that receives callbacks for component, alias and import registrations during a bean definition reading process
          在BeanDefinition分析過程中,對component,alias,import registrations,defaults registrations提供一組callbacks.

          接口代碼如下:
           1 public interface ReaderEventListener extends EventListener {
           2 
           3     /**
           4      * Notification that the given defaults has been registered.
           5      * @param defaultsDefinition a descriptor for the defaults
           6      * @see org.springframework.beans.factory.xml.DocumentDefaultsDefinition
           7      */
           8     void defaultsRegistered(DefaultsDefinition defaultsDefinition);
           9 
          10     /**
          11      * Notification that the given component has been registered.
          12      * @param componentDefinition a descriptor for the new component
          13      * @see BeanComponentDefinition
          14      */
          15     void componentRegistered(ComponentDefinition componentDefinition);
          16 
          17     /**
          18      * Notification that the given alias has been registered.
          19      * @param aliasDefinition a descriptor for the new alias
          20      */
          21     void aliasRegistered(AliasDefinition aliasDefinition);
          22 
          23     /**
          24      * Notification that the given import has been processed.
          25      * @param importDefinition a descriptor for the import
          26      */
          27     void importProcessed(ImportDefinition importDefinition);
          28     
          29 }

          接下去分析,ReaderEventListener是在哪個入口點,提供了回調.答案是XmlBeanDefinitionReader.
          在AbstractXmlApplicationContext,創建了XmlBeanDefinitionReader對象,見:
           1 public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
           2     
           3     /**
           4      * Loads the bean definitions via an XmlBeanDefinitionReader.
           5      * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
           6      * @see #initBeanDefinitionReader
           7      * @see #loadBeanDefinitions
           8      */
           9     protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
          10         // Create a new XmlBeanDefinitionReader for the given BeanFactory.
          11         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
          12 
          13         // Configure the bean definition reader with this context's
          14         // resource loading environment.
          15         beanDefinitionReader.setResourceLoader(this);
          16         beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
          17 
          18         // Allow a subclass to provide custom initialization of the reader,
          19         // then proceed with actually loading the bean definitions.
          20         initBeanDefinitionReader(beanDefinitionReader);
          21         loadBeanDefinitions(beanDefinitionReader);
          22     }
          23 
          24 }

          我們只需要去復寫這個方法,在創建XmlBeanDefinitionReader的時候,去注入EventListener即可.

          擴展代碼如下:
          LazyInitListener.java (不管配置文件如何配置,設置默認的LazyInit為true)
          public class LazyInitListener implements ReaderEventListener {

              
          private static final String LAZY_INIT = "true";

              @Override
              
          public void defaultsRegistered(DefaultsDefinition defaultsDefinition) {
                  
          //set lazy init true
                  if (defaultsDefinition instanceof DocumentDefaultsDefinition) {
                      DocumentDefaultsDefinition defaults 
          = (DocumentDefaultsDefinition) defaultsDefinition;
                      defaults.setLazyInit(LAZY_INIT);
                  }
              }

              @Override
              
          public void aliasRegistered(AliasDefinition aliasDefinition) {
                  
          //no-op
              }

              @Override
              
          public void componentRegistered(ComponentDefinition componentDefinition) {
                  
          //no-op
              }

              @Override
              
          public void importProcessed(ImportDefinition importDefinition) {
                  
          //no-op
              }

          }

          LazyInitClasspathXmlApplicationContext.java (復寫AbstractXmlApplicationContext,創建XmlBeanDefinitionReader的時候注入LazyInitListener)
           1 public class LazyInitClasspathXmlApplicationContext extends ClassPathXmlApplicationContext {
           2 
           3     public LazyInitClasspathXmlApplicationContext(String location) {
           4         super(location);
           5     }
           6 
           7     @Override
           8     protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
           9         // Create a new XmlBeanDefinitionReader for the given BeanFactory.
          10         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
          11 
          12         // Configure the bean definition reader with this context's
          13         // resource loading environment.
          14         beanDefinitionReader.setResourceLoader(this);
          15         beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
          16 
          17         // 添加的代碼,設置LazyInitListener
          18         beanDefinitionReader.setEventListener(new LazyInitListener());
          19 
          20         // Allow a subclass to provide custom initialization of the reader,
          21         // then proceed with actually loading the bean definitions.
          22         initBeanDefinitionReader(beanDefinitionReader);
          23         loadBeanDefinitions(beanDefinitionReader);
          24     }
          25 
          26 }

          演示代碼如下:
          TestBean:一個Spring Bean對象
          public class TestBean {

              
          public void init() {
                  
          try {
                      Thread.sleep(
          5000);
                  } 
          catch (InterruptedException e) {
                      
          //ignore
                      System.out.println(e);
                  }
                  System.out.println(
          "TestBean Init");
              }
          }

          Spring配置文件:
          1 <?xml version="1.0" encoding="UTF-8"?>
          2 <beans xmlns="http://www.springframework.org/schema/beans"
          3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          4     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
          5 
          6     <bean id="testBean" class="com.alibaba.javalab.spring.lazy.TestBean" init-method="init" />
          7 </beans>

          測試代碼:
           1 public class Run {
           2 
           3     private static final String CONFIG = "classpath:spring/bean.xml";
           4 
           5     public static void main(String[] args) {
           6         testInit();
           7         System.out.println("===============================");
           8         testLazyInit();
           9     }
          10 
          11     public static void testInit() {
          12         new ClassPathXmlApplicationContext(CONFIG);
          13     }
          14 
          15     public static void testLazyInit() {
          16         new LazyInitClasspathXmlApplicationContext(CONFIG);
          17     }
          18 }


          大功告成.收工. :)

          posted on 2010-06-03 12:46 stone2083 閱讀(3170) 評論(2)  編輯  收藏 所屬分類: java

          Feedback

          # re: 編程方式實現SpringBean LazyInit 2010-06-19 01:11 stone2083

          今天又細看了代碼,發現覆寫
          AbstractXmlApplicationContext.initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) 方法更為合理.  回復  更多評論   

          # re: 編程方式實現SpringBean LazyInit[未登錄] 2010-07-07 15:26 zhao

          你好強?。?nbsp; 回復  更多評論   

          主站蜘蛛池模板: 南充市| 四子王旗| 健康| 丹阳市| 长治县| 南丹县| 福安市| 金阳县| 张家港市| 渭南市| 海兴县| 缙云县| 尼玛县| 阿瓦提县| 嘉祥县| 曲水县| 民乐县| 调兵山市| 罗定市| 金阳县| 上林县| 隆安县| 兴山县| 封开县| 海林市| 翁牛特旗| 宜章县| 莲花县| 南宫市| 从江县| 福鼎市| 汽车| 汉寿县| 鄂尔多斯市| 上蔡县| 丹东市| 湘阴县| 特克斯县| 衡南县| 容城县| 富锦市|