`

不重复配置——利用Spring通用化配置

阅读更多
还记得 如下这种配置吗:

 

1、struts2作用域:每一个Action我们必须设置scope为prototype   每次都做重复的配置,而且有时候忘记配置还会出现bug,想不想删掉它?

 

<bean id="**Action" class="***Action" scope="prototype">

 

2、在使用spring集成hibernate时,每次都必须注入sessionFactory,虽然可以用父子bean解决 但还是要写parent="abstractHibernateDao"之类的。

<bean id="***Dao" class="***DaoImpl">

    <property name="sessionFactory" ref="sessionFactory">

</bean>

 

受够了这种配置,得想法解决这个重复配置,怎么解决呢?

 

思路:

在BeanFactory创建Bean之前查找所有我们需要通用化配置的Bean 然后修改BeanDefinition注入我们的通用数据就可以解决我们这个问题。

 

Spring提供了BeanFactoryPostProcessor扩展点,用于提供给我们修改BeanDefinition数据的。

 

还记得org.springframework.beans.factory.config.PropertyPlaceholderConfigurer吗? 替换占位符数据,它就是一个BeanFactoryPostProcessor的实现。

 

好了思路有了,接下来我们实现一下吧:

1、XML配置方式

 

 * 

 * 使用方法:<br/>

 * <pre>

 *  <bean class="cn.javass.common.spring.CommonConfigureProcessor">

       <property name="config">

            <map>

               <!--  aspectj表达式 选择所有Action结尾的Bean 注入scope数据 为 prototype  -->

               <entry key="cn.javass..*Action">

                   <props>

                       <prop key="scope">prototype</prop>

                   </props>

               </entry>

               <!-- aspectj表达式 选择所有的HibernateDaoSupport实现Bean 注入sessionFactory -->

               <entry key="org.springframework.orm.hibernate3.support.HibernateDaoSupport+">

                  <props>

                     <prop key="property-ref">sessionFactory=sessionFactory</prop>

                  </props>

               </entry>

            </map>          

       </property>

   </bean>

 * </pre>

 * 

 * 目前支持三种配置:

 *  scope:注入作用域

 *  property-ref:注入Bean引用 如之上的sessionFactory

 *     propertyName=beanName

 *  property-value:注入常量值

 *     propertyName=常量

 

2、CommonConfigureProcessor源码

 

Java代码 复制代码 收藏代码
  1. package cn.javass.common.spring;   
  2.   
  3. import java.util.ArrayList;   
  4. import java.util.HashMap;   
  5. import java.util.List;   
  6. import java.util.Map;   
  7. import java.util.Map.Entry;   
  8. import java.util.Properties;   
  9.   
  10. import org.aspectj.bridge.IMessageHandler;   
  11. import org.aspectj.weaver.ResolvedType;   
  12. import org.aspectj.weaver.World;   
  13. import org.aspectj.weaver.bcel.BcelWorld;   
  14. import org.aspectj.weaver.patterns.Bindings;   
  15. import org.aspectj.weaver.patterns.FormalBinding;   
  16. import org.aspectj.weaver.patterns.IScope;   
  17. import org.aspectj.weaver.patterns.PatternParser;   
  18. import org.aspectj.weaver.patterns.SimpleScope;   
  19. import org.aspectj.weaver.patterns.TypePattern;   
  20. import org.slf4j.Logger;   
  21. import org.slf4j.LoggerFactory;   
  22. import org.springframework.beans.BeansException;   
  23. import org.springframework.beans.factory.config.BeanDefinition;   
  24. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;   
  25. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;   
  26. import org.springframework.beans.factory.config.RuntimeBeanNameReference;   
  27. import org.springframework.beans.factory.config.RuntimeBeanReference;   
  28. import org.springframework.util.StringUtils;   
  29. /**  
  30.  *   
  31.  * 设置通用配置<br/>  
  32.  *   
  33.  * 使用方法:<br/>  
  34.  * <pre>  
  35.  *  <bean class="cn.javass.common.spring.CommonConfigureProcessor">  
  36.        <property name="config">  
  37.             <map>  
  38.                <!--  aspectj表达式 选择所有Action结尾的Bean 注入scope数据 为 prototype  -->  
  39.                <entry key="cn.javass..*Action">  
  40.                    <props>  
  41.                        <prop key="scope">prototype</prop>  
  42.                    </props>  
  43.                </entry>  
  44.                <!-- aspectj表达式 选择所有的HibernateDaoSupport实现Bean 注入sessionFactory -->  
  45.                <entry key="org.springframework.orm.hibernate3.support.HibernateDaoSupport+">  
  46.                   <props>  
  47.                      <prop key="property-ref">sessionFactory=sessionFactory</prop>  
  48.                   </props>  
  49.                </entry>  
  50.             </map>            
  51.        </property>  
  52.    </bean>  
  53.  * </pre>  
  54.  *   
  55.  * 目前支持三种配置:  
  56.  *  scope:注入作用域  
  57.  *  property-ref:注入Bean引用 如之上的sessionFactory  
  58.  *     propertyName=beanName  
  59.  *  property-value:注入常量值  
  60.  *     propertyName=常量  
  61.  *   
  62.  * @author Zhangkaitao  
  63.  * @version 1.0  
  64.  *  
  65.  */  
  66. public class CommonConfigureProcessor implements BeanFactoryPostProcessor {   
  67.        
  68.     private Logger log = LoggerFactory.getLogger(CommonConfigureProcessor.class);   
  69.   
  70.     private Map<String, Properties> config = new HashMap<String, Properties>();   
  71.     public void setConfig(Map<String, Properties> config) {   
  72.         this.config = config;   
  73.     }   
  74.   
  75.     @Override  
  76.     public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {   
  77.         log.debug("apply common config start");   
  78.         for(Entry<String, Properties> entry : config.entrySet()) {   
  79.             String aspectjPattern = entry.getKey();   
  80.             Properties props = entry.getValue();   
  81.   
  82.             List<BeanDefinition> bdList = findBeanDefinition(aspectjPattern, factory);   
  83.                
  84.             apply(bdList, props);   
  85.         }   
  86.         log.debug("apply common config end");   
  87.     }   
  88.   
  89.   
  90.     private void apply(List<BeanDefinition> bdList, Properties props) {   
  91.         for(Entry<Object, Object> entry : props.entrySet()) {   
  92.             String key = (String) entry.getKey();   
  93.             String value = (String) entry.getValue();   
  94.                
  95.             switch(SupportedConfig.keyToEnum(key)) {   
  96.                 case scope :    
  97.                     applyScope(bdList, value);   
  98.                     break;   
  99.                 case propertyRef:   
  100.                     applyPropertyRef(bdList, value);   
  101.                     break;   
  102.                 case propertyValue:   
  103.                     applyPropertyValue(bdList, value);   
  104.                     break;   
  105.                 default:   
  106.                     throw new IllegalArgumentException(String.format("错误的配置:[%s]", key));   
  107.             }   
  108.                
  109.                
  110.         }   
  111.     }   
  112.   
  113.   
  114.     private void applyPropertyValue(List<BeanDefinition> bdList, String value) {   
  115.         for(BeanDefinition bd : bdList) {   
  116.                
  117.             String propertyName = value.split("=")[0];    
  118.             String propertyValue = value.substring(propertyName.length()+1);   
  119.             bd.getPropertyValues().add(propertyName, propertyValue);   
  120.                
  121.             log.debug("apply property value {} to {}", value, bd.getBeanClassName());   
  122.         }   
  123.     }   
  124.   
  125.     private void applyPropertyRef(List<BeanDefinition> bdList, String value) {   
  126.         for(BeanDefinition bd : bdList) {   
  127.                
  128.             String propertyName = value.split("=")[0];    
  129.             String propertyValue = value.substring(propertyName.length()+1);   
  130.             bd.getPropertyValues().addPropertyValue(propertyName, new RuntimeBeanReference(propertyValue));   
  131.                
  132.             log.debug("apply property ref {} to {}", value, bd.getBeanClassName());   
  133.         }   
  134.     }   
  135.   
  136.     private void applyScope(List<BeanDefinition> bdList, String value) {   
  137.         for(BeanDefinition bd : bdList) {   
  138.             bd.setScope(value);   
  139.             log.debug("apply scope {} to {}", value, bd.getBeanClassName());   
  140.         }   
  141.     }   
  142.   
  143.     private List<BeanDefinition> findBeanDefinition(String aspectjPattern, ConfigurableListableBeanFactory factory) {   
  144.         List<BeanDefinition> bdList = new ArrayList<BeanDefinition>();   
  145.            
  146.         for(String beanName : factory.getBeanDefinitionNames()) {   
  147.             BeanDefinition bd = factory.getBeanDefinition(beanName);   
  148.                
  149.             if(matches(aspectjPattern, bd.getBeanClassName())) {   
  150.                 bdList.add(bd);   
  151.             }   
  152.                
  153.         }   
  154.            
  155.         return bdList;   
  156.     }   
  157.   
  158.        
  159.     private boolean matches(String aspectjPattern, String beanClassName) {   
  160.         if(!StringUtils.hasLength(beanClassName)) {   
  161.             return false;   
  162.         }   
  163.         return new AspectJTypeMatcher(aspectjPattern).matches(beanClassName);   
  164.     }   
  165.        
  166.     //支持的操作   
  167.     private static enum SupportedConfig {   
  168.         scope("scope"),    
  169.         propertyRef("property-ref"),   
  170.         propertyValue("property-value"),   
  171.            
  172.         error("error"); //出错的情况   
  173.   
  174.         private final String key;   
  175.         private SupportedConfig(String key) {   
  176.             this.key = key;   
  177.         }   
  178.            
  179.         public static SupportedConfig keyToEnum(String key) {   
  180.             if(key == null) {   
  181.                 return error;   
  182.             }   
  183.             for(SupportedConfig config : SupportedConfig.values()) {   
  184.                 if(config.key.equals(key.trim())) {   
  185.                     return config;   
  186.                 }   
  187.             }   
  188.             return error;   
  189.         }   
  190.            
  191.     }   
  192.        
  193.        
  194.     public static interface TypeMatcher {   
  195.         public boolean matches(String className);   
  196.     }   
  197.        
  198.     static class AspectJTypeMatcher implements TypeMatcher {   
  199.         private final World world;   
  200.         private final TypePattern typePattern;   
  201.            
  202.         public AspectJTypeMatcher(String pattern) {   
  203.             
  204.             this.world = new BcelWorld(Thread.currentThread().getContextClassLoader(), IMessageHandler.THROW, null);   
  205.             this.world.setBehaveInJava5Way(true);   
  206.             PatternParser patternParser = new PatternParser(pattern);   
  207.             TypePattern typePattern = patternParser.parseTypePattern();   
  208.             typePattern.resolve(this.world);   
  209.             IScope scope = new SimpleScope(this.world, new FormalBinding[0]);   
  210.             this.typePattern = typePattern.resolveBindings(scope, Bindings.NONE, falsefalse);   
  211.         }   
  212.         @Override  
  213.         public boolean matches(String className) {   
  214.             ResolvedType resolvedType = this.world.resolve(className);   
  215.             return this.typePattern.matchesStatically(resolvedType);   
  216.         }   
  217.     }   
  218.        
  219.     public static void main(String[] args) {   
  220.         //System.out.println(new AspectJTypeMatcher("cn.javass..*Action").matches("cn.javass.test.web.action.AbcAction"));   
  221.         //System.out.println(new AspectJTypeMatcher("com.opensymphony.xwork2.ActionSupport+").matches("cn.javass.erp.web.action.MoneyAction"));   
  222.     }   
  223. }  
package cn.javass.common.spring;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import org.aspectj.bridge.IMessageHandler;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.World;
import org.aspectj.weaver.bcel.BcelWorld;
import org.aspectj.weaver.patterns.Bindings;
import org.aspectj.weaver.patterns.FormalBinding;
import org.aspectj.weaver.patterns.IScope;
import org.aspectj.weaver.patterns.PatternParser;
import org.aspectj.weaver.patterns.SimpleScope;
import org.aspectj.weaver.patterns.TypePattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanNameReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.util.StringUtils;
/**
 * 
 * 设置通用配置<br/>
 * 
 * 使用方法:<br/>
 * <pre>
 *  <bean class="cn.javass.common.spring.CommonConfigureProcessor">
       <property name="config">
            <map>
               <!--  aspectj表达式 选择所有Action结尾的Bean 注入scope数据 为 prototype  -->
               <entry key="cn.javass..*Action">
                   <props>
                       <prop key="scope">prototype</prop>
                   </props>
               </entry>
               <!-- aspectj表达式 选择所有的HibernateDaoSupport实现Bean 注入sessionFactory -->
               <entry key="org.springframework.orm.hibernate3.support.HibernateDaoSupport+">
                  <props>
                     <prop key="property-ref">sessionFactory=sessionFactory</prop>
                  </props>
               </entry>
            </map>          
       </property>
   </bean>
 * </pre>
 * 
 * 目前支持三种配置:
 *  scope:注入作用域
 *  property-ref:注入Bean引用 如之上的sessionFactory
 *     propertyName=beanName
 *  property-value:注入常量值
 *     propertyName=常量
 * 
 * @author Zhangkaitao
 * @version 1.0
 *
 */
public class CommonConfigureProcessor implements BeanFactoryPostProcessor {
    
    private Logger log = LoggerFactory.getLogger(CommonConfigureProcessor.class);

    private Map<String, Properties> config = new HashMap<String, Properties>();
    public void setConfig(Map<String, Properties> config) {
        this.config = config;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
        log.debug("apply common config start");
        for(Entry<String, Properties> entry : config.entrySet()) {
            String aspectjPattern = entry.getKey();
            Properties props = entry.getValue();

            List<BeanDefinition> bdList = findBeanDefinition(aspectjPattern, factory);
            
            apply(bdList, props);
        }
        log.debug("apply common config end");
    }


    private void apply(List<BeanDefinition> bdList, Properties props) {
        for(Entry<Object, Object> entry : props.entrySet()) {
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            
            switch(SupportedConfig.keyToEnum(key)) {
                case scope : 
                    applyScope(bdList, value);
                    break;
                case propertyRef:
                    applyPropertyRef(bdList, value);
                    break;
                case propertyValue:
                    applyPropertyValue(bdList, value);
                    break;
                default:
                    throw new IllegalArgumentException(String.format("错误的配置:[%s]", key));
            }
            
            
        }
    }


    private void applyPropertyValue(List<BeanDefinition> bdList, String value) {
        for(BeanDefinition bd : bdList) {
            
            String propertyName = value.split("=")[0]; 
            String propertyValue = value.substring(propertyName.length()+1);
            bd.getPropertyValues().add(propertyName, propertyValue);
            
            log.debug("apply property value {} to {}", value, bd.getBeanClassName());
        }
    }

    private void applyPropertyRef(List<BeanDefinition> bdList, String value) {
        for(BeanDefinition bd : bdList) {
            
            String propertyName = value.split("=")[0]; 
            String propertyValue = value.substring(propertyName.length()+1);
            bd.getPropertyValues().addPropertyValue(propertyName, new RuntimeBeanReference(propertyValue));
            
            log.debug("apply property ref {} to {}", value, bd.getBeanClassName());
        }
    }

    private void applyScope(List<BeanDefinition> bdList, String value) {
        for(BeanDefinition bd : bdList) {
            bd.setScope(value);
            log.debug("apply scope {} to {}", value, bd.getBeanClassName());
        }
    }

    private List<BeanDefinition> findBeanDefinition(String aspectjPattern, ConfigurableListableBeanFactory factory) {
        List<BeanDefinition> bdList = new ArrayList<BeanDefinition>();
        
        for(String beanName : factory.getBeanDefinitionNames()) {
            BeanDefinition bd = factory.getBeanDefinition(beanName);
            
            if(matches(aspectjPattern, bd.getBeanClassName())) {
                bdList.add(bd);
            }
            
        }
        
        return bdList;
    }

    
    private boolean matches(String aspectjPattern, String beanClassName) {
        if(!StringUtils.hasLength(beanClassName)) {
            return false;
        }
        return new AspectJTypeMatcher(aspectjPattern).matches(beanClassName);
    }
    
    //支持的操作
    private static enum SupportedConfig {
        scope("scope"), 
        propertyRef("property-ref"),
        propertyValue("property-value"),
        
        error("error"); //出错的情况

        private final String key;
        private SupportedConfig(String key) {
            this.key = key;
        }
        
        public static SupportedConfig keyToEnum(String key) {
            if(key == null) {
                return error;
            }
            for(SupportedConfig config : SupportedConfig.values()) {
                if(config.key.equals(key.trim())) {
                    return config;
                }
            }
            return error;
        }
        
    }
    
    
    public static interface TypeMatcher {
        public boolean matches(String className);
    }
    
    static class AspectJTypeMatcher implements TypeMatcher {
        private final World world;
        private final TypePattern typePattern;
        
        public AspectJTypeMatcher(String pattern) {
         
            this.world = new BcelWorld(Thread.currentThread().getContextClassLoader(), IMessageHandler.THROW, null);
            this.world.setBehaveInJava5Way(true);
            PatternParser patternParser = new PatternParser(pattern);
            TypePattern typePattern = patternParser.parseTypePattern();
            typePattern.resolve(this.world);
            IScope scope = new SimpleScope(this.world, new FormalBinding[0]);
            this.typePattern = typePattern.resolveBindings(scope, Bindings.NONE, false, false);
        }
        @Override
        public boolean matches(String className) {
            ResolvedType resolvedType = this.world.resolve(className);
            return this.typePattern.matchesStatically(resolvedType);
        }
    }
    
    public static void main(String[] args) {
        //System.out.println(new AspectJTypeMatcher("cn.javass..*Action").matches("cn.javass.test.web.action.AbcAction"));
        //System.out.println(new AspectJTypeMatcher("com.opensymphony.xwork2.ActionSupport+").matches("cn.javass.erp.web.action.MoneyAction"));
    }
}
 

此类只实现基本的通用配置,欢迎大家提供想法并完善这个工具类。

分享到:
评论

相关推荐

    Spring学习心得(一)

    AOP允许我们将日志、事务管理、安全检查等通用功能作为“切面”独立处理,避免了在多个类中重复编写相同代码。切面通过定义切入点(Pointcut)和通知(Advice)来实现,Spring提供了多种通知类型,如前置通知、后置...

    spring-developing-java-applications-enterprise

    - **容器**:Spring提供了两种类型的容器——BeanFactory和ApplicationContext,它们都实现了工厂模式,用于实例化、定位和配置对象或bean。 - **MVC框架**:Spring提供了一个轻量级的MVC框架,方便快速地开发Web...

    dsf_spring

    通过AOP,我们可以定义横切关注点,如日志记录、事务管理等,将这些通用逻辑抽取出来,避免在每个业务方法中重复编写。Spring AOP支持使用注解和XML配置两种方式定义切面,大大提高了代码的可读性和可维护性。 最后...

    SpringReference2.0RC2.chm

    例如,日志、事务管理等通用功能可以通过切面实现,减少代码重复,提高代码结构清晰度。 3. **IoC容器**:Spring的核心组件,负责管理对象的生命周期和装配。容器读取配置元数据,创建并管理对象,通过依赖注入将...

    spring 手册

    3. **AOP**:面向切面编程允许开发者将关注点分离,例如日志、事务管理等,可以编写一次,然后在整个应用中通用,减少代码重复。 二、Spring MVC 1. **Model-View-Controller**:Spring MVC 是 Spring 框架的一...

    一个工具类搞定 CRUD 的创建人、修改人、时间等字段赋值!(csdn)————程序.pdf

    【知识点详解】 在软件开发中,特别是在企业级应用中,数据管理是一个重要的环节。CRUD(Create, Read, Update, Delete)...使用Spring Boot的AOP特性,我们可以高效地实现这一目标,使得CRUD操作更加智能化和自动化。

    一个简单的Spring-MVC例子.docx

    Spring框架中的AOP(面向方面编程)是其核心特性之一,它是对传统面向对象编程(OOP)的一种补充,用于解决横切关注点的问题,即那些在多个类中重复出现的非核心业务逻辑,如事务管理、日志记录、安全性等。...

    mica(云母)Spring Cloud 微服务开发核心包,支持 web 和 webflux

    **mica:云母——Spring Cloud微服务开发的核心包** mica,取名自云母,是一种在Spring Cloud生态中的微服务开发核心工具集。它为开发者提供了丰富的基础工具类和组件,使得在构建分布式系统时能够更加高效、便捷。...

    code-generator.zip

    此外,对于那些通用但需要特殊处理的部分,开发者可以保留接口不生成具体的实现,留待后期根据业务逻辑自行编写。 在Spring框架中,代码生成工具可以生成Service和Controller层的代码,为服务调用和视图展示提供...

    SHH1 jar 包

    - `spring-aop.jar`:此文件包含了Spring的AOP模块,提供了面向切面的编程实现,允许开发者在不修改源代码的情况下,对方法进行拦截和增强,如日志记录、事务管理等。 - `spring-context.jar`:这是Spring框架的...

    templates:一组通用模板,以避免记住无用的配置设置

    本主题主要关注的是“templates”——一组用于避免记忆大量无用配置设置的通用模板,尤其与Java编程语言相关。 标题“templates:一组通用模板,以避免记住无用的配置设置”揭示了这个资源的核心价值。这里的...

    SSM企业级开发框架,自动生成代码!仅限于学习,不要用于商业用途!

    SSM企业级开发框架是Java领域中常用的三大框架——Spring、SpringMVC和MyBatis的集成,广泛应用于Web应用的开发。这个压缩包提供的内容是基于MySQL数据库的SSM框架实现,适用于学习和理解企业级开发流程。下面将详细...

    holaspring

    通过定义切面、通知和切入点,我们可以将这些通用功能模块化,减少代码重复,提高代码质量。 五、数据访问集成 Spring提供了对各种数据库访问技术的支持,如JDBC、Hibernate、MyBatis等。在“holaspring”项目中,...

    java高级面试框架整理

    - **BeanFactory与ApplicationContext:** Spring提供了两个核心接口——BeanFactory和ApplicationContext,前者是最基础的工厂接口,后者提供了更丰富的应用上下文环境。 **2. Spring的IoC容器** - **Bean的生命...

    java开源框架的集合

    - **数据访问抽象**:Spring提供了一种通用的数据访问抽象层,包括高效且易于使用的JDBC框架,极大地提高了数据库操作的效率并减少了潜在的错误。此外,Spring的数据访问框架还集成了Hibernate等其他对象关系映射...

    javaStudy.rar

    封装可以提高代码的复用性,例如创建一个BaseController,提供通用的方法如结果集返回、参数校验等,其他Controller可以继承这个基类,减少重复代码。 3. **异常处理**:SpringBoot提供了全局异常处理机制,可以...

    java 框架总结

    1. **减少代码开发量**:框架能够通过一系列预定义的功能模块和通用的设计模式,减少开发者编写重复代码的工作量。 2. **注重流程处理**:框架提供了一套标准化的操作流程,帮助开发者遵循最佳实践,从而提高软件的...

    2023年Java Web应用开发中级复习课-理论题.pdf

    这样既可以利用`List`接口提供的通用方法,又可以利用`ArrayList`的具体实现细节。 #### 4. MVC 模式中控制器的作用 **题目**: MVC模式中,控制器的作用是? - **选项**: - A: 从模型中获取数据并指定这些数据...

    redis学习笔记+练习springboot-redisdemo

    这些数据类型为各种应用场景提供了基础,例如,使用字符串存储用户信息,哈希存储对象,列表实现消息队列,集合存储不重复元素,有序集合则可用于排行榜等需求。 2. **持久化机制**:Redis提供了两种主要的持久化...

Global site tag (gtag.js) - Google Analytics