非J2EE 容器环境下Spring +JPA 多持久化单元/多个JAR归档注解实体 的实体扫描问题及解决办法

非J2EE 容器环境下Spring +JPA 多持久化单元/多个JAR归档注解实体 的实体扫描问题及解决办法

关键字: jpa jar归档实体

     模块化的开发在复杂的项目中是非常普通的事,在我们的项目中使用了Spring+JPA架构,最终产品可能部署于不同的容器中,但在部署到非J2EE环境 下时,如部署到Tomcat中,运环境是J2SE时,分别按模块打包在不同JAR中的JPA的注解实体却出现了不能自动识别并添加到 EntityManagerFactory所管辖的持久化单元中的问题,这些JAR中的注解实体类分属不同的通用功能模块并可以在不同的项目中重用,但由 于各个JAR是在不同项目中累积的通用实体库,其中的persistence.xml配置也千差万别.而Spring 的JPA支持并不是那么完美,看过Spring源代码的人都知道,一个LocalContainerEntityManagerFactoryBean只 能管理一个持久化单元,尽管其内部创建的DefaultPersistenceUnitManager类可以读取多个持久化单元信息 (PersistenceUnitInfo),但最终只能有一个被返回给LocalContainerEntityManagerFactoryBean 用于创建JPA实现提供者的EntityManagerFactory,并不像网上搜索到的资料或那些破烂书籍所说的那样能真正支持多个持久化单元(我以 前没有看spirng源代码时就被误导了,害人不浅!!)。关于这个问题,官方文档说的也是很含糊、官方论坛里虽然也有一两个解决办法、但都不完美。


第一种是 :通过DefaultPersistenceUnitManager提供的设置PersistenceUnitPostProcessor接口实现类,传 入DefaultPersistenceUnitManager扫描到的classpath中所有persistence.xml最终得到的对应 PersistenceUnitInfo,并赶在将这些PersistenceUnitInfo其中一个(只能一个,而且是第一个扫描到的)返回给 LocalContainerEntityManagerFactoryBean之前修改各个对应persistence.xml的 PersistenceUnitInfo中的配置,从而将各个persistence.xml中配置的实体类合并成一个 PersistenceUnitInfo并最终返回给LocalContainerEntityManagerFactoryBean用以创建 EntityManagerFactory。

Java代码
  1. //PersistenceUnitPostProcessor实现类,用于修改PersistenceUnitManager读取到的各个对应persistence.xml产生的PersistenceUnitInfo   
  2.   
  3. package  com.yotexs.config.persist.jpa;  
  4.   
  5. import  java.util.ArrayList;  
  6. import  java.util.HashMap;  
  7. import  java.util.List;  
  8. import  java.util.Map;  
  9.   
  10. import  org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;  
  11. import  org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;  
  12.   
  13. /**  
  14.  * 合并多个JAR中的JPA实体到一个持久化单元  
  15.  * <p>  
  16.  * This merges all JPA entities from multiple jars. To use it, all entities must be listed in their respective  
  17.  * persistence.xml files using the <class> tag.  
  18.  *   
  19.  * @see http://forum.springsource.org/showthread.php?t=61763 a  
  20.  * @see http://javathoughts.capesugarbird.com/2009/02/jpa-and-multiple-persistence -units.html b  
  21.  */   
  22. public   class  MergingPersistenceUnitPostProcessor  implements  PersistenceUnitPostProcessor {  
  23.     Map<String, List<String>> puiClasses = new  HashMap<String, List<String>>();  
  24.   
  25.     public  MergingPersistenceUnitPostProcessor() {  
  26.   
  27.     }  
  28.   
  29.     public   void  postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {  
  30.         List<String> classes = puiClasses.get(pui.getPersistenceUnitName());  
  31.         if  (classes ==  null ) {  
  32.             classes = new  ArrayList<String>();  
  33.             puiClasses.put(pui.getPersistenceUnitName(), classes);  
  34.         }  
  35.         pui.getManagedClassNames().addAll(classes);  
  36.   
  37.         final  List<String> names = pui.getManagedClassNames();  
  38.         classes.addAll(names);  
  39.   
  40.         System.out.println("---------------------------------------------------------------" );  
  41.         System.out.println(pui.getPersistenceUnitName());  
  42.         System.out.println(pui);  
  43.         for  (String cn : names) {  
  44.             System.out.println(cn);  
  45.         }  
  46.   
  47.         System.out.println("---------------------------------------------------------------" );  
  48.     }  
  49.   
  50.     public   void  scanEntity() {  
  51.   
  52.     }  
  53. }  
//PersistenceUnitPostProcessor实现类,用于修改PersistenceUnitManager读取到的各个对应persistence.xml产生的PersistenceUnitInfo

package com.yotexs.config.persist.jpa;

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

import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;

/**
 * 合并多个JAR中的JPA实体到一个持久化单元
 * <p>
 * This merges all JPA entities from multiple jars. To use it, all entities must be listed in their respective
 * persistence.xml files using the <class> tag.
 * 
 * @see http://forum.springsource.org/showthread.php?t=61763 a
 * @see http://javathoughts.capesugarbird.com/2009/02/jpa-and-multiple-persistence -units.html b
 */
public class MergingPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
    Map<String, List<String>> puiClasses = new HashMap<String, List<String>>();

    public MergingPersistenceUnitPostProcessor() {

    }

    public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
        List<String> classes = puiClasses.get(pui.getPersistenceUnitName());
        if (classes == null) {
            classes = new ArrayList<String>();
            puiClasses.put(pui.getPersistenceUnitName(), classes);
        }
        pui.getManagedClassNames().addAll(classes);

        final List<String> names = pui.getManagedClassNames();
        classes.addAll(names);

        System.out.println("---------------------------------------------------------------");
        System.out.println(pui.getPersistenceUnitName());
        System.out.println(pui);
        for (String cn : names) {
            System.out.println(cn);
        }

        System.out.println("---------------------------------------------------------------");
    }

    public void scanEntity() {

    }
}
 
Xml代码
  1. < bean   id = "entityManagerFactory"   class = "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >   
  2.     < property   name = "persistenceUnitName"   value = "${jpa.persistenceUnitName}"   />   
  3.     < property   name = "jpaVendorAdapter"   ref = "jpaVendorAdapter"   />   
  4.     < property   name = "jpaProperties"   ref = "jpaProviderProperties"   />   
  5.     < property   name = "persistenceUnitPostProcessors"   >   
  6.         < util:list >   
  7.                < bean   class = "com.yotexs.config.persist.jpa.MergingPersistenceUnitPostProcessor"   />   
  8.         </ util:list >   
  9.     </ property >   
  10. </ bean >   

 

第二种做法是 :BeanPostProcessor监察LocalContainerEntityManagerFactoryBean,在其完成容器初始发前修改其 内部的DefaultPersistenceUnitManager返回的哪一个PersistenceUnitInfo中注册的实体信息

Java代码
  1. package  com.yotexs.config.persist.jpa;  
  2.   
  3. import  java.util.List;  
  4. import  java.util.Set;  
  5.   
  6. import  javax.persistence.Entity;  
  7. import  javax.persistence.spi.PersistenceUnitInfo;  
  8.   
  9. import  org.springframework.beans.BeansException;  
  10. import  org.springframework.beans.factory.config.BeanPostProcessor;  
  11. import  org.springframework.core.type.classreading.MetadataReader;  
  12. import  org.springframework.core.type.filter.AnnotationTypeFilter;  
  13. import  org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;  
  14.   
  15. import  com.yotexs.util.ClassPathScaner;  
  16. import  com.yotexs.util.ReflectionUtils;  
  17.   
  18. /**  
  19.  * @author bencmai  
  20.  */   
  21. public   class  PersistenceClassesConfigProcessor  implements  BeanPostProcessor {  
  22.     private   static   final  String ENTITY_MANAGER_FACTORY =  "entityManagerFactory" ;  
  23.     String                      entityManagerFactory   = ENTITY_MANAGER_FACTORY;  
  24.     private  String[]            entityClassNames;  
  25.   
  26.     public  PersistenceClassesConfigProcessor() {  
  27.   
  28.     }  
  29.   
  30.     public  String[] getEntityClassNames() {  
  31.         if  (entityClassNames ==  null  || entityClassNames.length <  1 ) { // 配置中没有指定添加到持久化单元的实体时进行自动扫描   
  32.             ClassPathScaner p = new  ClassPathScaner();  
  33.             p.addIncludeFilter(new  AnnotationTypeFilter(Entity. class ));  
  34.             Set<MetadataReader> entitys = p.findCandidateClasss("com.yotexs.model" );  
  35.             entityClassNames = new  String[entitys.size()];  
  36.             int  i =  0 ;  
  37.             for  (MetadataReader entity : entitys) {  
  38.                 entityClassNames[i++] = entity.getClassMetadata().getClassName();  
  39.             }  
  40.         }  
  41.         return  entityClassNames;  
  42.     }  
  43.   
  44.     public   void  setEntityClassNames(String[] entityClassNames) {  
  45.         this .entityClassNames = entityClassNames;  
  46.   
  47.     }  
  48.   
  49.     public   void  setBeanNameOfEntityManagerFactory(String entityManagerFactory) {  
  50.         this .entityManagerFactory = entityManagerFactory;  
  51.     }  
  52.   
  53.     @Override   
  54.     public  Object postProcessAfterInitialization(Object bean, String beanName)  throws  BeansException {  
  55.         return  bean;  
  56.     }  
  57.   
  58.     @Override   
  59.     public  Object postProcessBeforeInitialization(Object bean, String beanName)  throws  BeansException {  
  60.         if  (beanName.equals(entityManagerFactory) && bean  instanceof  LocalContainerEntityManagerFactoryBean) {  
  61.             LocalContainerEntityManagerFactoryBean unitManager = (LocalContainerEntityManagerFactoryBean) bean;  
  62.             PersistenceUnitInfo puf = (PersistenceUnitInfo) ReflectionUtils.getFieldValue(unitManager, "persistenceUnitInfo" );  
  63.             List<String> managedClass = puf.getManagedClassNames();  
  64.             managedClass.clear();  
  65.             for  (String entityClassName : getEntityClassNames()) {  
  66.                 if  (!(managedClass.contains(entityClassName))) {  
  67.                     managedClass.add(entityClassName);// 加入额外的持久化类   
  68.                 }  
  69.             }  
  70.         }  
  71.         return  bean;  
  72.     }  
  73. }  
package com.yotexs.config.persist.jpa;

import java.util.List;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.spi.PersistenceUnitInfo;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

import com.yotexs.util.ClassPathScaner;
import com.yotexs.util.ReflectionUtils;

/**
 * @author bencmai
 */
public class PersistenceClassesConfigProcessor implements BeanPostProcessor {
    private static final String ENTITY_MANAGER_FACTORY = "entityManagerFactory";
    String                      entityManagerFactory   = ENTITY_MANAGER_FACTORY;
    private String[]            entityClassNames;

    public PersistenceClassesConfigProcessor() {

    }

    public String[] getEntityClassNames() {
        if (entityClassNames == null || entityClassNames.length < 1) {// 配置中没有指定添加到持久化单元的实体时进行自动扫描
            ClassPathScaner p = new ClassPathScaner();
            p.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
            Set<MetadataReader> entitys = p.findCandidateClasss("com.yotexs.model");
            entityClassNames = new String[entitys.size()];
            int i = 0;
            for (MetadataReader entity : entitys) {
                entityClassNames[i++] = entity.getClassMetadata().getClassName();
            }
        }
        return entityClassNames;
    }

    public void setEntityClassNames(String[] entityClassNames) {
        this.entityClassNames = entityClassNames;

    }

    public void setBeanNameOfEntityManagerFactory(String entityManagerFactory) {
        this.entityManagerFactory = entityManagerFactory;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals(entityManagerFactory) && bean instanceof LocalContainerEntityManagerFactoryBean) {
            LocalContainerEntityManagerFactoryBean unitManager = (LocalContainerEntityManagerFactoryBean) bean;
            PersistenceUnitInfo puf = (PersistenceUnitInfo) ReflectionUtils.getFieldValue(unitManager, "persistenceUnitInfo");
            List<String> managedClass = puf.getManagedClassNames();
            managedClass.clear();
            for (String entityClassName : getEntityClassNames()) {
                if (!(managedClass.contains(entityClassName))) {
                    managedClass.add(entityClassName);// 加入额外的持久化类
                }
            }
        }
        return bean;
    }
}
 
Xml代码
  1. 用法:  
  2. 第一步  
  3.   
  4.  < bean   id = "entityManagerFactory"   class = "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >   
  5.          < property   name = "persistenceUnitManager"   ref = "persistenceUnitManager" />   
  6.          < property   name = "dataSource"   ref = "dataSource" />   
  7.          < property   name = "jpaVendorAdapter" >   
  8.              < bean   class = "org.springframework.orm.jpa.vendor.RedSoftJpaVendorAdapter" >   
  9.              </ bean >   
  10.          </ property >   
  11.      </ bean >   
  12.    
  13.      < bean   id = "persistenceUnitManager"   class = "org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager" >   
  14.          < property   name = "persistenceXmlLocations" >   
  15.              < list >   
  16.                  < value > classpath*:/redsoft_jpa_persistence.xml </ value >   
  17.              </ list >   
  18.          </ property >   
  19.      </ bean >   
  20.    
  21.   
  22. 第二步  
  23.   
  24.  < import   resource = "classpath*:/ormContext.xml" />   
  25.    
  26.      < bean   id = "entityClasses"   class = "com.abest.util.PersistenceClassesConfigProcessor" >   
  27.          < property   name = "entityClassNames" >   
  28.              < list >   
  29.                  < value > com.abest.common.dao.TestBean </ value >   
  30.                  < value > com.abest.uwin.baseinfo.domain.Region </ value >   
  31.                  < value > com.abest.uwin.baseinfo.domain.Brand </ value >   
  32.                  < value > com.abest.uwin.baseinfo.domain.MeasureUnit </ value >   
  33.                  < value > com.abest.uwin.baseinfo.domain.ProductionFactory </ value >   
  34.                  < value > com.abest.uwin.baseinfo.domain.MaterialType </ value >   
  35.              </ list >   
  36.          </ property >   
  37.      </ bean >   

 

上面两种做法(仅做演示,在你的环境中不一定通过)在一定程度上可以解决问题,但使用上还是相对麻烦而且有一定的限制,且使用起来不灵活,在我自己的实现中,

 

我使用了按指定的包名豆单列表扫描classpath的JAR的办法 (实际上我做了另外的两种实现,一种是仿照Hibernate的Ejb3Configration的JAR包扫描,这种实现虽然方便和通用,但较为复杂, 另一种是仿照spring的ClassPathScanningCandidateComponentProvider扫描@Component的办法, 简单通用,这里以后者为例)

 

Java代码
  1. package  com.yotexs.util;  
  2.   
  3. import  java.io.IOException;  
  4. import  java.util.Arrays;  
  5. import  java.util.LinkedHashSet;  
  6. import  java.util.LinkedList;  
  7. import  java.util.List;  
  8. import  java.util.Set;  
  9.   
  10. import  javax.persistence.Entity;  
  11.   
  12. import  org.slf4j.Logger;  
  13. import  org.slf4j.LoggerFactory;  
  14. import  org.springframework.core.io.Resource;  
  15. import  org.springframework.core.io.support.PathMatchingResourcePatternResolver;  
  16. import  org.springframework.core.io.support.ResourcePatternResolver;  
  17. import  org.springframework.core.type.classreading.CachingMetadataReaderFactory;  
  18. import  org.springframework.core.type.classreading.MetadataReader;  
  19. import  org.springframework.core.type.classreading.MetadataReaderFactory;  
  20. import  org.springframework.core.type.filter.AnnotationTypeFilter;  
  21. import  org.springframework.core.type.filter.TypeFilter;  
  22. import  org.springframework.util.ClassUtils;  
  23. import  org.springframework.util.SystemPropertyUtils;  
  24.   
  25. /**  
  26.  * 类或资源扫描器,可以批量过滤CLASSPATH路径和JAR中的任意内容  
  27.  * <p>  
  28.  * This implementation is based on Spring's {@link org.springframework.core.type.classreading.MetadataReader  
  29.  * MetadataReader} facility, backed by an ASM {@link org.springframework.asm.ClassReader ClassReader}.  
  30.  *   
  31.  * @author bencmai  
  32.  * @see org.springframework.core.type.classreading.MetadataReaderFactory  
  33.  * @see org.springframework.core.type.AnnotationMetadata  
  34.  */   
  35. public   class  ClassPathScaner {  
  36.     protected   final  Logger logger = LoggerFactory.getLogger(getClass());  
  37.   
  38.     private   static   final  String     DEFAULT_RESOURCE_PATTERN =  "**/*.class" ;  
  39.     private  ResourcePatternResolver resourcePatternResolver  =  new  PathMatchingResourcePatternResolver();  
  40.     private  MetadataReaderFactory   metadataReaderFactory    =  new  CachingMetadataReaderFactory( this .resourcePatternResolver);  
  41.     private  String                  resourcePattern          = DEFAULT_RESOURCE_PATTERN;  
  42.     private   final  List<TypeFilter>  includeFilters           =  new  LinkedList<TypeFilter>();  
  43.     private   final  List<TypeFilter>  excludeFilters           =  new  LinkedList<TypeFilter>();  
  44.   
  45.     /** Add an include type filter to the <i>end</i> of the inclusion list. */  
  46.     public   void  addIncludeFilter(TypeFilter includeFilter) {  
  47.         this .includeFilters.add(includeFilter);  
  48.     }  
  49.   
  50.     /** Add an exclude type filter to the <i>front</i> of the exclusion list. */   
  51.     public   void  addExcludeFilter(TypeFilter excludeFilter) {  
  52.         this .excludeFilters.add( 0 , excludeFilter);  
  53.     }  
  54.   
  55.     /** Reset the configured type filters. */   
  56.     public   void  resetFilters() {  
  57.         this .includeFilters.clear();  
  58.         this .excludeFilters.clear();  
  59.     }  
  60.   
  61.     /**  
  62.      * 将.包路径解释为/路径 <br>  
  63.      * Resolve the specified base package into a pattern specification for the package search path.  
  64.      * <p>  
  65.      * The default implementation resolves placeholders against system properties, and converts a "."-based package path  
  66.      * to a "/"-based resource path.  
  67.      *   
  68.      * @param basePackage the base package as specified by the user  
  69.      * @return the pattern specification to be used for package searching  
  70.      */   
  71.     public  String packageToRelativedPath(String basePackage) {  
  72.         return  ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));  
  73.     }  
  74.   
  75.     /**  
  76.      * 和配置的排除过滤器和包含过滤器进行匹配过滤<br>  
  77.      * Determine whether the given class does not match any exclude filter and does match at least one include filter.  
  78.      *   
  79.      * @param metadataReader the ASM ClassReader for the class  
  80.      * @return whether the class qualifies as a candidate component  
  81.      */   
  82.     protected   boolean  isCandidateComponent(MetadataReader metadataReader)  throws  IOException {  
  83.         for  (TypeFilter tf :  this .excludeFilters) {  
  84.             if  (tf.match(metadataReader,  this .metadataReaderFactory)) {  return   false ; }  
  85.         }  
  86.         for  (TypeFilter tf :  this .includeFilters) {  
  87.             if  (tf.match(metadataReader,  this .metadataReaderFactory)) {  return   true ; }  
  88.         }  
  89.         return   false ;  
  90.     }  
  91.   
  92.     /**  
  93.      * 扫描类路径并根据过滤器以找出合条件的类元数据<br>  
  94.      * <p>  
  95.      * 注:如果包是空白字符,只能扫描到非JAR中的内容  
  96.      *   
  97.      * <pre>  
  98.      * ClassPathScaner p = new ClassPathScaner();  
  99.      * // p.addIncludeFilter(new AssignableTypeFilter(TypeFilter.class));  
  100.      * // Set&lt;MetadataReader&gt; bd = p.findCandidateClasss(&quot;org.springframework&quot;);  
  101.      * p.addIncludeFilter(new AnnotationTypeFilter(Entity.class));  
  102.      * Set&lt;MetadataReader&gt; bd = p.findCandidateClasss(&quot;com&quot;);  
  103.      * for (MetadataReader b : bd) {  
  104.      *     System.out.println(b.getClassMetadata().getClassName());  
  105.      * }  
  106.      * p.resetFilters();  
  107.      * </pre>  
  108.      *   
  109.      * @param basePackage the package to check for annotated classes  
  110.      * @return a corresponding Set of autodetected bean definitions  
  111.      */   
  112.     public  Set<MetadataReader> findCandidateClasss(String... basePackage) {  
  113.         Set<MetadataReader> candidates = new  LinkedHashSet<MetadataReader>();  
  114.         try  {  
  115.             for  (String s : basePackage) {  
  116.                 String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + packageToRelativedPath(s) + "/"   
  117.                         + this .resourcePattern;  
  118.                 if  (logger.isDebugEnabled()) logger.debug( "扫描包:"  + packageSearchPath);  
  119.                 Resource[] resources = this .resourcePatternResolver.getResources(packageSearchPath);  
  120.                 for  (Resource resource : resources) {  
  121.                     if  (resource.isReadable()) {  
  122.                         try  {  
  123.                             MetadataReader metadataReader = this .metadataReaderFactory.getMetadataReader(resource);  
  124.                             if  (isCandidateComponent(metadataReader)) {  
  125.                                 candidates.add(metadataReader);  
  126.                                 if  (logger.isDebugEnabled()) logger.debug( "匹配:"  + metadataReader.getClassMetadata().getClassName());  
  127.                             }  
  128.                         } catch  (Throwable ex) {  
  129.                             // throw new Exception("类符合条件但读取失败: " + resource, ex);   
  130.                         }  
  131.                     } else  {  
  132.                         if  (logger.isDebugEnabled()) logger.debug( "因为扫描到的类无法读取元数据,忽略: "  + resource);  
  133.                     }  
  134.                 }  
  135.             }  
  136.         } catch  (IOException ex) {  
  137.             // throw new IOException("扫描时发生 I/O 异常", ex);   
  138.         }  
  139.         return  candidates;  
  140.     }  
  141.   
  142.     /**  
  143.      * 扫描CLASSPATH路径以找出合条件的文件  
  144.      * <p>  
  145.      * 注:如果包是空白字符,只能扫描到非JAR中的内容  
  146.      *   
  147.      * <pre>  
  148.      * ClassPathScaner p = new ClassPathScaner();  
  149.      * List&lt;Resource&gt; rs = p.findCandidateFiles("**/ *.properties";, &quot;META-INF&quot;,  "com.yotexs.model" ;,  "org.yotexs.model" ;);  
  150.      * for  (Resource r : rs) {  
  151.      *     System.out.println(r.getURI().toURL().toString());  
  152.      * }  
  153.      * </pre>  
  154.      *   
  155.      * @param  patterns ant方式的匹配模式 如:**&frasl;*.xml  
  156.      * @param  basePackage 要扫描的包组 如:com.yotexs,META-INF  
  157.      * @return   
  158.      */  
  159.     public  List<Resource> findCandidateFiles(String patterns, String... basePackage) {  
  160.         List<Resource> resources = new  LinkedList<Resource>();  
  161.         try  {  
  162.             for  (String p : basePackage) {  
  163.                 String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + packageToRelativedPath(p) + "/"  + patterns;  
  164.                 Resource[] current = this .resourcePatternResolver.getResources(packageSearchPath);  
  165.                 if  (current.length ==  0continue ;  
  166.                 resources.addAll(Arrays.asList(current));  
  167.             }  
  168.             return  resources;  
  169.         } catch  (IOException ex) {  
  170.             // throw new IOException("扫描时发生 I/O 异常", ex);   
  171.             return   null ;  
  172.         }  
  173.     }  
  174.   
  175.     // ----------------------------------------------------------------------------------------------   
  176.     public   static   void  main(String a[])  throws  Exception {  
  177.         // -----------------------------------------直接扫描   
  178.         // Enumeration<URL> xmls = Thread.currentThread().getContextClassLoader()   
  179.         // .getResources("META-INF/persistence.xml");   
  180.         // while (xmls.hasMoreElements()) {   
  181.         // URL url = xmls.nextElement();   
  182.         // System.out.println(url.toURI().toURL());   
  183.         // }   
  184.         // -----------------------------------------直接扫描   
  185.         // ResourcePatternResolver rp = new PathMatchingResourcePatternResolver();   
  186.         // String packages = "META-INF";   
  187.         // Resource[] rs = rp.getResources("classpath*:/" + packages + "/**/*.*");   
  188.         // for (Resource r : rs) {   
  189.         // System.out.println(r);   
  190.         // }   
  191.         // -----------------------------------------类扫描   
  192.         ClassPathScaner p = new  ClassPathScaner();  
  193.         // p.addIncludeFilter(new AssignableTypeFilter(TypeFilter.class));   
  194.         // Set<MetadataReader> bd = p.findCandidateClasss("org.springframework");   
  195.         p.addIncludeFilter(new  AnnotationTypeFilter(Entity. class ));  
  196.         Set<MetadataReader> bd = p.findCandidateClasss("com" );  
  197.         for  (MetadataReader b : bd) {  
  198.             System.out.println("<class>"  + b.getClassMetadata().getClassName() +  "</class>" );  
  199.         }  
  200.   
  201.         // -----------------------------------------资源扫描   
  202.         // ClassPathScaner p = new ClassPathScaner();   
  203.         // List<Resource> rs = p.findCandidateFiles("**/*.xml", "META-INF", "com", "org");   
  204.         // for (Resource r : rs) {   
  205.         // System.out.println(r.getURI().toURL().toString());   
  206.         // }   
  207.     }  
  208.   
  209. }  
package com.yotexs.util;

import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.persistence.Entity;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;

/**
 * 类或资源扫描器,可以批量过滤CLASSPATH路径和JAR中的任意内容
 * <p>
 * This implementation is based on Spring's {@link org.springframework.core.type.classreading.MetadataReader
 * MetadataReader} facility, backed by an ASM {@link org.springframework.asm.ClassReader ClassReader}.
 * 
 * @author bencmai
 * @see org.springframework.core.type.classreading.MetadataReaderFactory
 * @see org.springframework.core.type.AnnotationMetadata
 */
public class ClassPathScaner {
    protected final Logger logger = LoggerFactory.getLogger(getClass());

    private static final String     DEFAULT_RESOURCE_PATTERN = "**/*.class";
    private ResourcePatternResolver resourcePatternResolver  = new PathMatchingResourcePatternResolver();
    private MetadataReaderFactory   metadataReaderFactory    = new CachingMetadataReaderFactory(this.resourcePatternResolver);
    private String                  resourcePattern          = DEFAULT_RESOURCE_PATTERN;
    private final List<TypeFilter>  includeFilters           = new LinkedList<TypeFilter>();
    private final List<TypeFilter>  excludeFilters           = new LinkedList<TypeFilter>();

    /** Add an include type filter to the <i>end</i> of the inclusion list. */
    public void addIncludeFilter(TypeFilter includeFilter) {
        this.includeFilters.add(includeFilter);
    }

    /** Add an exclude type filter to the <i>front</i> of the exclusion list. */
    public void addExcludeFilter(TypeFilter excludeFilter) {
        this.excludeFilters.add(0, excludeFilter);
    }

    /** Reset the configured type filters. */
    public void resetFilters() {
        this.includeFilters.clear();
        this.excludeFilters.clear();
    }

    /**
     * 将.包路径解释为/路径 <br>
     * Resolve the specified base package into a pattern specification for the package search path.
     * <p>
     * The default implementation resolves placeholders against system properties, and converts a "."-based package path
     * to a "/"-based resource path.
     * 
     * @param basePackage the base package as specified by the user
     * @return the pattern specification to be used for package searching
     */
    public String packageToRelativedPath(String basePackage) {
        return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
    }

    /**
     * 和配置的排除过滤器和包含过滤器进行匹配过滤<br>
     * Determine whether the given class does not match any exclude filter and does match at least one include filter.
     * 
     * @param metadataReader the ASM ClassReader for the class
     * @return whether the class qualifies as a candidate component
     */
    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        for (TypeFilter tf : this.excludeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) { return false; }
        }
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, this.metadataReaderFactory)) { return true; }
        }
        return false;
    }

    /**
     * 扫描类路径并根据过滤器以找出合条件的类元数据<br>
     * <p>
     * 注:如果包是空白字符,只能扫描到非JAR中的内容
     * 
     * <pre>
     * ClassPathScaner p = new ClassPathScaner();
     * // p.addIncludeFilter(new AssignableTypeFilter(TypeFilter.class));
     * // Set&lt;MetadataReader&gt; bd = p.findCandidateClasss(&quot;org.springframework&quot;);
     * p.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
     * Set&lt;MetadataReader&gt; bd = p.findCandidateClasss(&quot;com&quot;);
     * for (MetadataReader b : bd) {
     *     System.out.println(b.getClassMetadata().getClassName());
     * }
     * p.resetFilters();
     * </pre>
     * 
     * @param basePackage the package to check for annotated classes
     * @return a corresponding Set of autodetected bean definitions
     */
    public Set<MetadataReader> findCandidateClasss(String... basePackage) {
        Set<MetadataReader> candidates = new LinkedHashSet<MetadataReader>();
        try {
            for (String s : basePackage) {
                String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + packageToRelativedPath(s) + "/"
                        + this.resourcePattern;
                if (logger.isDebugEnabled()) logger.debug("扫描包:" + packageSearchPath);
                Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
                for (Resource resource : resources) {
                    if (resource.isReadable()) {
                        try {
                            MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                            if (isCandidateComponent(metadataReader)) {
                                candidates.add(metadataReader);
                                if (logger.isDebugEnabled()) logger.debug("匹配:" + metadataReader.getClassMetadata().getClassName());
                            }
                        } catch (Throwable ex) {
                            // throw new Exception("类符合条件但读取失败: " + resource, ex);
                        }
                    } else {
                        if (logger.isDebugEnabled()) logger.debug("因为扫描到的类无法读取元数据,忽略: " + resource);
                    }
                }
            }
        } catch (IOException ex) {
            // throw new IOException("扫描时发生 I/O 异常", ex);
        }
        return candidates;
    }

    /**
     * 扫描CLASSPATH路径以找出合条件的文件
     * <p>
     * 注:如果包是空白字符,只能扫描到非JAR中的内容
     * 
     * <pre>
     * ClassPathScaner p = new ClassPathScaner();
     * List&lt;Resource&gt; rs = p.findCandidateFiles("**/*.properties";, &quot;META-INF&quot;, "com.yotexs.model";, "org.yotexs.model";);
     * for (Resource r : rs) {
     *     System.out.println(r.getURI().toURL().toString());
     * }
     * </pre>
     * 
     * @param patterns ant方式的匹配模式 如:**&frasl;*.xml
     * @param basePackage 要扫描的包组 如:com.yotexs,META-INF
     * @return
     */
    public List<Resource> findCandidateFiles(String patterns, String... basePackage) {
        List<Resource> resources = new LinkedList<Resource>();
        try {
            for (String p : basePackage) {
                String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + packageToRelativedPath(p) + "/" + patterns;
                Resource[] current = this.resourcePatternResolver.getResources(packageSearchPath);
                if (current.length == 0) continue;
                resources.addAll(Arrays.asList(current));
            }
            return resources;
        } catch (IOException ex) {
            // throw new IOException("扫描时发生 I/O 异常", ex);
            return null;
        }
    }

    // ----------------------------------------------------------------------------------------------
    public static void main(String a[]) throws Exception {
        // -----------------------------------------直接扫描
        // Enumeration<URL> xmls = Thread.currentThread().getContextClassLoader()
        // .getResources("META-INF/persistence.xml");
        // while (xmls.hasMoreElements()) {
        // URL url = xmls.nextElement();
        // System.out.println(url.toURI().toURL());
        // }
        // -----------------------------------------直接扫描
        // ResourcePatternResolver rp = new PathMatchingResourcePatternResolver();
        // String packages = "META-INF";
        // Resource[] rs = rp.getResources("classpath*:/" + packages + "/**/*.*");
        // for (Resource r : rs) {
        // System.out.println(r);
        // }
        // -----------------------------------------类扫描
        ClassPathScaner p = new ClassPathScaner();
        // p.addIncludeFilter(new AssignableTypeFilter(TypeFilter.class));
        // Set<MetadataReader> bd = p.findCandidateClasss("org.springframework");
        p.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
        Set<MetadataReader> bd = p.findCandidateClasss("com");
        for (MetadataReader b : bd) {
            System.out.println("<class>" + b.getClassMetadata().getClassName() + "</class>");
        }

        // -----------------------------------------资源扫描
        // ClassPathScaner p = new ClassPathScaner();
        // List<Resource> rs = p.findCandidateFiles("**/*.xml", "META-INF", "com", "org");
        // for (Resource r : rs) {
        // System.out.println(r.getURI().toURL().toString());
        // }
    }

}
 
Java代码
  1. package  com.yotexs.config.persist.jpa;  
  2.   
  3. import  java.util.List;  
  4. import  java.util.Set;  
  5.   
  6. import  javax.persistence.Entity;  
  7. import  javax.persistence.EntityManagerFactory;  
  8. import  javax.persistence.PersistenceException;  
  9. import  javax.persistence.spi.PersistenceProvider;  
  10. import  javax.persistence.spi.PersistenceUnitInfo;  
  11. import  javax.sql.DataSource;  
  12.   
  13. import  org.springframework.core.type.classreading.MetadataReader;  
  14. import  org.springframework.core.type.filter.AnnotationTypeFilter;  
  15. import  org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;  
  16. import  org.springframework.orm.jpa.JpaVendorAdapter;  
  17. import  org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;  
  18. import  org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;  
  19. import  org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;  
  20.   
  21. import  com.yotexs.util.Assert;  
  22. import  com.yotexs.util.ClassPathScaner;  
  23. import  com.yotexs.util.StringUtils;  
  24.   
  25. /**  
  26.  * 重新实现JPA容器托管实体工厂代替LocalContainerEntityManagerFactoryBean以方便扫描打jar后的models  
  27.  *   
  28.  * @author bencmai  
  29.  */   
  30. public   class  ContainerEntityManagerFactoryBean  extends  AbstractEntityManagerFactoryBean {  
  31.   
  32.     private  DefaultPersistenceUnitManager persistenceUnitManager;  
  33.   
  34.     private  PersistenceUnitInfo           persistenceUnitInfo;  
  35.     private  DataSource                    dataSource;  
  36.     private  String                        scanPackages =  "" ;  
  37.   
  38.     // ----------------------------------------------------------------------------------------------   
  39.     @Override   
  40.     public  PersistenceUnitInfo getPersistenceUnitInfo() {  
  41.         return   this .persistenceUnitInfo;  
  42.     }  
  43.   
  44.     @Override   
  45.     public  String getPersistenceUnitName() { // 指定实体工厂使用特定的持久化单元   
  46.         if  ( this .persistenceUnitInfo !=  null ) {  return   this .persistenceUnitInfo.getPersistenceUnitName(); }  
  47.         return   super .getPersistenceUnitName();  
  48.     }  
  49.   
  50.     @Override   
  51.     public  DataSource getDataSource() {  
  52.         if  (dataSource !=  nullreturn  dataSource;  
  53.         else   if  ( this .persistenceUnitInfo !=  nullreturn   this .persistenceUnitInfo.getNonJtaDataSource();  
  54.         else   return   this .persistenceUnitManager.getDefaultDataSource();  
  55.     }  
  56.   
  57.     @Override   
  58.     protected  EntityManagerFactory createNativeEntityManagerFactory()  throws  PersistenceException {  
  59.         Assert.isTrue((persistenceUnitManager != null  || persistenceUnitInfo !=  null ),  "需要设置persistenceUnitManager或persistenceUnitInfo属性" );  
  60.   
  61.         if  (persistenceUnitInfo ==  nullthis .persistenceUnitInfo = determinePersistenceUnitInfo(persistenceUnitManager);  
  62.         JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter();  
  63.         if  (jpaVendorAdapter !=  null  &&  this .persistenceUnitInfo  instanceof  MutablePersistenceUnitInfo) {  
  64.             ((MutablePersistenceUnitInfo) this .persistenceUnitInfo).setPersistenceProviderPackageName(jpaVendorAdapter  
  65.                     .getPersistenceProviderRootPackage());  
  66.         }  
  67.         PersistenceProvider provider = getPersistenceProvider();  
  68.         if  (logger.isInfoEnabled()) logger.info( "正在构建 JPA 容器 EntityManagerFactory, 持久化单元为:'"  +  this .persistenceUnitInfo.getPersistenceUnitName()  
  69.                 + "'" );  
  70.   
  71.         scanEntitys();// 扫描实体并在创建实体工厂前添加到所使用的持久化单元里   
  72.   
  73.         this .nativeEntityManagerFactory = provider.createContainerEntityManagerFactory( this .persistenceUnitInfo, getJpaPropertyMap());  
  74.   
  75.         postProcessEntityManagerFactory(this .nativeEntityManagerFactory,  this .persistenceUnitInfo);  
  76.   
  77.         return   this .nativeEntityManagerFactory;  
  78.     }  
  79.   
  80.     // ----------------------------------------------------------------------------------------------   
  81.     protected  PersistenceUnitInfo determinePersistenceUnitInfo(PersistenceUnitManager persistenceUnitManager) {  
  82.         if  (getPersistenceUnitName() !=  nullreturn  persistenceUnitManager.obtainPersistenceUnitInfo(getPersistenceUnitName());  
  83.         else   return  persistenceUnitManager.obtainDefaultPersistenceUnitInfo();  
  84.     }  
  85.   
  86.     protected   void  postProcessEntityManagerFactory(EntityManagerFactory emf, PersistenceUnitInfo pui) {  
  87.     }  
  88.   
  89.     public   void  setPersistenceUnitManager(DefaultPersistenceUnitManager persistenceUnitManager) {  
  90.         this .persistenceUnitManager = persistenceUnitManager;  
  91.     }  
  92.   
  93.     // 直接指定PersistenceUnitInfo就不需要指定PersistenceUnitManager,但应指定DataSource   
  94.     public   void  setPersistenceUnitInfo(PersistenceUnitInfo persistenceUnitInfo) {  
  95.         this .persistenceUnitInfo = persistenceUnitInfo;  
  96.     }  
  97.   
  98.     public   void  setDataSource(DataSource dataSource) {  
  99.         this .dataSource = dataSource;  
  100.     }  
  101.   
  102.     public   void  setScanPackages(String scanPackages) { // null或不指定表示不扫描,空白表示扫描非jar目录   
  103.         this .scanPackages = scanPackages;  
  104.     }  
  105.   
  106.     /** 扫描classpath中的(包括分别打包在不同jar中的)实体类并添加到PersistenceUnitInfo中以创建EntityManagerFactory */   
  107.     private   void  scanEntitys() {  
  108.         String[] pgs = StringUtils.commaDelimitedListToStringArray(scanPackages);  
  109.         if  (pgs.length > - 1 ) {  
  110.             ClassPathScaner p = new  ClassPathScaner();  
  111.             // p.addIncludeFilter(new AssignableTypeFilter(TypeFilter.class));   
  112.             // Set<MetadataReader> bd = p.findCandidateClasss("org.springframework");   
  113.             p.addIncludeFilter(new  AnnotationTypeFilter(Entity. class ));  
  114.             Set<MetadataReader> bd = p.findCandidateClasss(pgs);  
  115.             List<String> managedClass = persistenceUnitInfo.getManagedClassNames();  
  116.             for  (MetadataReader b : bd) {  
  117.                 if  (!(managedClass.contains(b.getClassMetadata().getClassName()))) {  
  118.                     managedClass.add(b.getClassMetadata().getClassName());  
  119.                 }  
  120.             }  
  121.         }  
  122.     }  
  123. }  
package com.yotexs.config.persist.jpa;

import java.util.List;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceException;
import javax.persistence.spi.PersistenceProvider;
import javax.persistence.spi.PersistenceUnitInfo;
import javax.sql.DataSource;

import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;

import com.yotexs.util.Assert;
import com.yotexs.util.ClassPathScaner;
import com.yotexs.util.StringUtils;

/**
 * 重新实现JPA容器托管实体工厂代替LocalContainerEntityManagerFactoryBean以方便扫描打jar后的models
 * 
 * @author bencmai
 */
public class ContainerEntityManagerFactoryBean extends AbstractEntityManagerFactoryBean {

    private DefaultPersistenceUnitManager persistenceUnitManager;

    private PersistenceUnitInfo           persistenceUnitInfo;
    private DataSource                    dataSource;
    private String                        scanPackages = "";

    // ----------------------------------------------------------------------------------------------
    @Override
    public PersistenceUnitInfo getPersistenceUnitInfo() {
        return this.persistenceUnitInfo;
    }

    @Override
    public String getPersistenceUnitName() {// 指定实体工厂使用特定的持久化单元
        if (this.persistenceUnitInfo != null) { return this.persistenceUnitInfo.getPersistenceUnitName(); }
        return super.getPersistenceUnitName();
    }

    @Override
    public DataSource getDataSource() {
        if (dataSource != null) return dataSource;
        else if (this.persistenceUnitInfo != null) return this.persistenceUnitInfo.getNonJtaDataSource();
        else return this.persistenceUnitManager.getDefaultDataSource();
    }

    @Override
    protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException {
        Assert.isTrue((persistenceUnitManager != null || persistenceUnitInfo != null), "需要设置persistenceUnitManager或persistenceUnitInfo属性");

        if (persistenceUnitInfo == null) this.persistenceUnitInfo = determinePersistenceUnitInfo(persistenceUnitManager);
        JpaVendorAdapter jpaVendorAdapter = getJpaVendorAdapter();
        if (jpaVendorAdapter != null && this.persistenceUnitInfo instanceof MutablePersistenceUnitInfo) {
            ((MutablePersistenceUnitInfo) this.persistenceUnitInfo).setPersistenceProviderPackageName(jpaVendorAdapter
                    .getPersistenceProviderRootPackage());
        }
        PersistenceProvider provider = getPersistenceProvider();
        if (logger.isInfoEnabled()) logger.info("正在构建 JPA 容器 EntityManagerFactory, 持久化单元为:'" + this.persistenceUnitInfo.getPersistenceUnitName()
                + "'");

        scanEntitys();// 扫描实体并在创建实体工厂前添加到所使用的持久化单元里

        this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(this.persistenceUnitInfo, getJpaPropertyMap());

        postProcessEntityManagerFactory(this.nativeEntityManagerFactory, this.persistenceUnitInfo);

        return this.nativeEntityManagerFactory;
    }

    // ----------------------------------------------------------------------------------------------
    protected PersistenceUnitInfo determinePersistenceUnitInfo(PersistenceUnitManager persistenceUnitManager) {
        if (getPersistenceUnitName() != null) return persistenceUnitManager.obtainPersistenceUnitInfo(getPersistenceUnitName());
        else return persistenceUnitManager.obtainDefaultPersistenceUnitInfo();
    }

    protected void postProcessEntityManagerFactory(EntityManagerFactory emf, PersistenceUnitInfo pui) {
    }

    public void setPersistenceUnitManager(DefaultPersistenceUnitManager persistenceUnitManager) {
        this.persistenceUnitManager = persistenceUnitManager;
    }

    // 直接指定PersistenceUnitInfo就不需要指定PersistenceUnitManager,但应指定DataSource
    public void setPersistenceUnitInfo(PersistenceUnitInfo persistenceUnitInfo) {
        this.persistenceUnitInfo = persistenceUnitInfo;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void setScanPackages(String scanPackages) {// null或不指定表示不扫描,空白表示扫描非jar目录
        this.scanPackages = scanPackages;
    }

    /** 扫描classpath中的(包括分别打包在不同jar中的)实体类并添加到PersistenceUnitInfo中以创建EntityManagerFactory */
    private void scanEntitys() {
        String[] pgs = StringUtils.commaDelimitedListToStringArray(scanPackages);
        if (pgs.length > -1) {
            ClassPathScaner p = new ClassPathScaner();
            // p.addIncludeFilter(new AssignableTypeFilter(TypeFilter.class));
            // Set<MetadataReader> bd = p.findCandidateClasss("org.springframework");
            p.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
            Set<MetadataReader> bd = p.findCandidateClasss(pgs);
            List<String> managedClass = persistenceUnitInfo.getManagedClassNames();
            for (MetadataReader b : bd) {
                if (!(managedClass.contains(b.getClassMetadata().getClassName()))) {
                    managedClass.add(b.getClassMetadata().getClassName());
                }
            }
        }
    }
}
 
Java代码
  1. <?xml version= "1.0"  encoding= "UTF-8" ?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"   
  3.     xmlns:context="http://www.springframework.org/schema/context"  xmlns:tx= "http://www.springframework.org/schema/tx"   
  4.     xmlns:util="http://www.springframework.org/schema/util"   
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
  6.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd   
  7.         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd   
  8.         http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">   
  9.   
  10.     <context:property-placeholder location="classpath*:/META-INF/*.properties"  />  
  11.     <!-- jdbc额外属性 -->  
  12.     <util:properties id="jdbcExtraProperties"  location= "classpath:META-INF/jdbcextra.properties"  />  
  13.     <!-- jpa提供者属性 -->  
  14.     <util:properties id="jpaProviderProperties"  location= "classpath:META-INF/jpaprovider.properties"  />  
  15.   
  16.     <context:annotation-config />  
  17.   
  18.      <tx:annotation-driven />  
  19.   
  20.     <!--数据源-->  
  21.     <bean id="dataSource"   class = "com.mchange.v2.c3p0.ComboPooledDataSource" >  
  22.         <property name="driverClass"  value= "${connection.driver_class}"  />  
  23.         <property name="jdbcUrl"  value= "${connection.url}"  />  
  24.         <property name="user"  value= "${connection.username}"  />  
  25.         <property name="password"  value= "${connection.password}"  />  
  26.         <property name="properties"  ref= "jdbcExtraProperties"  />  
  27.     </bean>  
  28.   
  29.     <!--持久化单元管理器 -->  
  30.     <bean id="persistenceUnitManager"   class = "org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager" >  
  31.         <property name="dataSources" >  
  32.             <map>  
  33.                 <entry key="c3p0DataSourse"  value-ref= "dataSource"  />  
  34.             </map>  
  35.         </property>  
  36.         <property name="defaultDataSource"  ref= "dataSource"  />  
  37.         <!--  
  38.             <property name="persistenceUnitPostProcessors" > <bean  
  39.             class = "com.yotexs.config.jpa.MergingPersistenceUnitPostProcessor"  /> </property>  
  40.         -->  
  41.     </bean>  
  42.   
  43.     <!-- JPA 提供者实现 -->  
  44.     <bean id="jpaVendorAdapter"   class = "org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >  
  45.         <property name="showSql"  value= "${jpa.showSql}"  />  
  46.         <property name="generateDdl"  value= "${jpa.generateDdl}"  />  
  47.         <property name="database"  value= "${jpa.database}"  />  
  48.         <property name="databasePlatform"  value= "${jpa.databasePlatform}"  />  
  49.     </bean>  
  50.   
  51.     <!-- 实体管理器工厂 -->  
  52.     <bean id="entityManagerFactory"   class = "com.yotexs.config.persist.jpa.ContainerEntityManagerFactoryBean" >  
  53.         <property name="persistenceUnitManager"  ref= "persistenceUnitManager"  />  
  54.         <property name="persistenceUnitName"  value= "${jpa.persistenceUnitName}"  />  
  55.         <property name="jpaVendorAdapter"  ref= "jpaVendorAdapter"  />  
  56.                 <!-- 指定需要扫描的存在@Entity 实体的包,并将扫描到的实体 添加到持久化单元-->  
  57.         <property name="scanPackages"  value= "com.yotexs.model,org.yotexs.model"  />  
  58.         <property name="jpaProperties"  ref= "jpaProviderProperties"  />  
  59.     </bean>  
  60.   
  61.     <bean id="transactionManager"   class = "org.springframework.orm.jpa.JpaTransactionManager" >  
  62.         <property name="entityManagerFactory"  ref= "entityManagerFactory"  />  
  63.     </bean>  
  64.   
  65.     <!-- 字节码织入方式 -->  
  66.     <context:load-time-weaver />  
  67.   
  68. </beans> 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值