【问题标题】:CDI in layered architecture. How to inject service object using CDI annotations?分层架构中的 CDI。如何使用 CDI 注释注入服务对象?
【发布时间】:2012-01-04 03:13:58
【问题描述】:

我正在开发一些应用程序,它由三层组成:

  1. 数据库访问层(JPA + Hibernate 作为提供者)
  2. 业务逻辑层
  3. 表示层 (JSF 2.0)

在开始之前,我阅读了 David Geary 和 Cay S. Horstmann 所著的 Core JavaServer Faces (3rd Edition) 一书中的一些章节。在本书中,作者强烈推荐使用@Named 注解而不是@ManagedBean。好的,我想我可以试试。

然后我通过实现一些基本功能(用户登录)来对我的应用程序进行分层构建。

我还阅读了一些新注释,即@Inject。我认为仅基于接口将一层注入另一层会很舒服。但是我怕我误会了什么,所以我来找你有我的问题。

让我介绍一下我的代码的一些部分:

CredentialsBean.java

@Named("userCredentials")
public class CredentialsBean {
    @Inject
    AccountService accountService;

    private String login;
    private String password;

    public String verify()
    {
        if (accountService.verifyCredentials(login, password))
            return "success";
        else
            return "failure";
    }
    // getters and setters
}

AccountService.java

public interface AccountService {
    public Boolean verifyCredentials(String login, String password);
}

AccountServiceImpl.java:

public class AccountServiceImpl implements AccountService {
    @Inject
    AccountDAO dao;

    @Override
    public Boolean verifyCredentials(String login, String password) {
        // some logic
    }
}

AccountDAO.java

public interface AccountDAO {
    public Account getAccount(String login);
}

AccountDAOImpl.java

public class AccountDAOImpl implements AccountDAO {
    @PersistenceContext(unitName = "MyApp")
    protected EntityManager em;

    public EntityManager getEntityManager() {
        return em;
    }

    @Override
    public Account getAccount(String login) {
        // some data processing
    }
}

最后一个类在带有 @Entity 注释的某个 Java 类上运行,没关系。

我感觉我的解决方案有问题。

基本错误是事实,即使我向使用<h:form><h:inputText> 标签创建的表单提供一些数据,在调试verify() 方法时我可以看到loginpassword 是@987654335 @,所以这里出了点问题,但我不知道是什么。

我也担心我是否理解@Inject。我可以像上面提供的那样使用它来使用接口耦合层吗?


好的。我找到了登录和密码字段为空的原因,但我还不知道解决方案。 这是因为在以某种神奇的方式执行期间,创建了多个(至少两个)CredentialsBean 实例。在 Eclipse 调试器中检查。第一个正确设置其字段,但第二个没有,第二个的值被发送到服务层。 我想知道这是否不是范围问题。我不应该将@SessionScoped 放在 CredentialsBean 中吗?

【问题讨论】:

  • 您的实现类没有@Named 注释。这是对代码 sn-ps 的故意还是过度简化?
  • 他们必须这样做吗?我认为只有用于在 JSF 页面和应用程序逻辑之间传输信息的 bean 才需要它。我错了吗?
  • @Stateless 如果应该是 EJB 也可以。容器应该如何知道您拥有和需要注入哪些实现?
  • 我不明白你的回复。我想我不需要EJB。我创建层是为了允许不同的对象使用服务层,即 JSF bean 执行一些任务,而 HttpServlet 执行一些其他任务。我不相信我需要 EJB 组件。
  • 只是AccountDAOImpl是一个典型的@Stateless EJB实现。如果你想成为@Named,很好,但你必须自己管理交易。但这不是我的评论的真正意义所在。关键是,如果你不注释实现,容器应该如何知道你拥有和需要注入哪些实现?

标签: dependency-injection jsf-2 layer cdi


【解决方案1】:

我认为问题出在您的 CredintialsBean 类上。您没有为 bean 指定范围,因此它使用默认范围(请参阅What is the default scope of a Named CDI bean? 了解更多信息)。

如果你在你的类中添加类似@RequestScoped 的东西,它应该可以工作。确保使用 javax.enterprise.context.RequestScoped 而不是 javax.faces 版本。

【讨论】:

    【解决方案2】:

    您对@Inject 的理解是正确的,这正是它的用途。有可能您的注入点为空,因为您没有 bean 存档(您需要 WEB-INF 或 META-INF 中名为 beans.xml 的文件,如果它是一个 jar,它可以是空的)。这就是注入点为 null 的常见原因。

    【讨论】:

    • 不幸的是,这不是正确的解决方案。从 Eclipse 项目配置开始,我在 WebContent/WEB-INF 目录中有 beans.xml。我的登录名和密码仍然为空。有什么想法吗?
    • 我不明白你是如何得到空值而不是异常的。
    猜你喜欢
    • 2014-01-27
    • 1970-01-01
    • 2017-11-19
    • 2016-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-14
    相关资源
    最近更新 更多