在FUSE EAP环境中使用SpringBoot时,这可能对我来说是一个误解。我一直在尝试部署服务,该服务是根据RedHat文档以及我在网上找到的混合了Camel和SpringBoot的原型/示例而开发的,但无济于事。
据我了解,当创建到EAP Fuse服务器中已配置和测试的JNDI数据源的连接时,我可以使用application.properties或application.yml来让spring应用程序自动配置连接。就我而言,由于扩展JpaRepository的CRUD操作并不能真正满足需求,因此需要使用@PersistenceContext来调用EntityManager。
根据RedHat的文档,FUSE 7.2已安装在EAP 7.1中,并且POM使用的是org.jboss.redhat-fuse.fuse-springboot-bom版本7.2.0.fuse-720020-redhat-00001。
我尝试使用spring的自动配置,声明@Configuration类的手动配置,通过camel-context.xml文件声明数据库连接的手动配置以及其他一些次要测试。
根据我是否尝试通过使spring-boot-maven-plugin具有重新打包执行目标而生成的.jar或.jar.original,错误会有所不同,到目前为止,获得的错误是:
这是我的程序的片段,其中包括POM,Application.java和试图获取EntityManager的组件,如果不够/不清楚,将乐意提供更多片段。
POM.xml
...
<properties>
<fuse.version>7.2.0.fuse-720020-redhat-00001</fuse.version>
...
</properties>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
...
<build>
<defaultGoal>spring-boot:run</defaultGoal>
<plugins>
...
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.16.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
...
application.properties
spring.datasource.jndi-name=jdbc:sqlserver://ip:1433;DatabaseName=dbname
spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.generate-ddl=false
Application.java
@ImportResource({"classpath:spring/camel-context.xml"})
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
camel-context.xml
<beans ...>
...
<camelContext id="identidades_financieras" xmlns="http://camel.apache.org/schema/spring">
<onException>
<exception>java.lang.Exception</exception>
<handled>
<constant>true</constant>
</handled>
<setHeader headerName="Exchange.HTTP_RESPONSE_CODE">
<constant>500</constant>
</setHeader>
<setBody>
<simple>${exception.message}</simple>
</setBody>
</onException>
<restConfiguration apiContextPath="/openapi.json"
bindingMode="json" component="undertow"
contextPath="/restservice/api_v1" enableCORS="true">
<dataFormatProperty key="prettyPrint" value="true"/>
</restConfiguration>
<rest enableCORS="true" id="rest-for-openapi-document" path="/openapi">
<get id="openapi.json" produces="application/json" uri="openapi.json">
<description>Gets the OpenAPI document for this service</description>
<route id="route-for-openapi-document">
<setHeader headerName="Exchange.CONTENT_TYPE" id="setHeader-for-openapi-document">
<constant>application/vnd.oai.openapi+json</constant>
</setHeader>
<setBody id="setBody-for-openapi-document">
<constant>resource:classpath:openapi.json</constant>
</setBody>
</route>
</get>
</rest>
<rest bindingMode="auto" enableCORS="true"
id="rest-b5d099c1-1996-458b-b5db-34aadc57a548" path="/">
<get id="customPaginatexxxVO" produces="application/json" uri="/xxx">
<to uri="direct:customPaginatexxxVO"/>
</get>
...
<route id="route-28f4489d-b354-401b-b774-6425bec1c120">
<from id="from-17c4205f-8d28-4d3d-a265-cb1c38c9bc32" uri="direct:customPaginatexxxVO"/>
<log id="customPaginatexxxVO-log-1" message="headers ====> pageSize: ${header.pageSize} - pageNumber: ${header.pageNumber}"/>
<bean id="to-ee6565efaf-de46-4941-b119-be7aaa07d892"
method="paginate" ref="genericService"/>
<log id="customPaginatexxxVO-log-2" message="${body}"/>
</route>
<beans/>
genericService.java
@Service
public class genericServiceImpl implements genericService {
@Autowired
private genericDAO dao;
...
@Override
public xxxVO paginate(Map<String, Object> reqHeaders) {
... pageProps are defined using reqHeaders ...
xxxVO paginated = dao.customPagination(pageProps);
return paginated;
}
...
}
genericDAOImpl.java,当调用有关em的任何内容时都会出错。
@Repository
public class genericDAOImpl implements genericDAO {
@PersistenceContext //when manually configured, I've added the (unitName="") in reference to the persistence unit, from my understanding, since only one datasource was created, this should pick up by default
private EntityManager em;
...
@Override
public xxxVO customPagination(paginateProps pageProps) {
xxxVO result = null;
try {
CriteriaBuilder paginationBuilder = em.getCriteriaBuilder();
CriteriaQuery<T> paginationQuery = paginationBuilder.createQuery(entity.class);
Root<T> entityClass = paginationQuery.from(entity.class);
paginationQuery.select(entityClass);
... some settings with pageProps ...
TypedQuery<T> query = em.createQuery(paginationQuery);
entityList = query.getResultList();
... entityList is transformed to xxxVO ...
} catch (Exception e) {
LOG.error("caught something");
e.printStackTrace();
}
return result;
}
...
如前所述,根据我尝试过的选项,我遇到了许多不同的错误,并且大多数错误显然归因于配置错误或未正确部署,在谈到SpringBoot时,我还是没有经验和骆驼(Camel),以及我在互联网上阅读的不同内容引起了一些混乱。为了确保,分页方法虽然很简单,但如果它的EntityManager没有为空,则应该可以使用。
以下是一些日志:
根据我所做的测试,在解析.jar(具有所有依赖关系的胖jar)时,可以使用java -jar进行正确部署,但不能在保险丝eap服务中进行部署
09:16:01,937 WARN [org.springframework.context.support.GenericApplicationContext] (MSC service thread 1-3) Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [com.example.dao.genericDAOImpl] for bean with name 'genericDAO' defined in URL [vfs:/content/identidades_financieras-1.0-SNAPSHOT.jar/BOOT-INF/classes/spring/camel-context.xml]; nested exception is java.lang.ClassNotFoundException: com.example.dao.genericDAOImpl from [Module "deployment.identidades_financieras-1.0-SNAPSHOT.jar" from Service Module Loader]
09:16:01,940 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-3) MSC000001: Failed to start service jboss.deployment.unit."identidades_financieras-1.0-SNAPSHOT.jar".CamelContextActivationService."identidades_financieras-1.0-SNAPSHOT.jar": org.jboss.msc.service.StartException in service jboss.deployment.unit."identidades_financieras-1.0-SNAPSHOT.jar".CamelContextActivationService."identidades_financieras-1.0-SNAPSHOT.jar": Cannot create camel context: identidades_financieras-1.0-SNAPSHOT.jar
at org.wildfly.extension.camel.service.CamelContextActivationService.start(CamelContextActivationService.java:71)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:2032)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1955)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [com.example.dao.genericDAOImpl] for bean with name 'genericDAO' defined in URL [vfs:/content/identidades_financieras-1.0-SNAPSHOT.jar/BOOT-INF/classes/spring/camel-context.xml]; nested exception is java.lang.ClassNotFoundException: com.example.dao.genericDAO from [Module "deployment.identidades_financieras-1.0-SNAPSHOT.jar" from Service Module Loader]
...
使用手动配置的DataSource和EntityManagerFactory部署.jar.original(基本上只是Java)时。据我了解,该服务期望org.springframework.boot依赖项存在于服务器上。检查模块后,保险丝层中没有org.springframework.boot模块。这是故意的吗?
09:50:17,265 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-8) MSC000001: Failed to start service jboss.deployment.unit."identidades_financieras-1.0-SNAPSHOT.jar".CamelContextActivationService."identidades_financieras-1.0-SNAPSHOT.jar": org.jboss.msc.service.StartException in service jboss.deployment.unit."identidades_financieras-1.0-SNAPSHOT.jar".CamelContextActivationService."identidades_financieras-1.0-SNAPSHOT.jar": Failed to start service
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1978)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/orm/jpa/EntityManagerFactoryBuilder
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.getDeclaredMethods(Class.java:1975)
at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:613)
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:524)
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:510)
at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:570)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:697)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:640)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:609)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1490)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:425)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:395)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:96)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525)
at org.wildfly.extension.camel.SpringCamelContextBootstrap$1.run(SpringCamelContextBootstrap.java:90)
at org.wildfly.extension.camel.proxy.ProxyUtils$1.invoke(ProxyUtils.java:51)
at com.sun.proxy.$Proxy68.run(Unknown Source)
at org.wildfly.extension.camel.proxy.ProxyUtils.invokeProxied(ProxyUtils.java:55)
at org.wildfly.extension.camel.SpringCamelContextBootstrap.createSpringCamelContexts(SpringCamelContextBootstrap.java:87)
at org.wildfly.extension.camel.service.CamelContextActivationService.start(CamelContextActivationService.java:58)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:2032)
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1955)
... 3 more
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder from [Module "deployment.identidades_financieras-1.0-SNAPSHOT.jar" from Service Module Loader]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:198)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:412)
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:400)
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116)
... 27 more
最后,当仅使用Spring自动配置上传.jar.original时,EM为空,使用邮递员,当我使用REST时,状态为500,“无响应”
java.lang.NullPointerException
at com.example.dao.genericDAOImpl.customPagination(GenericDAOImpl.java:252)
该行引用了CriteriaBuilder paginationBuilder = em.getCriteriaBuilder()或调用EM方法的任何其他地方。
感谢您的宝贵时间!任何评论表示赞赏...
答案 0 :(得分:2)
不支持使用Fuse EAP和Camel子系统的Spring Boot。因此,为什么在保险丝模块层中看不到任何org.springframework.boot
依赖项。
如果要将Camel Spring Boot应用程序部署到EAP中,最好禁用Camel子系统进行部署,或者避免完全安装子系统。
答案 1 :(得分:0)
这绝不是解决我遇到的问题的方法,我认为这只是我代码上的一个临时补丁,因为7.4版本的Fuse据说将支持SpringBoot 2.1.x或类似的东西,但是这样做以下内容使我能够创建数据库连接并继续我的生活。除非被告知这是唯一的方法,否则我不会将其标记为可接受的答案。
在Application.java中,我直接禁用了SpringBootServletInitializer。完全公开了,我直截了当地不知道这样做会对应用程序产生什么影响,但是在我尝试部署时,依赖性令人不安。
@ImportResource({"classpath:spring/camel-context.xml"})
@SpringBootApplication
public class Application {//extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
我创建了一个persistence.xml文件,在其中配置了持久性单元的名称,并选择了包含实体的包(或列出了它们,两者都可以使用)。
在camel-context.xml中,我在标记之前声明了以下内容
<bean class="org.apache.camel.component.jpa.JpaComponent" id="jpa">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="transactionManager" ref="jpaTxManager"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="jpaTxManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="PERSISTENCE UNIT NAME IN PERSISTENCE.XML"/>
</bean>
<bean class="org.apache.camel.spring.spi.SpringTransactionPolicy" id="requiredPolicy">
<property name="transactionManager" ref="jpaTxManager"/>
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
</bean>
我创建了一个负责创建EntityManager的Java类,该类是@Stateless(EJB),并且使与持久性单元的连接保持静态非常重要。
@Stateless
public class persistenceUnitEntityManagerImpl implements IfEntityManager{
private static EntityManager em;
static {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("PERSISTENCE UNIT NAME");
em = entityManagerFactory.createEntityManager();
}
public void setEntityManager( EntityManager em ) {
persistenceUnitEntityManagerImpl.em = em;
}
public EntityManager getEntityManager() {
return persistenceUnitEntityManagerImpl.em;
}
}
在需要数据库连接的Bean中,以我为例,使用@Component(在@Repository中应该也一样),我添加了以下内容:
private IfEntityManagerImpl IfEntityManager;
@PostConstruct
public void init() {
this.persistenceUnitEntityManagerImpl = new persistenceUnitEntityManagerImpl();
}
每当需要调用EntityManager时,我都可以使用persistenceUnitEntityManagerImpl.getEntityManager()
只要确保该组件不会创建新的连接/实体管理器/其他内容,就可以将LOG添加到@PostConstruct初始化中,如果您的bean是单例的(我相信默认情况下应该是)永远不会获得该日志或打印行。