Проблемы с использованием автоконфигурации Springboot для подключения к SQL-серверу в среде FUSE EAP - PullRequest
0 голосов
/ 25 июня 2019

С моей стороны это может быть неправильным представлением о работе с SpringBoot в средах FUSE EAP. Я пытался развернуть сервис, который я разработал, следуя документации RedHat и архетипам / примерам, которые я нашел в Интернете, которые смешивают Camel и SpringBoot, но безрезультатно.

Насколько я понимаю, при создании соединения с источником данных JNDI, который был настроен и протестирован на сервере EAP Fuse, я могу использовать application.properties или application.yml, чтобы приложение Spring автоматически настраивало соединение , В моем случае требуется, чтобы я использовал @PersistenceContext для вызова EntityManager, так как операции CRUD, которые расширяющий JpaRepository на самом деле не покрывает потребности.

Согласно документации 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 и некоторые другие незначительные тесты.

Ошибки меняются в зависимости от того, пытаюсь ли я отфильтровать .jar или .jar.original, сгенерированный с помощью плагина spring-boot-maven-plugin с целью выполнения переупаковки, ошибки, полученные до этого момента:

  • NullPointer, так как EntityManager em имеет значение null (.jar.original)
  • java.lang.NoClassDefFoundError: org / springframework / boot / orm / jpa / EntityManagerFactoryBuilder (.jar.original, когда есть ручная конфигурация источника данных, будь то в аннотированном классе Java @Configuration или в camel- context.xml с использованием Spring DSL)
  • java.lang.ClassNotFoundException: com.example.dao.genericDAOImpl (.jar со всеми упакованными зависимостями)

Вот фрагменты моей программы, которые включают 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);
    }
}

верблюд-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 и верблюд, и разные вещи, которые я читал в Интернете, создали некоторую путаницу. Просто чтобы удостовериться, что метод нумерации страниц, хотя и очень урезанный, должен работать, если он имеет ненулевой EntityManager.

Вот пара логов:

При удалении .jar (толстый jar со всеми зависимостями), который из проведенных мною тестов правильно развертывается с использованием java -jar, но не в службе fuse 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]
...

При развертывании .jar.original (в основном, только java) с настроенными вручную DataSource и EntityManagerFactory. Насколько я понимаю, сервис ожидает, что на сервере существуют зависимости 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

Наконец, при загрузке .jar.original с использованием только автоконфигурации Spring EM становится пустым, используя Почтальон, я получаю статус 500 и «Нет ответа» при использовании REST

java.lang.NullPointerException
at com.example.dao.genericDAOImpl.customPagination(GenericDAOImpl.java:252)

Строка ссылается на CriteriaBuilder paginationBuilder = em.getCriteriaBuilder () или любое другое место, где вызывается EM-метод.

Спасибо за ваше время! Любой комментарий приветствуется ...

Ответы [ 2 ]

2 голосов
/ 26 июня 2019

Spring Boot не поддерживается с Fuse EAP и подсистемой Camel. Следовательно, почему вы не видите никаких org.springframework.boot зависимостей на уровне модуля Fuse.

Если вы собираетесь развертывать приложения Camel Spring Boot в EAP, лучше всего либо отключить подсистему Camel для своего развертывания, либо избегать полной установки подсистемы.

0 голосов
/ 26 июня 2019

Это ни в коем случае не решение проблемы, с которой я столкнулся, я считаю, что это временный патч для моего кода, поскольку версия Fuse 7.4 предположительно будет поддерживать 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>

Я создал java-класс, отвечающий за создание EntityManager, очень важно, чтобы класс был @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, если ваш компонент является синглтоном (я думаю, он должен быть по умолчанию), вы никогда не получите этот LOG или printline.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...