Spring BenPostProcessorと動的ローディングデータソース構成


前言:
      本論文では、Spring動的構成データソースの方法を紹介することを目的として、つまり、1つのDataSourceの構成について、例えば、jdbcUrl、user、password、driver Classは、xml静的構成ではなく、動作時に指定される.
      Spring構造Contextのパラメータは、一般的に構成ファイル経路とクラス加重器のみを含み、動的着信構成パラメータの目的を達成するためには、Springが必要であり、データソース関連beanを初期化する際に、既存の構成に対して修正または置換を実行することができ、便宜上処理するために、本明細書ではDynamicDataSourceConfigHolderというパブリッククラスを定義します.
       本明細書では、データソースをc 3 p 0に置き換えて構成する.
BeanPostProcessor概要:
      Spring BenPostProcessorは、一般的にSpring Bernフィードバックプロセッサと呼ばれるが、一般的には、1つのbeanを実装する前と後のいくつかの付加的な動作を増加させるために使用され、グローバルなSpring bean構成に効果がある.
Spring Beanのライフサイクル処理:
      Spring Bernライフサイクルは、通常は2つの処理に対応しており、一つはinit-method&destroy-method、もう一つはInitializingBenのafterPropertiesset()方法とDispacBenのdestroy()方法であり、BenPostProcessorの出現によってバッチSpring beanが定義される可能性がある.
BeanPostProcessor定義:
 1 /**
 2  * Factory hook that allows for custom modification of new bean instances,
 3  * e.g. checking for marker interfaces or wrapping them with proxies.
 4  *
 5  * <p>ApplicationContexts can autodetect BeanPostProcessor beans in their
 6  * bean definitions and apply them to any beans subsequently created.
 7  * Plain bean factories allow for programmatic registration of post-processors,
 8  * applying to all beans created through this factory.
 9  *
10  * <p>Typically, post-processors that populate beans via marker interfaces
11  * or the like will implement {@link #postProcessBeforeInitialization},
12  * while post-processors that wrap beans with proxies will normally
13  * implement {@link #postProcessAfterInitialization}.
14  *
15  * @author Juergen Hoeller
16  * @since 10.10.2003
17  * @see InstantiationAwareBeanPostProcessor
18  * @see DestructionAwareBeanPostProcessor
19  * @see ConfigurableBeanFactory#addBeanPostProcessor
20  * @see BeanFactoryPostProcessor
21  */
22 public interface BeanPostProcessor {
23 
24     /**
25      * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
26      * initialization callbacks (like InitializingBean's <code>afterPropertiesSet</code>
27      * or a custom init-method). The bean will already be populated with property values.
28      * The returned bean instance may be a wrapper around the original.
29      * @param bean the new bean instance
30      * @param beanName the name of the bean
31      * @return the bean instance to use, either the original or a wrapped one; if
32      * <code>null</code>, no subsequent BeanPostProcessors will be invoked
33      * @throws org.springframework.beans.BeansException in case of errors
34      * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
35      */
36     Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
37 
38     /**
39      * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
40      * initialization callbacks (like InitializingBean's <code>afterPropertiesSet</code>
41      * or a custom init-method). The bean will already be populated with property values.
42      * The returned bean instance may be a wrapper around the original.
43      * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
44      * instance and the objects created by the FactoryBean (as of Spring 2.0). The
45      * post-processor can decide whether to apply to either the FactoryBean or created
46      * objects or both through corresponding <code>bean instanceof FactoryBean</code> checks.
47      * <p>This callback will also be invoked after a short-circuiting triggered by a
48      * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
49      * in contrast to all other BeanPostProcessor callbacks.
50      * @param bean the new bean instance
51      * @param beanName the name of the bean
52      * @return the bean instance to use, either the original or a wrapped one; if
53      * <code>null</code>, no subsequent BeanPostProcessors will be invoked
54      * @throws org.springframework.beans.BeansException in case of errors
55      * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
56      * @see org.springframework.beans.factory.FactoryBean
57      */
58     Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
59 
60 }
   以上はSpringソースコードです.Spring bean初期化との関係、すなわちpostProcess BeforeInitializationはSpringでbean初期化フックを実行する前に呼び出されます.
DynamicData SourceConfigHolder:
 1 package org.wit.ff;
 2 
 3 import java.util.Map;
 4 
 5 /**
 6  *          .
 7  * @author ff
 8  *
 9  */
10 public class DynamicDataSourceConfigHolder {
11     
12     /**
13      *       ,      Spring Context           ,      。
14      */
15     private static final ThreadLocal<Map<String,String>> dynamicDataSourceConfigHolder = new ThreadLocal<Map<String,String>>();
16     
17     public static void setDynamicConfig(Map<String,String> dynamicDataSourceConfig) {
18         dynamicDataSourceConfigHolder.set(dynamicDataSourceConfig);
19     }
20 
21     public static Map<String,String> getDynamicDataSourceConfig() {
22         return (dynamicDataSourceConfigHolder.get());
23     }
24 
25     public static void clear() {
26         dynamicDataSourceConfigHolder.remove();
27     }
28 
29 }
データソース設定ファイル:
1 db.driverClass=****
2 db.jdbcUrl=****
3 db.user=****
4 db.password=****
カスタムbeanコールバックプロセッサ:
 1 package org.wit.ff;
 2 
 3 import java.lang.reflect.Method;
 4 import java.util.HashMap;
 5 import java.util.Map;
 6 
 7 import org.springframework.beans.BeansException;
 8 import org.springframework.beans.factory.config.BeanPostProcessor;
 9 import org.springframework.util.ReflectionUtils;
10 
11 import com.mchange.v2.c3p0.ComboPooledDataSource;
12 
13 /**
14  * Bean     .
15  * @author ff
16  *
17  */
18 public class ComboPooledDataSourceBeanPostProcessor implements BeanPostProcessor {
19 
20     private String dataSourceName;
21 
22     @Override
23     public Object postProcessAfterInitialization(Object bean, String paramString) throws BeansException {
24         return bean;
25     }
26 
27     @Override
28     public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
29         //           .
30         if (bean instanceof ComboPooledDataSource && dataSourceName.equals(beanName)) {
31             final Map<String,String> methodMatchField = new HashMap<String,String>();
32             methodMatchField.put("setDriverClass", "db.driverClass");
33             methodMatchField.put("setJdbcUrl", "db.jdbcUrl");
34             methodMatchField.put("setUser", "db.user");
35             methodMatchField.put("setPassword", "db.password");
36             //          .
37             final Map<String, String> config = DynamicDataSourceConfigHolder.getDynamicDataSourceConfig();
38             ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
39                 @Override
40                 public void doWith(Method paramMethod) throws IllegalArgumentException, IllegalAccessException {
41                     if(methodMatchField.containsKey(paramMethod.getName())){
42                         ReflectionUtils.invokeMethod(paramMethod, bean, config.get(methodMatchField.get(paramMethod.getName())));
43                     }
44                 }
45             });
46         }
47         return bean;
48     }
49 
50     public void setDataSourceName(String dataSourceName) {
51         this.dataSourceName = dataSourceName;
52     }
53 
54 }


SpringプロファイルdynamicDatasource/appication Contact.xml:
 1  <!--   properties     -->
 2     <bean id="propertyConfigurer"
 3         class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
 4         <property name="locations">
 5             <list>
 6                 <!--           :classpath file -->
 7                 <value>classpath:dynamicDatasource/dbconfig.properties</value>
 8             </list>
 9         </property>
10     </bean>
11     <!--      .-->
12     <bean id="dynamicDataSourceBp" class="org.wit.ff.ComboPooledDataSourceBeanPostProcessor" >
13         <property name="dataSourceName" value="dataSource" />
14     </bean>
15 
16     <!--        -->
17     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
18         destroy-method="close">
19         <property name="driverClass" value="${db.driverClass}" />
20         <property name="jdbcUrl" value="${db.jdbcUrl}" />
21         <property name="user" value="${db.user}" />
22         <property name="password" value="${db.password}" />
23     </bean>
24     


テストの例:
 1 Map<String,String> dynamicDataSourceConfig = new HashMap<String,String>();
 2 dynamicDataSourceConfig.put("db.driverClass", "com.mysql.jdbc.Driver");
 3 dynamicDataSourceConfig.put("db.jdbcUrl", "jdbc:mysql://127.0.0.1:3306/menlo3?autoReconnect=true&characterEncoding=utf-8");
 4 dynamicDataSourceConfig.put("db.user", "root");
 5 dynamicDataSourceConfig.put("db.password", "root");
 6 DynamicDataSourceConfigHolder.setDynamicConfig(dynamicDataSourceConfig);
 7 ApplicationContext applicationContext = new ClassPathXmlApplicationContext(new String[]{"classpath:dynamicDatasource/applicationContext.xml"});
 8 
 9 //                .
10 
11 assertNotNull(applicationContext);