带有Karaf,Spring和JPA的LocalContainerEntityManagerFactoryBean

时间:2015-06-29 08:04:29

标签: spring hibernate jpa karaf

在许多情况下,声明XML文件中的数据源和持久性单元并不理想。为此,我尝试使用LocalContainerEntityManagerFactoryBean配置JPA。但首先,一些证明此方法的参考资料适用于非OSGI环境:

  • www.baeldung.com/2011/12/22/the-persistence-layer-with-spring-data-jpa /
  • docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html

为此,我的Karaf OSGI捆绑包的源代码如下:

    public class AbstractXyzTableServiceImpl
    {
        private static EntityManagerFactory _entityManagerFactory;

        MysqlDataSource mysqlDataSource = null;


        // private static final SessionFactory configurationSessionFactory = buildConfigurationSessionFactory();

        @Bean
        public DataSource dataSource()
        {
            final MysqlDataSource dataSource = new MysqlDataSource();

            dataSource.setServerName("localhost");
            dataSource.setDatabaseName("PSH");
            dataSource.setUser("root");
            dataSource.setPassword("password");

            return dataSource;
        }


        @Bean
        public Properties hibernateProperties()
        {
            final Properties properties = new Properties();

            properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
            properties.put("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
            // properties.put("hibernate.connection.driver_class", "mysql-pool-xa");
            // properties.put("hibernate.hbm2ddl.auto", "create-drop");

            return properties;
        }


        public EntityManagerFactory getEntityManagerFactory()
        {
            // _entityManagerFactory = Persistence.createEntityManagerFactory("Config");

            if (_entityManagerFactory == null)
                _entityManagerFactory = getEntityManagerFactory(dataSource(), hibernateProperties());
            return _entityManagerFactory;
        }


        @Bean
        public EntityManagerFactory getEntityManagerFactory(DataSource dataSource, Properties hibernateProperties)
        {
            final LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean();
            //emfBean.setPersistenceUnitName("Config");
            emfBean.setDataSource(dataSource);
            emfBean.setPackagesToScan(new String[] { "info.test.configuration.data" });
            emfBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
            emfBean.setJpaProperties(hibernateProperties);
            emfBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
            //emfBean.setPersistenceXmlLocation("META-INF/persistence.xml");
            emfBean.afterPropertiesSet();

            return emfBean.getObject();
        }

    }

不幸的是,Spring / LocalContainerEntityManagerFactoryBean似乎坚持使用相应的persistence.xml文件,为此可以覆盖所有已定义的属性。这很好,除了在Karaf 4.0.0中部署时我无法获取此代码来查找persistence.xml文件。 Karaf提供的堆栈跟踪如下:

    javax.persistence.PersistenceException: Unable to resolve persistence unit root URL
        at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.determineDefaultPersistenceUnitRootUrl(DefaultPersistenceUnitManager.java:591)[158:org.apache.servicemix.bundles.spring-orm:4.1.6.RELEASE_1]
        at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.preparePersistenceUnitInfos(DefaultPersistenceUnitManager.java:443)[158:org.apache.servicemix.bundles.spring-orm:4.1.6.RELEASE_1]
        at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.afterPropertiesSet(DefaultPersistenceUnitManager.java:424)[158:org.apache.servicemix.bundles.spring-orm:4.1.6.RELEASE_1]
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:310)[158:org.apache.servicemix.bundles.spring-orm:4.1.6.RELEASE_1]
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)[158:org.apache.servicemix.bundles.spring-orm:4.1.6.RELEASE_1]
        at info.leonard.configuration.service.impl.AbstractConfigurationServiceImpl.getEntityManagerFactory(AbstractConfigurationServiceImpl.java:83)[195:leonard-configuration-businessLogic:0.0.1.SNAPSHOT]
        at info.leonard.configuration.service.impl.AbstractConfigurationServiceImpl.getEntityManagerFactory(AbstractConfigurationServiceImpl.java:67)[195:leonard-configuration-businessLogic:0.0.1.SNAPSHOT]
        at info.leonard.configuration.service.impl.ConfigurationDomainServiceImpl.createDomain(ConfigurationDomainServiceImpl.java:80)[195:leonard-configuration-businessLogic:0.0.1.SNAPSHOT]
        at info.leonard.configuration.command.domain.CreateDomainCommand.execute(CreateDomainCommand.java:34)[195:leonard-configuration-businessLogic:0.0.1.SNAPSHOT]
        at org.apache.karaf.shell.commands.basic.AbstractCommand.execute(AbstractCommand.java:34)[43:org.apache.karaf.shell.core:4.0.0]
        at org.apache.karaf.shell.compat.CommandTracker$1.execute(CommandTracker.java:109)[43:org.apache.karaf.shell.core:4.0.0]
        at org.apache.karaf.shell.impl.console.osgi.secured.SecuredCommand.execute(SecuredCommand.java:67)[43:org.apache.karaf.shell.core:4.0.0]
        at org.apache.karaf.shell.impl.console.osgi.secured.SecuredCommand.execute(SecuredCommand.java:87)[43:org.apache.karaf.shell.core:4.0.0]
        at org.apache.felix.gogo.runtime.Closure.executeCmd(Closure.java:480)[43:org.apache.karaf.shell.core:4.0.0]
        at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:406)[43:org.apache.karaf.shell.core:4.0.0]
        at org.apache.felix.gogo.runtime.Pipe.run(Pipe.java:108)[43:org.apache.karaf.shell.core:4.0.0]
        at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:182)[43:org.apache.karaf.shell.core:4.0.0]
        at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:119)[43:org.apache.karaf.shell.core:4.0.0]
        at org.apache.felix.gogo.runtime.CommandSessionImpl.execute(CommandSessionImpl.java:94)[43:org.apache.karaf.shell.core:4.0.0]
        at org.apache.karaf.shell.impl.console.ConsoleSessionImpl.run(ConsoleSessionImpl.java:267)[43:org.apache.karaf.shell.core:4.0.0]
        at java.lang.Thread.run(Thread.java:745)[:1.7.0_60-ea]
    Caused by: java.io.FileNotFoundException: class path resource [] cannot be resolved to URL because it does not exist
        at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:187)[155:org.apache.servicemix.bundles.spring-core:4.1.6.RELEASE_1]
        at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.determineDefaultPersistenceUnitRootUrl(DefaultPersistenceUnitManager.java:588)[158:org.apache.servicemix.bundles.spring-orm:4.1.6.RELEASE_1]
        ... 20 more

在Karaf 4.0.0中,已加载以下弹簧功能:

@root()> feature:list | grep spring
spring                          | 4.1.6.RELEASE_1                  |          | Started     | spring-4.0.0             | Spring 4.1.x support
spring-aspects                  | 4.1.6.RELEASE_1                  |          | Uninstalled | spring-4.0.0             | Spring 4.1.x AOP support
spring-instrument               | 4.1.6.RELEASE_1                  |          | Uninstalled | spring-4.0.0             | Spring 4.1.x Instrument support
spring-jdbc                     | 4.1.6.RELEASE_1                  |          | Started     | spring-4.0.0             | Spring 4.1.x JDBC support
spring-jms                      | 4.1.6.RELEASE_1                  |          | Uninstalled | spring-4.0.0             | Spring 4.1.x JMS support
spring-test                     | 4.1.6.RELEASE_1                  |          | Uninstalled | spring-4.0.0             | Spring 4.1.x Test support
spring-orm                      | 4.1.6.RELEASE_1                  | x        | Started     | spring-4.0.0             | Spring 4.1.x ORM support
spring-oxm                      | 4.1.6.RELEASE_1                  |          | Uninstalled | spring-4.0.0             | Spring 4.1.x OXM support
spring-tx                       | 4.1.6.RELEASE_1                  |          | Started     | spring-4.0.0             | Spring 4.1.x Transaction (TX) support
spring-web                      | 4.1.6.RELEASE_1                  |          | Uninstalled | spring-4.0.0             | Spring 4.1.x Web support
spring-web-portlet              | 4.1.6.RELEASE_1                  |          | Uninstalled | spring-4.0.0             | Spring 4.1.x Web Portlet support
spring-websocket                | 4.1.6.RELEASE_1                  |          | Uninstalled | spring-4.0.0             | Spring 4.1.x WebSocket support
spring-security                 | 3.1.4.RELEASE                    |          | Uninstalled | spring-4.0.0             | Spring Security 3.1.x support

另外,我的pom.xml如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>info.leonard.configuration</groupId>
    <artifactId>leonard-configuration-businessLogic</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>bundle</packaging>
    <parent>
        <groupId>info.leonard.configuration</groupId>
        <artifactId>leonard-configuration</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../leonard-configuration</relativePath>
    </parent>

    <properties>
        <log4j-version>1.2.16</log4j-version>
        <slf4j-version>1.6.1</slf4j-version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
            </plugin>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                        <Bundle-Version>${project.version}</Bundle-Version>
                        <Import-Package>
                            org.apache.felix.service.command;version="[0.6,1)",
                            org.apache.felix.gogo.commands;version="[0.6,1)",
                            org.apache.karaf.shell.console;version="[2.2,4)",
                            com.mysql.jdbc,
                            org.hibernate,
                            org.hibernate.cfg,
                            org.hibernate.service,
                            org.hibernate.jpa,
                            org.hibernate.proxy,
                            org.hibernate.annotations,
                            org.springframework.context.annotation,
                            org.springframework.orm.jpa,
                            org.springframework.orm.jpa.vendor,
                            *,
                            javassist.util.proxy
                            info.leonard.foundation.common.*,
                            info.leonard.foundation.database.*,
                            info.leonard.foundation.environment.*,
                            info.leonard.foundation.exception.*,
                            info.leonard.foundation.finance.*,
                            info.leonard.foundation.finance.exception.*,
                            info.leonard.foundation.identity.*,
                            info.leonard.foundation.localization.*
                        </Import-Package>
                        <Export-Package>
                            info.leonard.configuration.data,
                            info.leonard.configuration.data.dao,
                            info.leonard.configuration.data.exception
                        </Export-Package>
                        <DynamicImport-Package>com.mysql.jdbc</DynamicImport-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.apache.karaf.shell</groupId>
            <artifactId>org.apache.karaf.shell.console</artifactId>
            <version>4.0.0.M2</version>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.core</artifactId>
            <version>4.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.enterprise</artifactId>
            <version>4.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
            <version>1.0.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-osgi</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.common</groupId>
            <artifactId>hibernate-commons-annotations</artifactId>
            <version>4.0.4.Final</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.35</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j-version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j-version}</version>
        </dependency>

        <dependency>
            <groupId>info.leonard.foundation</groupId>
            <artifactId>leonard-foundation-businessLogic</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.apache.servicemix.bundles</groupId>
            <artifactId>org.apache.servicemix.bundles.commons-dbcp</artifactId>
            <version>1.4_3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.0-beta1</version>
        </dependency>
    </dependencies>
</project>

这似乎是某种类别的类路径问题:

  • jira.spring.io/browse/SPR-8832

我的问题是:

  • 让其他人采用无XML方法在Karaf / OSGI中初始化JPA,并分享他们的方法
  • 如果这是阻止LocalContainerEntityManagerFactoryBean在resources / META-INF目录中查找persistence.xml的类路径问题,是否有建议的解决方案?

提前致谢, 好色

1 个答案:

答案 0 :(得分:0)

对于初学者,我会尝试将您的配置更改为以下内容。

public class AbstractConfigurationServiceImpl extends AbstractDao {

    @Bean
    public DataSource dataSource()
    {
        final MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setServerName("localhost");
        dataSource.setDatabaseName("PSH");
        dataSource.setUser("root");
        dataSource.setPassword("password");
        return dataSource;
    }


    @Bean
    public FactoryBean<EntityManagerFactory> entityManagerFactory()
    {
        final LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean();
        emfBean.setDataSource(dataSource());
        emfBean.setPackagesToScan(new String[] { "info.test.configuration.data" });
        emfBean.setJpaVendorAdapter(hibernateJpaVendorAdapter());
        return emfBean;
    }

    @Bean
    public JpaVendorAdapter hibernateJpaVendorAdapter(){
        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect"
        return jpaVendorAdapter;
    }

}

您实际上并不需要这些属性,因此您不需要设置JpaDialect,因为您已经设置了JpaVendorAdapter。您还应该让Spring管理生命周期,而不是自己。

有一件事我想知道为什么它在延伸AbstractDao,对我来说,看起来你正在将DAO方法转变为配置appraoch。基本上混合了关注点和责任。这也基于您的堆栈跟踪。

在您的服务中,您应该申请EntityManager而不是EntityManagerFactory。如果你真的想要注入它但不使用配置类作为基类。

@Service
@Transactional
public class ConfigurationDomainServiceImpl implements ConfigurationDomainService {

    @PersistenceContext
    private EntityManager em;

    public void createDomain(...) {
       Domain d = // do whatever is needed to create the domain.
       em.persist(domain);

    }

}