无法将 @Stateless EJB 注入 CDI bean(多模块)Jakarta EE 8
Unable to inject @Stateless EJB into CDI bean (multi-module) Jakarta EE 8
将遗留项目迁移到 Jakarta EE 8(Maven EAR 在 Wildly 26 上构建)是:
-WebApp.ear
-WebApp-entities.jar
-WebApp-ejb.jar
-WebApp-web.war
-WebApp-mobile.war
-WebApp-api.war
该结构是基于 wildfly-jakartaee8-with-tools 原型创建的
我要注入的 DAO 是一个使用 @LocalBean 无接口的 @Stateless bean,例如
@Named
@LocalBean
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class UserDAO extends GenericDAOBean<User,Long> {
@PersistenceContext(unitName="ReadOnlyDatabase") private EntityManager readOnlyEntityManager;
/**
* Default constructor
*/
public UserDAO() {
//Super call to construct AbstractDAO
super();
}
public User findNonDeletedByEmail(String email){
String s = "from User where email = :email and disabled = false";
Query query = this.getEntityManager().createQuery(s);
query.setParameter("email", email);
try{
return (User)query.getSingleResult();
}catch(NoResultException nre){
return null;
}catch(Exception e){
return null;
}
}
}
我的 CDI bean 是 WAR 模块中的标准 @RequestScoped bean,它试图注入 DAO 以执行登录
@Named
@RequestScoped
public class LoginBean implements Serializable {
private static final long serialVersionUID = 1504441323094295359L;
@Inject private SecurityContext securityContext;
@Inject private UserDAO userDAO;
@Inject private FacesContext facesContext;
@Inject private ExternalContext externalContext;
private String username, password;
public void login() throws IOException {
Credential credential = new UsernamePasswordCredential(username, new Password(password));
User user = userDAO.findByEmailForUserLogin(username);
AuthenticationStatus status = securityContext.authenticate(
getRequest(facesContext),
getResponse(facesContext),
AuthenticationParameters.withParams()
.credential(credential));
switch (status) {
case SEND_CONTINUE:
facesContext.responseComplete();
break;
case SEND_FAILURE:
facesContext.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Login failed", null));
break;
case SUCCESS:
facesContext.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO, "Login succeed", null));
externalContext.redirect(externalContext.getRequestContextPath() + "/user/home.xhtml");
break;
case NOT_DONE:
}
}
private static HttpServletResponse getResponse(FacesContext context) {
return (HttpServletResponse) context
.getExternalContext()
.getResponse();
}
private static HttpServletRequest getRequest(FacesContext context) {
return (HttpServletRequest) context
.getExternalContext()
.getRequest();
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
当我从 JSF 页面调用 login() 方法时,出现以下错误:
Target Unreachable, identifier 'loginBean' resolved to null: javax.el.PropertyNotFoundException
如果我注释掉 userDAO 注入,方法调用正常,所以我知道是 UserDAO 导致了问题,没有其他错误
在服务器启动日志中,我可以看到 UserDAO 已成功注册,例如:
java:global/WebApp/Web-entities/UserDAO!com.webapp.dao.beans.UserDAO
java:app/Web-entities/UserDAO!com.webapp.dao.beans.UserDAO
java:module/UserDAO!com.webapp.dao.beans.UserDAO
java:global/WebApp/Web-entities/UserDAO
java:app/Web-entities/UserDAO
java:module/UserDAO
我在 /web-inf/beans.xml (war) 和 /meta-inf/beans.xml (jar) 中定义了 beans.xml [=] =15=]
我的 EJB 模块作为 Maven 依赖包含在 WAR .pom 中 <scope>provided</scope>
我也试过用@EJB注入也有同样的错误
更新:
我发现通过在 boss-deployment-structure.xml 中设置 <ear-subdeployments-isolated>false</ear-subdeployments-isolated>
允许注入工作但是这会产生跨模块重复依赖关系的问题和 class-path 错误所以我不认为它是正确的解决方案(我们的遗留 EE 6 项目隔离了 EAR 部署并且 DI 工作正常)
最终通过向 jboss-deployment-structure.xml 中的 EJB 和 Entity 模块添加模块依赖关系实现了此功能,如下所示...
<sub-deployment name="WebApp-web.war">
<dependencies>
<module name="deployment.WebApp.ear.WebApp-entities.jar" />
<module name="deployment.WebApp.ear.WebApp-ejb.jar" />
</dependencies>
</sub-deployment>
注入 WAR 现在可以正常工作,这在旧版 EE 6 / JBoss 7 应用程序中不是必需的,因此 class 加载行为必须已更改
将遗留项目迁移到 Jakarta EE 8(Maven EAR 在 Wildly 26 上构建)是:
-WebApp.ear
-WebApp-entities.jar
-WebApp-ejb.jar
-WebApp-web.war
-WebApp-mobile.war
-WebApp-api.war
该结构是基于 wildfly-jakartaee8-with-tools 原型创建的
我要注入的 DAO 是一个使用 @LocalBean 无接口的 @Stateless bean,例如
@Named
@LocalBean
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class UserDAO extends GenericDAOBean<User,Long> {
@PersistenceContext(unitName="ReadOnlyDatabase") private EntityManager readOnlyEntityManager;
/**
* Default constructor
*/
public UserDAO() {
//Super call to construct AbstractDAO
super();
}
public User findNonDeletedByEmail(String email){
String s = "from User where email = :email and disabled = false";
Query query = this.getEntityManager().createQuery(s);
query.setParameter("email", email);
try{
return (User)query.getSingleResult();
}catch(NoResultException nre){
return null;
}catch(Exception e){
return null;
}
}
}
我的 CDI bean 是 WAR 模块中的标准 @RequestScoped bean,它试图注入 DAO 以执行登录
@Named
@RequestScoped
public class LoginBean implements Serializable {
private static final long serialVersionUID = 1504441323094295359L;
@Inject private SecurityContext securityContext;
@Inject private UserDAO userDAO;
@Inject private FacesContext facesContext;
@Inject private ExternalContext externalContext;
private String username, password;
public void login() throws IOException {
Credential credential = new UsernamePasswordCredential(username, new Password(password));
User user = userDAO.findByEmailForUserLogin(username);
AuthenticationStatus status = securityContext.authenticate(
getRequest(facesContext),
getResponse(facesContext),
AuthenticationParameters.withParams()
.credential(credential));
switch (status) {
case SEND_CONTINUE:
facesContext.responseComplete();
break;
case SEND_FAILURE:
facesContext.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Login failed", null));
break;
case SUCCESS:
facesContext.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO, "Login succeed", null));
externalContext.redirect(externalContext.getRequestContextPath() + "/user/home.xhtml");
break;
case NOT_DONE:
}
}
private static HttpServletResponse getResponse(FacesContext context) {
return (HttpServletResponse) context
.getExternalContext()
.getResponse();
}
private static HttpServletRequest getRequest(FacesContext context) {
return (HttpServletRequest) context
.getExternalContext()
.getRequest();
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
当我从 JSF 页面调用 login() 方法时,出现以下错误:
Target Unreachable, identifier 'loginBean' resolved to null: javax.el.PropertyNotFoundException
如果我注释掉 userDAO 注入,方法调用正常,所以我知道是 UserDAO 导致了问题,没有其他错误
在服务器启动日志中,我可以看到 UserDAO 已成功注册,例如:
java:global/WebApp/Web-entities/UserDAO!com.webapp.dao.beans.UserDAO
java:app/Web-entities/UserDAO!com.webapp.dao.beans.UserDAO
java:module/UserDAO!com.webapp.dao.beans.UserDAO
java:global/WebApp/Web-entities/UserDAO
java:app/Web-entities/UserDAO
java:module/UserDAO
我在 /web-inf/beans.xml (war) 和 /meta-inf/beans.xml (jar) 中定义了 beans.xml [=] =15=]
我的 EJB 模块作为 Maven 依赖包含在 WAR .pom 中 <scope>provided</scope>
我也试过用@EJB注入也有同样的错误
更新:
我发现通过在 boss-deployment-structure.xml 中设置 <ear-subdeployments-isolated>false</ear-subdeployments-isolated>
允许注入工作但是这会产生跨模块重复依赖关系的问题和 class-path 错误所以我不认为它是正确的解决方案(我们的遗留 EE 6 项目隔离了 EAR 部署并且 DI 工作正常)
最终通过向 jboss-deployment-structure.xml 中的 EJB 和 Entity 模块添加模块依赖关系实现了此功能,如下所示...
<sub-deployment name="WebApp-web.war">
<dependencies>
<module name="deployment.WebApp.ear.WebApp-entities.jar" />
<module name="deployment.WebApp.ear.WebApp-ejb.jar" />
</dependencies>
</sub-deployment>
注入 WAR 现在可以正常工作,这在旧版 EE 6 / JBoss 7 应用程序中不是必需的,因此 class 加载行为必须已更改