我有一个分成 3 个模块的耳朵项目:
- 一个网络模块,
- 一个包含我的实体的 jar 模块,
- 一个ejb模块。
我有一个看起来像这样的类:
public class UserServiceProviderEnterpriseImpl implements UserServiceProvider {
@Override
public UserService getUserService() {
final BeanManager beanManager = CDI.current().getBeanManager();
Bean<?> bean = beanManager.getBeans("userService").iterator().next();
final CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean);
return (UserService) beanManager.getReference(bean, bean.getBeanClass(), creationalContext);
}
}
该类属于实体模块。
该类的一个实例是在我的@Entity 对象的@MappedSuperclass 中的@PreUpdate 挂钩中创建的。这个类(和所说的钩子)看起来像这样:
@MappedSuperclass
@Access(AccessType.FIELD)
public abstract class BusinessObject<T extends Serializable> implements Cloneable {
// [...]
@PrePersist
@PreUpdate
@SuppressWarnings("unchecked")
private void _prePersist() {
// [...]
final User currentUser = getUserServiceProvider().getUserService().getCurrentUser();
// [...]
}
private static UserServiceProvider getUserServiceProvider() {
try {
return SenyuProperties.Core.getUserServiceProviderClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Erreur lors de l'instanciation du UserServiceProvider", e);
}
}
// [...]
}
扩展此实体类的实体类与 UserServiceProviderEnterpriseImpl 类位于同一模块中。
我的问题出现在这一行:
Bean<?> bean = beanManager.getBeans("userService").iterator().next();
...有时会抛出 NoSuchElementException (由 BeanManager#getBeans 方法返回的空 Set 的原因),但有时不会。这个问题似乎是部署范围的,因为我可以部署我的耳朵,这将在每次调用 getUserService() 方法时发生,但在重新部署后,相同的场景可以完全正常工作(BeanManager#getBeans 方法不返回一个空的集合了)。
所以我的问题是:为什么这段代码的行为方式是这样的?难道我做错了什么?这种随机性的来源是什么?
如果这有帮助,我的托管 bean 看起来像这样(它属于 web 模块):
@Named("userService")
@SessionScoped
public class UserServiceEnterpriseImpl implements UserService, Serializable {
@EJB
private UserDAO dao;
private User user;
@Override
public User getCurrentUser() {
return user;
}
@PostConstruct
private void initCurrentUser() {
user = dao.findByUsername((String)SecurityUtils.getSubject().getPrincipal());
}
}
我正在使用 Payara 4.1.1.162。
更新
我已经尝试过但没有用的东西:
- 使用 application.xml 中的 initialize-in-order 标记(设置为 true)并更改模块的顺序,
- 将 Payara 更新到可用的最新版本 (4.1.1.163),
- 通过命令行手动部署应用程序(我通常从 IntelliJ 执行此操作),
- 删除 BusinessObject#getUserServiceProvider() 方法中的“静态”关键字,
- 在我更改 getUserService() 方法代码以使用此答案https://stackoverflow.com/a/40328987/7090063提供的解决方案之后,所有这一切。
根据要求,这是我唯一的 beans.xml,它位于我的 src/main/webapp/WEB-INF 目录中的 web 模块中:
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
<interceptors>
<class>org.senyu.intranet.managedbean.ShiroSecuredInterceptor</class>
</interceptors>
</beans>
这是我到目前为止提到的类的耳朵结构的总结:
ear
+-ejb (jar)
+-entity (jar)
| +-src
| +-main
| +-java
| +-org
| +-senyu
| +-intranet
| +-entity
| +-user
| | +-UserServiceProviderEnterpriseImpl
| +-contrat
| +-Contrat // the class extending BusinessObject.
| // The latter reside in a dependency
| // (core-common-1.0.0-SNAPSHOT.jar).
| // The full list is right beneath.
| // The UserService and UserServiceProvider
| // interfaces also come from this jar.
+-web
+-src
+-main
| +-java
| +-org
| +-senyu
| +-intranet
| +-managedbean
| +-UserServiceEnterpriseImpl
| +-ShiroSecuredInterceptor // @Interceptor class with an @AroundInvoke annotated method
+-webapp
+-WEB-INF
+-beans.xml
这些是打包在我的war文件的WEB-INF/lib目录中的jar:
antlr-2.7.7.jar
aopalliance-repackaged-2.5.0-b05.jar
bootstrap-3.3.7-1.jar
cdi-api-1.1.jar
classmate-1.3.0.jar
commons-beanutils-1.8.3.jar
commons-codec-1.10.jar
commons-lang3-3.4.jar
commons-logging-1.2.jar
core-common-1.0.0-SNAPSHOT.jar // I developed this...
core-enterprise-1.0.0-SNAPSHOT.jar // ...and that too.
dom4j-1.6.1.jar
el-api-2.2.jar
geronimo-jta_1.1_spec-1.1.1.jar
gson-2.7.jar
hibernate-commons-annotations-5.0.1.Final.jar
hibernate-core-5.2.3.Final.jar
hibernate-jpa-2.1-api-1.0.0.Final.jar
hk2-api-2.5.0-b05.jar
hk2-locator-2.5.0-b05.jar
hk2-utils-2.5.0-b05.jar
jackson-annotations-2.8.0.jar
jackson-core-2.8.3.jar
jackson-databind-2.8.3.jar
jandex-2.0.0.Final.jar
javassist-3.20.0-GA.jar
javax.annotation-api-1.2.jar
javax.inject-1.jar
javax.inject-2.5.0-b05.jar
javax.ws.rs-api-2.0.1.jar
jboss-interceptors-api_1.1_spec-1.0.0.Beta1.jar
jboss-logging-3.3.0.Final.jar
jersey-client-2.23.2.jar
jersey-common-2.23.2.jar
jersey-guava-2.23.2.jar
jersey-media-jaxb-2.23.2.jar
jersey-mvc-2.23.2.jar
jersey-server-2.23.2.jar
jquery-1.12.4.jar
jsr250-api-1.0.jar
log4j-api-2.6.2.jar
log4j-core-2.6.2.jar
osgi-resource-locator-1.0.1.jar
primefaces-6.0.jar
servlet-api-2.4.jar
shiro-core-1.3.0.jar
shiro-web-1.3.0.jar
slf4j-api-1.6.4.jar
validation-api-1.1.0.Final.jar
更新 2
我在 Payara 中为 org.weld.jboss 创建了一个记录器。这是我在工作时得到的:
Sending PAT using the default event resolver: [BackedAnnotatedType] public @Named @SessionScoped class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-001536: Found [] constructors annotated with @Inject for [EnhancedAnnotatedTypeImpl] public @SessionScoped @Named class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-000002: Exactly one constructor ([EnhancedAnnotatedConstructorImpl] public org.senyu.intranet.managedbean.UserServiceEnterpriseImpl()) defined, using it as the bean constructor for [EnhancedAnnotatedTypeImpl] public @SessionScoped @Named class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-000004: Exactly one post construct method ([EnhancedAnnotatedMethodImpl] @PostConstruct private org.senyu.intranet.managedbean.UserServiceEnterpriseImpl.initCurrentUser()) for [EnhancedAnnotatedTypeImpl] public @SessionScoped @Named class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-001536: Found [] constructors annotated with @Inject for [EnhancedAnnotatedTypeImpl] public @SessionScoped @Named class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-000002: Exactly one constructor ([EnhancedAnnotatedConstructorImpl] public org.senyu.intranet.managedbean.UserServiceEnterpriseImpl()) defined, using it as the bean constructor for [EnhancedAnnotatedTypeImpl] public @SessionScoped @Named class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-000012: Building bean metadata for class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-000010: Using qualifiers [@javax.enterprise.inject.Default(), @javax.inject.Named(value=userService), @javax.enterprise.inject.Any()] for Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any]]]
WELD-000014: Using name userService for Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any]]]
WELD-000016: Using scope interface javax.enterprise.context.SessionScoped for Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any]]]
WELD-000106: Bean: Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any]]]
WELD-001538: Created context instance for bean Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any] identified as WELD%ManagedBean%intranet-ear|intranet-web-1.0.0-SNAPSHOT.war|org.senyu.intranet.managedbean.UserServiceEnterpriseImpl|null|false]]
WELD-001542: Retrieving/generating proxy class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl$Proxy$_$$_WeldClientProxy]]
WELD-001541: Adding method to proxy: public org.senyu.core.common.user.User org.senyu.intranet.managedbean.UserServiceEnterpriseImpl.getCurrentUser()]]
WELD-001541: Adding method to proxy: private void org.senyu.intranet.managedbean.UserServiceEnterpriseImpl.initCurrentUser()]]
WELD-001543: Created Proxy class of type class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl$Proxy$_$$_WeldClientProxy supporting interfaces [interface org.senyu.core.common.user.UserService, interface java.io.Serializable, interface org.jboss.weld.interceptor.proxy.LifecycleMixin, interface org.jboss.weld.interceptor.util.proxy.TargetInstanceProxy, interface org.jboss.weld.bean.proxy.ProxyObject]]]
WELD-001506: Created new client proxy of type class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl$Proxy$_$$_WeldClientProxy for bean Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any] with ID WELD%ManagedBean%intranet-ear|intranet-web-1.0.0-SNAPSHOT.war|org.senyu.intranet.managedbean.UserServiceEnterpriseImpl|null|false]]
WELD-001507: Located client proxy of type class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl$Proxy$_$$_WeldClientProxy for bean Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any]]]
WELD-000200: Looked for WELD%ManagedBean%intranet-ear|intranet-web-1.0.0-SNAPSHOT.war|org.senyu.intranet.managedbean.UserServiceEnterpriseImpl|null|false and got null in org.jboss.weld.context.beanstore.http.LazySessionBeanStore@3feb0ef2]]
WELD-000200: Looked for WELD%ManagedBean%intranet-ear|intranet-web-1.0.0-SNAPSHOT.war|org.senyu.intranet.managedbean.UserServiceEnterpriseImpl|null|false and got null in org.jboss.weld.context.beanstore.http.LazySessionBeanStore@3feb0ef2]]
WELD-000200: Looked for WELD%ManagedBean%intranet-ear|intranet-web-1.0.0-SNAPSHOT.war|org.senyu.intranet.managedbean.UserServiceEnterpriseImpl|null|false and got null in org.jboss.weld.context.beanstore.http.LazySessionBeanStore@3feb0ef2]]
WELD-000200: Looked for WELD%ManagedBean%intranet-ear|intranet-web-1.0.0-SNAPSHOT.war|org.senyu.intranet.managedbean.UserServiceEnterpriseImpl|null|false and got null in org.jboss.weld.context.beanstore.http.LazySessionBeanStore@3feb0ef2]]
WELD-000220: Added WELD_S#WELD%ManagedBean%intranet-ear|intranet-web-1.0.0-SNAPSHOT.war|org.senyu.intranet.managedbean.UserServiceEnterpriseImpl|null|false to session 0fcfe5dc9c8fb5d583f9b90ce7ae]]
WELD-000202: Added ForwardingBean userService for Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any] with key WELD%ManagedBean%intranet-ear|intranet-web-1.0.0-SNAPSHOT.war|org.senyu.intranet.managedbean.UserServiceEnterpriseImpl|null|false to org.jboss.weld.context.beanstore.http.LazySessionBeanStore@3feb0ef2]]
当它没有时:
Sending PAT using the default event resolver: [BackedAnnotatedType] public @Named @SessionScoped class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-001536: Found [] constructors annotated with @Inject for [EnhancedAnnotatedTypeImpl] public @SessionScoped @Named class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-000002: Exactly one constructor ([EnhancedAnnotatedConstructorImpl] public org.senyu.intranet.managedbean.UserServiceEnterpriseImpl()) defined, using it as the bean constructor for [EnhancedAnnotatedTypeImpl] public @SessionScoped @Named class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-000004: Exactly one post construct method ([EnhancedAnnotatedMethodImpl] @PostConstruct private org.senyu.intranet.managedbean.UserServiceEnterpriseImpl.initCurrentUser()) for [EnhancedAnnotatedTypeImpl] public @SessionScoped @Named class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-001536: Found [] constructors annotated with @Inject for [EnhancedAnnotatedTypeImpl] public @SessionScoped @Named class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-000002: Exactly one constructor ([EnhancedAnnotatedConstructorImpl] public org.senyu.intranet.managedbean.UserServiceEnterpriseImpl()) defined, using it as the bean constructor for [EnhancedAnnotatedTypeImpl] public @SessionScoped @Named class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-000012: Building bean metadata for class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl]]
WELD-000010: Using qualifiers [@javax.enterprise.inject.Default(), @javax.inject.Named(value=userService), @javax.enterprise.inject.Any()] for Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any]]]
WELD-000014: Using name userService for Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any]]]
WELD-000016: Using scope interface javax.enterprise.context.SessionScoped for Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any]]]
WELD-000106: Bean: Managed Bean [class org.senyu.intranet.managedbean.UserServiceEnterpriseImpl] with qualifiers [@Default @Named @Any]]]
HHH000346: Error during managed flush [WELD-001308: Unable to resolve any beans for Type: interface org.senyu.core.common.user.UserService; Qualifiers: [@javax.enterprise.inject.Default(), @javax.enterprise.inject.Any()]]]]
org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001308: Unable to resolve any beans for Type: interface org.senyu.core.common.user.UserService; Qualifiers: [@javax.enterprise.inject.Default(), @javax.enterprise.inject.Any()]
at org.senyu.intranet.entity.user.UserServiceProviderEnterpriseImpl.getUserService(UserServiceProviderEnterpriseImpl.java:17)
Caused by: org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001308: Unable to resolve any beans for Type: interface org.senyu.core.common.user.UserService; Qualifiers: [@javax.enterprise.inject.Default(), @javax.enterprise.inject.Any()]
at org.senyu.intranet.entity.user.UserServiceProviderEnterpriseImpl.getUserService(UserServiceProviderEnterpriseImpl.java:17)
Caused by: org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001308: Unable to resolve any beans for Type: interface org.senyu.core.common.user.UserService; Qualifiers: [@javax.enterprise.inject.Default(), @javax.enterprise.inject.Any()]
at org.senyu.intranet.entity.user.UserServiceProviderEnterpriseImpl.getUserService(UserServiceProviderEnterpriseImpl.java:17)
Caused by: org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001308: Unable to resolve any beans for Type: interface org.senyu.core.common.user.UserService; Qualifiers: [@javax.enterprise.inject.Default(), @javax.enterprise.inject.Any()]
at org.senyu.intranet.entity.user.UserServiceProviderEnterpriseImpl.getUserService(UserServiceProviderEnterpriseImpl.java:17)