`

非J2EE 容器环境下Spring +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。

//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() {

    }
}
 
	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="${jpa.persistenceUnitName}" />
		<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
		<property name="jpaProperties" ref="jpaProviderProperties" />
		<property name="persistenceUnitPostProcessors" >
			<util:list>
			       <bean class="com.yotexs.config.persist.jpa.MergingPersistenceUnitPostProcessor" />
			</util:list>
		</property>
	</bean>

 

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

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;
    }
}
 
用法:
第一步

 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
         <property name="persistenceUnitManager" ref="persistenceUnitManager"/>
         <property name="dataSource" ref="dataSource"/>
         <property name="jpaVendorAdapter">
             <bean class="org.springframework.orm.jpa.vendor.RedSoftJpaVendorAdapter">
             </bean>
         </property>
     </bean>
 
     <bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
         <property name="persistenceXmlLocations">
             <list>
                 <value>classpath*:/redsoft_jpa_persistence.xml</value>
             </list>
         </property>
     </bean>
 

第二步

 <import resource="classpath*:/ormContext.xml"/>
 
     <bean id="entityClasses" class="com.abest.util.PersistenceClassesConfigProcessor">
         <property name="entityClassNames">
             <list>
                 <value>com.abest.common.dao.TestBean</value>
                 <value>com.abest.uwin.baseinfo.domain.Region</value>
                 <value>com.abest.uwin.baseinfo.domain.Brand</value>
                 <value>com.abest.uwin.baseinfo.domain.MeasureUnit</value>
                 <value>com.abest.uwin.baseinfo.domain.ProductionFactory</value>
                 <value>com.abest.uwin.baseinfo.domain.MaterialType</value>
             </list>
         </property>
     </bean>

 

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

 

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

 

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());
        // }
    }

}
 
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());
                }
            }
        }
    }
}
 
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

	<context:property-placeholder location="classpath*:/META-INF/*.properties" />
	<!-- jdbc额外属性 -->
	<util:properties id="jdbcExtraProperties" location="classpath:META-INF/jdbcextra.properties" />
	<!-- jpa提供者属性 -->
	<util:properties id="jpaProviderProperties" location="classpath:META-INF/jpaprovider.properties" />

	<context:annotation-config />

	 <tx:annotation-driven />

	<!--数据源-->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${connection.driver_class}" />
		<property name="jdbcUrl" value="${connection.url}" />
		<property name="user" value="${connection.username}" />
		<property name="password" value="${connection.password}" />
		<property name="properties" ref="jdbcExtraProperties" />
	</bean>

	<!--持久化单元管理器 -->
	<bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
		<property name="dataSources">
			<map>
				<entry key="c3p0DataSourse" value-ref="dataSource" />
			</map>
		</property>
		<property name="defaultDataSource" ref="dataSource" />
		<!--
			<property name="persistenceUnitPostProcessors"> <bean
			class="com.yotexs.config.jpa.MergingPersistenceUnitPostProcessor" /> </property>
		-->
	</bean>

	<!-- JPA 提供者实现 -->
	<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
		<property name="showSql" value="${jpa.showSql}" />
		<property name="generateDdl" value="${jpa.generateDdl}" />
		<property name="database" value="${jpa.database}" />
		<property name="databasePlatform" value="${jpa.databasePlatform}" />
	</bean>

	<!-- 实体管理器工厂 -->
	<bean id="entityManagerFactory" class="com.yotexs.config.persist.jpa.ContainerEntityManagerFactoryBean">
		<property name="persistenceUnitManager" ref="persistenceUnitManager" />
		<property name="persistenceUnitName" value="${jpa.persistenceUnitName}" />
		<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
				<!-- 指定需要扫描的存在@Entity实体的包,并将扫描到的实体 添加到持久化单元-->
		<property name="scanPackages" value="com.yotexs.model,org.yotexs.model" />
		<property name="jpaProperties" ref="jpaProviderProperties" />
	</bean>

	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

	<!-- 字节码织入方式 -->
	<context:load-time-weaver />

</beans>
 

 

分享到:
评论
4 楼 seaport2008 2009-08-25  
seaport2008 写道
老大,你的群号是多少啊。。。我的qq是xxxxxxxx,有时间给指导一下吧,我现在的问题是把自己原有的一个项目打成jar包,然后做二次开发,在二次开发的环境中添加的 实体类无法自动映射到数据库,按照spring参考手册中的处理多个持久化单元做过改动,用以下方式实现,但是spring每次只去找一次,而且是最后那个配置文件的。。。,希望看到后加我qq号给指导一下,先谢过了。。。
  <property name="persistenceXmlLocation">
    <list>
     <value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
     <value>classpath:/my/package/**/custom-persistence.xml</value>
     <value>classpath*:META-INF/persistence.xml</value>
    </list>
  </property>



老大,按照你的第三个方法调通了,呵呵,谢谢代码分享了,非常感谢!
3 楼 seaport2008 2009-08-25  
老大,你的群号是多少啊。。。我的qq是49751920,有时间给指导一下吧,我现在的问题是把自己原有的一个项目打成jar包,然后做二次开发,在二次开发的环境中添加的 实体类无法自动映射到数据库,按照spring参考手册中的处理多个持久化单元做过改动,用以下方式实现,但是spring每次只去找一次,而且是最后那个配置文件的。。。,希望看到后加我qq号给指导一下,先谢过了。。。
  <property name="persistenceXmlLocation">
    <list>
     <value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
     <value>classpath:/my/package/**/custom-persistence.xml</value>
     <value>classpath*:META-INF/persistence.xml</value>
    </list>
  </property>


2 楼 bencmai 2009-08-25  
seaport2008 写道
老大,能把你最后一种解决方法的源码共享一份吗,我都郁闷了三四天了,试尽了所有的方法。。。小弟在此先谢过了,望尽快回复


你是什么问题,
仿照Hibernate的Ejb3Configration的JAR包扫描实体类要写近十个类,过于复杂,我自己都很少用,一般是用上面的第三种方案已经可以解决问题了,我自己也是这么用的,有什么不明白的,可以进我的群聊,呵呵,javaeye上来的少一些
1 楼 seaport2008 2009-08-24  
老大,能把你最后一种解决方法的源码共享一份吗,我都郁闷了三四天了,试尽了所有的方法。。。小弟在此先谢过了,望尽快回复

相关推荐

    J2EE常用的jar包

    2. `hibernate-entitymanager.jar`:该包提供了Java持久化API(JPA)的实现,允许开发者使用注解或XML配置方式管理持久化实体。 3. `hibernate-instrument.jar`:该包提供了类字节码增强的功能,使得Hibernate可以...

    spring框架最新4.3.4jar包

    4. **数据访问/集成**:Spring Framework 4.3.4提供了对各种持久化技术的支持,包括JDBC、ORM(Hibernate、JPA等)和OXM(Object-XML Mapping)。这些模块在4.3.4中进行了性能优化,提升了数据库操作的效率。 5. **...

    J2EE常用Jar包

    描述中提到"大部分都在里面了",意味着这个压缩包可能包含了J2EE开发中常见的核心组件和框架,如Servlet、JSP、EJB、JMS、JTA、JPA等,以及一些常用的第三方库,例如Spring、Hibernate、Struts等。这些Jar包通常用于...

    struts2.1.18+hibernate3.5.6+spring3.0整合jar

    Struts2.1.18、Hibernate3.5.6和Spring3.0是Java开发中非常著名的三大开源框架,它们分别负责Web层、持久化层和应用上下文管理。这三个框架的整合,通常被称为"S2SH"或者"SSH2",在J2EE应用程序中被广泛使用,为...

    SSH整合 Struts2.1+Spring4.1+Hibernate4.1

    这个“SSH整合 Struts2.1+Spring4.1+Hibernate4.1”是一个预配置的框架模板,适用于快速开发J2EE项目,特别是对于那些需要管理业务逻辑和持久层操作的复杂应用。 Struts2是MVC(模型-视图-控制器)架构的扩展,提供...

    Spring快速学习PPT

    Spring还能与各种持久层技术(如Hibernate、JPA)集成,提供数据访问服务,并且可以通过声明式事务管理来处理数据库事务。 **创建Spring工程**: 创建Spring工程通常包括以下步骤: 1. 创建一个新的Java项目。 2. ...

    springframework.rar

    Spring框架是中国最流行的Java企业级应用开发框架,它由Rod Johnson在其著作《Expert One-on-One J2EE Design and Development》中首次阐述,并在2003年3月正式发布。Spring以其轻量级、模块化的设计,极大地简化了...

    Web项目基础jar包

    2. **javax.persistence.jar**:这个jar包是Java持久化API(JPA)的一部分,它为对象关系映射(ORM)提供了标准接口,简化了数据库操作。通过JPA,开发者可以将Java对象直接映射到数据库表,避免了繁琐的SQL编写。它...

    java spring 框架

    8. **Spring Data**:提供了一种声明式的方式访问各种持久化存储,如JPA、MongoDB等,简化数据访问层的编写。 9. **Spring Integration**:提供了异步处理、消息传递和企业服务总线(ESB)功能,便于实现系统的集成...

    最新SSHjar包

    这个"最新SSH jar包"组合,旨在为开发人员提供一个快速启动Java Web项目的环境,特别是对于那些使用Struts进行前端展示,Spring进行业务逻辑控制,Hibernate进行数据持久化,以及Oracle作为后台数据库的项目。...

    spring框架依赖

    这些JAR包涵盖了Spring的多个模块,例如: 1. **Spring Core**:这是Spring框架的基础,提供了IoC(Inversion of Control)容器,支持依赖注入和资源定位。 2. **Spring Beans**:处理bean的定义、实例化、装配和...

    Hibernate所需的一些jar包

    标题"Hibernate所需的一些jar包"指出我们关注的是Hibernate框架在数据库持久化开发中的依赖库。Hibernate是Java领域一个流行的Object-Relational Mapping (ORM)框架,它简化了Java应用与关系数据库之间的交互。描述...

    Struts +Hibernate 常用开发驱动包

    结合这两个框架,可以构建出高效的J2EE应用,其中Struts负责请求处理和页面跳转,而Hibernate则负责数据的持久化操作。它们的集成通常涉及以下步骤: - **配置Struts2**:在struts.xml配置文件中定义Action,设置...

    EJB入门

    3. **实体Bean(Entity Beans)**:实体Bean代表持久化的业务对象,通常对应数据库中的记录。现代Java EE中,实体Bean已经由JPA(Java Persistence API)中的注解驱动的实体类所取代,简化了数据访问。 了解了EJB的...

Global site tag (gtag.js) - Google Analytics