Spring + Spring Data JPA в Java SE автономно
Я пытаюсь создать простой JAR с возможностями Spring + Spring Data + Hibernate. Это работает, когда я только что разделил Spring или Hibernate + JPA, но не когда я собираю их все вместе.
Возможен ли этот тип конфигурации?
Я использую плагин сборки Maven просто для создания JAR с зависимостями.
Я также указываю конкретные пакеты для сканирования сущностей JPA, и это работает с eclipse, но не при выполнении одного JAR.
Моя конфигурация свободна от XML (там нет ни persistence.xml, ни application.xml), и теперь она ищет persistence.xml. если я помещаю файл в META-INF/persisntece.xml, ошибка остается той же.
Обновлено: ConfigPersistence
@Configuration
@ComponentScan(basePackageClasses=_PackageTypeSafeClassModel.class)
@EnableJpaRepositories(basePackageClasses=_PackageTypeSafeClassModelRepositories.class)
@EnableTransactionManagement
@Import(ConfigProperties.class)
public class ConfigPersistence {
private static final Logger LOGGER = LoggerFactory.getLogger(LogNames.CONFIGURATION.toString());
/* Connection properties */
@Value("${db.user}") private String propDBUser;
@Value("${db.pass}") private String propDBPass;
@Value("${db.host}") private String propDBHost;
@Value("${db.port}") private String propDBPort;
@Value("${db.database}") private String propDBDatabase;
/* Pool properties */
@Value("${db.pool.datasource}") private String propDatasource;
@Value("${db.pool.setMinimumIdle}") private Integer propSetMinimumIdle;
@Value("${db.pool.setIdleTimeout}") private Integer propSetIdleTimeout;
@Value("${db.pool.setMaximumPoolSize}") private Integer propSetMaximumPoolSize;
@Value("${db.pool.setConnectionTimeout}") private Integer propSetConnectionTimeout;
/* Hibernate properties */
@Value("${db.hibernate.hbm2ddl.auto}") private String propHibernateHbm2ddl;
@Value("${db.hibernate_dialect}") private String propHibernateDialect;
@Value("${db.hibernate.show_sql}") private String propHibernateShowSql;
@Value("${db.hibernate.format_sql}") private String propHibernateFormatSql;
@Value("${db.hibernate.generate_statistics}") private String propHibernateStatistics;
@Value("${db.hibernate.use_sql_comments}") private String propHibernateSqlComments;
@Value("${db.hibernate.connection.autocommit}") private String propHibernateAutocommit;
@Value("${db.hibernate.mapping.precedence}") private String propHibernatePrecedence;
@Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPackagesToScan(_PackageTypeSafeClassModelEntities.class.getPackage().getName());
entityManagerFactoryBean.setJpaVendorAdapter( new HibernateJpaVendorAdapter() );
entityManagerFactoryBean.setJpaProperties(hibernateProperties());
entityManagerFactoryBean.afterPropertiesSet();
return entityManagerFactoryBean.getObject();
}
@Bean
public DataSource dataSource() {
HikariDataSource hikariDS = new HikariDataSource();
/* Hikari Pool configuration */
hikariDS.setPoolName( "HikariCP pool" );
hikariDS.setDataSourceClassName( propDatasource );
hikariDS.setMinimumIdle( propSetMinimumIdle );
hikariDS.setIdleTimeout( propSetIdleTimeout ); // Minutes
hikariDS.setMaximumPoolSize( propSetMaximumPoolSize ); // Connection pool size
hikariDS.setConnectionTimeout( propSetConnectionTimeout ); // Miliseconds
/* Database configuration */
hikariDS.addDataSourceProperty("serverName", propDBHost );
hikariDS.addDataSourceProperty("portNumber", propDBPort );
hikariDS.addDataSourceProperty("databaseName", propDBDatabase );
hikariDS.addDataSourceProperty("user", propDBUser );
hikariDS.addDataSourceProperty("password", propDBPass );
LOGGER.info("Database connection to: {}:{}, database {} with user {}",
propDBHost, propDBPort, propDBDatabase, propDBUser);
return hikariDS;
}
@Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
private Properties hibernateProperties(){
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", propHibernateDialect );
hibernateProperties.setProperty("hibernate.ejb.entitymanager_factory_name", "myEntityManager");
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", propHibernateHbm2ddl );
hibernateProperties.setProperty("hibernate.show_sql", propHibernateShowSql );
hibernateProperties.setProperty("hibernate.format_sql", propHibernateFormatSql );
hibernateProperties.setProperty("hibernate.generate_statistics", propHibernateStatistics );
hibernateProperties.setProperty("hibernate.use_sql_comments", propHibernateSqlComments );
hibernateProperties.setProperty("hibernate.connection.autocommit", propHibernateAutocommit );
hibernateProperties.setProperty("hibernate.mapping.precedence", propHibernatePrecedence);
LOGGER.info("Setting {} hibernateProperties {}", hibernateProperties.size(), hibernateProperties);
return hibernateProperties;
}
}
Ошибка, которую я получаю:
Caused by: javax.persistence.PersistenceException: Unable to resolve persistence unit root URL
at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.determineDefaultPersistenceUnitRootUrl(DefaultPersistenceUnitManager.java:591) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.preparePersistenceUnitInfos(DefaultPersistenceUnitManager.java:443) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.afterPropertiesSet(DefaultPersistenceUnitManager.java:424) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:310) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318) ~[company-monitor-jar-with-dependencies.jar:na]
at com.company.config.ConfigPersistence.entityManagerFactory(ConfigPersistence.java:88) ~[company-monitor-jar-with-dependencies.jar:na]
at com.company.config.ConfigPersistence$$EnhancerBySpringCGLIB$$a1e8e6cc.CGLIB$entityManagerFactory$1(<generated>) ~[company-monitor-jar-with-dependencies.jar:na]
at com.company.config.ConfigPersistence$$EnhancerBySpringCGLIB$$a1e8e6cc$$FastClassBySpringCGLIB$$17999b5a.invoke(<generated>) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:318) ~[company-monitor-jar-with-dependencies.jar:na]
at com.company.config.ConfigPersistence$$EnhancerBySpringCGLIB$$a1e8e6cc.entityManagerFactory(<generated>) ~[company-monitor-jar-with-dependencies.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_91]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_91]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_91]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ~[company-monitor-jar-with-dependencies.jar:na]
... 13 common frames omitted
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) ~[company-monitor-jar-with-dependencies.jar:na]
at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.determineDefaultPersistenceUnitRootUrl(DefaultPersistenceUnitManager.java:588) ~[company-monitor-jar-with-dependencies.jar:na]
... 28 common frames omitted
[ERROR][CONFIGURATION] - [Main.java:30] - 24/05/2016 11:57:05.614 - Exception: Error creating bean with name 'entityManagerFactory' defined in com.company.config.ConfigPersistence: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.persistence.EntityManagerFactory]: Factory method 'entityManagerFactory' threw exception; nested exception is javax.persistence.PersistenceException: Unable to resolve persistence unit root URL
Обновлено: POM Dependencies
<dependencies>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<exclusions>
<exclusion>
<groupId>io.undertow</groupId>
<artifactId>undertow-websockets-jsr</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Databases dependencies -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>${database.oracle.version}</version>
</dependency>
<!-- Hibernate dependencies -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<!-- Connection pool -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!-- Logging: SL4J and LogBack dependencies -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<!-- JCommander -->
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>${jcommander.version}</version>
</dependency>
</dependencies>
2 ответа
Вместо того, чтобы пытаться получить рабочее решение, используя maven-assembly-plugin
Я бы предложил использовать Spring Boot. Это уже позаботится о таких вещах, как установка правильных загрузчиков классов и т. Д.
Начните с перевода вашей конфигурации в application.properties
и используйте имена свойств Spring Boot. Затем вы можете просто удалить свои классы конфигурации (так как Spring Boot автоматически определит, что находится на вашем пути к классам, и настроит соответственно).
Хотя в качестве стратегии миграции вы могли бы начать с собственных классов конфигурации, запустить их, а затем убрать все, что для вас предусмотрено (что, в основном, и все, что вы здесь показали).
Затем создайте начальный класс (в пакете верхнего уровня, чтобы он охватывал все пакеты).
@SpringBootApplication
public class MyApplication {
public static void main(String... args) throws Exception {
SpringApplication.run(MyApplication.class, args);
}
}
Ваши зависимости должны выглядеть примерно так. (выводится из вашего вопроса, но я предполагаю, что есть немного больше).
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
</dependencies>
Это предполагает, что вы используете Spring Boot в качестве родителя для вашего проекта.
Вместо сборочного плагина используйте пружинный загрузочный плагин.
<!-- Package as an executable jar -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Это должно дать вам исполняемый jar без особых усилий и автоматически загрузить ваше приложение.
Согласно предоставленной трассировке стека, вы используете LocalContainerEntityManagerFactoryBean и
LocalContainerEntityManagerFactoryBean создает JPA EntityManagerFactory в соответствии со стандартным контрактом начальной загрузки контейнера JPA ( источник)
Но Spring также предоставляет LocalEntityManagerFactoryBean и
LocalEntityManagerFactoryBean создает JPA EntityManagerFactory в соответствии со стандартным автономным контрактом начальной загрузки JPA ( источник)
Поэтому первое, что нужно сделать, это использовать LocalEntityManagerFactoryBean. Я не знаю, решит ли это все ваши проблемы, но, по крайней мере, это первый шаг, если вы не работаете в контейнере.