Spring Boot / JPA:为什么 war 转换中断功能 and/or JPA 搜索?
Spring Boot / JPA: Why would war conversion break functionality and/or JPA searches?
我是运行一个基于社区版Broadleaf Commerce演示站点(辣酱)的应用。
为了试验 CI 和部署选项,我们已按照 broadleaf and spring 文档将库存 spring 引导包(jar)转换为 war。
转换后,应用程序将正常启动,但似乎某些数据库 (JPA) 交互已中断(搜索和数据库更新时出错)。
我有几个相关的问题:
- 当从 jar 转换为 war 时,initialize/access JPA(通过 Hibernate)资源是否需要额外的配置或注意事项?spring 文档中指定的内容以上?
- 运行 通过 Maven 目标
mvn
spring-boot:run
(成功)与 运行 java -jar <war-file>
之间有什么区别
(失败)?
- 特别是与我看到的关于 JPA 标准路径的错误(复制在下面)相关,我发现这个 SO post 表明它可能是一个实现问题。但回到问题 #2,如果是这样的话,如果是代码问题,为什么我 运行 应用程序的方式很重要?
可能相关的信息:
- 我已验证数据库正在通过其他客户端响应。
错误信息:
2018-11-08 17:46:22.578 INFO 17053 --- [nio-8443-exec-7] o.h.cache.internal.StandardQueryCache : HHH000248: Starting query cache at region: query.Order
2018-11-08 17:46:22.820 ERROR 17053 --- [nio-8443-exec-7] .BroadleafSimpleMappingExceptionResolver : Error caught and handled.:05d420e6-69fc-4098-b085-2f8393a9ad7f
org.springframework.dao.InvalidDataAccessApiUsageException: Unable to resolve attribute [archiveStatus] against path; nested exception is java.lang.IllegalArgumentException: Unable to resolve attribute [archiveStatus] against path
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:384) ~[spring-orm-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:246) ~[spring-orm-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
...
Caused by: java.lang.IllegalArgumentException: Unable to resolve attribute [archiveStatus] against path
at org.hibernate.ejb.criteria.path.AbstractPathImpl.unknownAttribute(AbstractPathImpl.java:120) ~[hibernate-entitymanager-4.1.11.Final.jar!/:4.1.11.Final]
at org.hibernate.ejb.criteria.path.AbstractPathImpl.locateAttribute(AbstractPathImpl.java:229) ~[hibernate-entitymanager-4.1.11.Final.jar!/:4.1.11.Final]
at org.hibernate.ejb.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:200) ~[hibernate-entitymanager-4.1.11.Final.jar!/:4.1.11.Final]
at org.broadleafcommerce.core.search.dao.SearchFacetDaoImpl.readAllSearchFacets(SearchFacetDaoImpl.java:65) ~[broadleaf-framework-5.2.6-GA.jar!/:na]
at org.broadleafcommerce.core.search.dao.SearchFacetDaoImpl$$FastClassBySpringCGLIB$73d5b3.invoke(<generated>) ~[broadleaf-framework-5.2.6-GA.jar!/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:736) ~[spring-aop-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
... 150 common frames omitted
Spring 引导应用程序配置文件:
@SpringBootApplication
@EnableAutoConfiguration
public class SiteApplication extends SpringBootServletInitializer {
@Configuration
@EnableBroadleafSiteAutoConfiguration
public static class BroadleafFrameworkConfiguration {}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SiteApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SiteApplication.class, args);
}
}
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<groupId>org.broadleafcommerce</groupId>
<artifactId>broadleaf-boot-starter-parent</artifactId>
<version>5.2.6-GA</version>
</parent>
<artifactId>our-site</artifactId>
<packaging>war</packaging>
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
...
</dependencies>
...
</project>
存档状态class(根据错误消息)
@Embeddable
public class ArchiveStatus implements Serializable, SandBoxNonProductionSkip {
@Column(name = "ARCHIVED")
@AdminPresentation(friendlyName = "archived", visibility = VisibilityEnum.HIDDEN_ALL, group = "ArchiveStatus")
protected Character archived = 'N';
public Character getArchived() {
return archived;
}
public void setArchived(Character archived) {
this.archived = archived;
}
}
产品Class(嵌入存档状态)
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@javax.persistence.Table(name = "BLC_PRODUCT")
//multi-column indexes don't appear to get exported correctly when declared at the field level, so declaring here as a workaround
@org.hibernate.annotations.Table(appliesTo = "BLC_PRODUCT", indexes = {
@Index(name = "PRODUCT_URL_INDEX",
columnNames = {"URL", "URL_KEY"}
)
})
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "blProducts")
... (BLC-specific overrides ommitted) ...
public class ProductImpl implements Product, ProductAdminPresentation, Status, AdminMainEntity, Locatable, TemplatePathContainer {
...
@Embedded
protected ArchiveStatus archiveStatus = new ArchiveStatus();
...
}
DAO 方法:
public List<SearchFacet> readAllSearchFacets(FieldEntity entityType) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<SearchFacet> criteria = builder.createQuery(SearchFacet.class);
Root<SearchFacetImpl> facet = criteria.from(SearchFacetImpl.class);
criteria.select(facet);
Path<Character> archived = facet.get("archiveStatus").get("archived");
criteria.where(
builder.equal(facet.get("showOnSearch").as(Boolean.class), true),
builder.or(builder.isNull(archived.as(String.class)),
builder.notEqual(archived.as(Character.class), 'Y')),
facet.join("fieldType")
.join("indexField")
.join("field")
.get("entityType")
.as(String.class)
.in(entityType.getAllLookupTypes())
);
TypedQuery<SearchFacet> query = em.createQuery(criteria);
query.setHint(QueryHints.HINT_CACHEABLE, true);
query.setHint(QueryHints.HINT_CACHE_REGION, "query.Search");
return query.getResultList();
}
我在 运行 DemoSite 通过编译的 jarfile 时发现了同样的错误。
看看这个话题:https://github.com/BroadleafCommerce/DemoSite/issues/51
在我的例子中,我必须在站点的 pom.xml 中包含 spring-instrument
依赖项,并使用 -javaagent
参数指定其 jar 位置:
$ java -Xmx1024m -javaagent:./path/to/spring-instrument.jar -jar site.jar
我是运行一个基于社区版Broadleaf Commerce演示站点(辣酱)的应用。
为了试验 CI 和部署选项,我们已按照 broadleaf and spring 文档将库存 spring 引导包(jar)转换为 war。
转换后,应用程序将正常启动,但似乎某些数据库 (JPA) 交互已中断(搜索和数据库更新时出错)。
我有几个相关的问题:
- 当从 jar 转换为 war 时,initialize/access JPA(通过 Hibernate)资源是否需要额外的配置或注意事项?spring 文档中指定的内容以上?
- 运行 通过 Maven 目标
mvn spring-boot:run
(成功)与 运行java -jar <war-file>
之间有什么区别 (失败)? - 特别是与我看到的关于 JPA 标准路径的错误(复制在下面)相关,我发现这个 SO post 表明它可能是一个实现问题。但回到问题 #2,如果是这样的话,如果是代码问题,为什么我 运行 应用程序的方式很重要?
可能相关的信息:
- 我已验证数据库正在通过其他客户端响应。
错误信息:
2018-11-08 17:46:22.578 INFO 17053 --- [nio-8443-exec-7] o.h.cache.internal.StandardQueryCache : HHH000248: Starting query cache at region: query.Order
2018-11-08 17:46:22.820 ERROR 17053 --- [nio-8443-exec-7] .BroadleafSimpleMappingExceptionResolver : Error caught and handled.:05d420e6-69fc-4098-b085-2f8393a9ad7f
org.springframework.dao.InvalidDataAccessApiUsageException: Unable to resolve attribute [archiveStatus] against path; nested exception is java.lang.IllegalArgumentException: Unable to resolve attribute [archiveStatus] against path
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:384) ~[spring-orm-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:246) ~[spring-orm-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
...
Caused by: java.lang.IllegalArgumentException: Unable to resolve attribute [archiveStatus] against path
at org.hibernate.ejb.criteria.path.AbstractPathImpl.unknownAttribute(AbstractPathImpl.java:120) ~[hibernate-entitymanager-4.1.11.Final.jar!/:4.1.11.Final]
at org.hibernate.ejb.criteria.path.AbstractPathImpl.locateAttribute(AbstractPathImpl.java:229) ~[hibernate-entitymanager-4.1.11.Final.jar!/:4.1.11.Final]
at org.hibernate.ejb.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:200) ~[hibernate-entitymanager-4.1.11.Final.jar!/:4.1.11.Final]
at org.broadleafcommerce.core.search.dao.SearchFacetDaoImpl.readAllSearchFacets(SearchFacetDaoImpl.java:65) ~[broadleaf-framework-5.2.6-GA.jar!/:na]
at org.broadleafcommerce.core.search.dao.SearchFacetDaoImpl$$FastClassBySpringCGLIB$73d5b3.invoke(<generated>) ~[broadleaf-framework-5.2.6-GA.jar!/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:736) ~[spring-aop-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.18.RELEASE.jar!/:4.3.18.RELEASE]
... 150 common frames omitted
Spring 引导应用程序配置文件:
@SpringBootApplication
@EnableAutoConfiguration
public class SiteApplication extends SpringBootServletInitializer {
@Configuration
@EnableBroadleafSiteAutoConfiguration
public static class BroadleafFrameworkConfiguration {}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SiteApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(SiteApplication.class, args);
}
}
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<groupId>org.broadleafcommerce</groupId>
<artifactId>broadleaf-boot-starter-parent</artifactId>
<version>5.2.6-GA</version>
</parent>
<artifactId>our-site</artifactId>
<packaging>war</packaging>
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
...
</dependencies>
...
</project>
存档状态class(根据错误消息)
@Embeddable
public class ArchiveStatus implements Serializable, SandBoxNonProductionSkip {
@Column(name = "ARCHIVED")
@AdminPresentation(friendlyName = "archived", visibility = VisibilityEnum.HIDDEN_ALL, group = "ArchiveStatus")
protected Character archived = 'N';
public Character getArchived() {
return archived;
}
public void setArchived(Character archived) {
this.archived = archived;
}
}
产品Class(嵌入存档状态)
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@javax.persistence.Table(name = "BLC_PRODUCT")
//multi-column indexes don't appear to get exported correctly when declared at the field level, so declaring here as a workaround
@org.hibernate.annotations.Table(appliesTo = "BLC_PRODUCT", indexes = {
@Index(name = "PRODUCT_URL_INDEX",
columnNames = {"URL", "URL_KEY"}
)
})
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "blProducts")
... (BLC-specific overrides ommitted) ...
public class ProductImpl implements Product, ProductAdminPresentation, Status, AdminMainEntity, Locatable, TemplatePathContainer {
...
@Embedded
protected ArchiveStatus archiveStatus = new ArchiveStatus();
...
}
DAO 方法:
public List<SearchFacet> readAllSearchFacets(FieldEntity entityType) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<SearchFacet> criteria = builder.createQuery(SearchFacet.class);
Root<SearchFacetImpl> facet = criteria.from(SearchFacetImpl.class);
criteria.select(facet);
Path<Character> archived = facet.get("archiveStatus").get("archived");
criteria.where(
builder.equal(facet.get("showOnSearch").as(Boolean.class), true),
builder.or(builder.isNull(archived.as(String.class)),
builder.notEqual(archived.as(Character.class), 'Y')),
facet.join("fieldType")
.join("indexField")
.join("field")
.get("entityType")
.as(String.class)
.in(entityType.getAllLookupTypes())
);
TypedQuery<SearchFacet> query = em.createQuery(criteria);
query.setHint(QueryHints.HINT_CACHEABLE, true);
query.setHint(QueryHints.HINT_CACHE_REGION, "query.Search");
return query.getResultList();
}
我在 运行 DemoSite 通过编译的 jarfile 时发现了同样的错误。
看看这个话题:https://github.com/BroadleafCommerce/DemoSite/issues/51
在我的例子中,我必须在站点的 pom.xml 中包含 spring-instrument
依赖项,并使用 -javaagent
参数指定其 jar 位置:
$ java -Xmx1024m -javaagent:./path/to/spring-instrument.jar -jar site.jar