访问无状态内的现有有状态实例,java ee 6

发布于 2025-01-07 18:36:44 字数 1478 浏览 2 评论 0原文

是否可以在无状态 bean 中访问有状态会话 bean?

我的问题是我有一个名为 User 的会话 bean,我想访问无状态 bean 内的用户信息...

我正在尝试这样:

Ejb 端:

@Stateless
public class OfferManagerBean implements OfferManagerLocal, OfferManager
{
    @Resource 
    private SessionContext context;
    @EJB
    private ro.project.ejb.interfaces.User user;
    public String getUsername()
    {
        user = (ro.project.ejb.interfaces.User) context.lookup("java:global/project/projectEJB/User!ro.project.ejb.interfaces.User");
        return user.getUsername();
}

客户端

 User user = (User) ctx.lookup("java:global/project/projectEJB/User!ro.project.ejb.interfaces.User");
 user.setUsername("Alex");

 OfferManager offerManager = (OfferManager) ctx.lookup("java:global/project/projectEJB/OfferManagerBean!ro.project.ejb.interfaces.OfferManager");
 assertEquals(offerManager.getUsername(), "Alex");

此测试用例的结果是 java.lang。断言错误:预期:但是:

它失败了.. 似乎我请求有状态 bean 的方式正在返回给我一个新实例...

  1. 我知道为什么这不起作用。因为我的测试失败了:P。我得到一个新实例..
  2. 我想检查 EJB 中登录用户的某些权限,因为我不想依靠客户端,因为我可能会在那里犯错误,或者我会告诉其他开发人员为它制作一个 GUI我的项目..
  3. 我不想使用Java EE安全性,因为我不知道如何在RCP应用程序中登录
  4. 我的主要问题是:如何访问内部的会话bean(与客户端拥有的相同)一个EJB..是吗 可能的?又如何呢?

我问的问题几乎与这个人问的一样:概念rmi ejb 调用中的可重用登录会话

我想这样做,但不是使用 JAAS...

提前谢谢

Is it possible to access a stateful session bean inside a stateless bean?

My problem is that I have a session bean called User and I want to access user info inside a stateless bean...

I am trying like this:

Ejb Side:

@Stateless
public class OfferManagerBean implements OfferManagerLocal, OfferManager
{
    @Resource 
    private SessionContext context;
    @EJB
    private ro.project.ejb.interfaces.User user;
    public String getUsername()
    {
        user = (ro.project.ejb.interfaces.User) context.lookup("java:global/project/projectEJB/User!ro.project.ejb.interfaces.User");
        return user.getUsername();
}

Client side

 User user = (User) ctx.lookup("java:global/project/projectEJB/User!ro.project.ejb.interfaces.User");
 user.setUsername("Alex");

 OfferManager offerManager = (OfferManager) ctx.lookup("java:global/project/projectEJB/OfferManagerBean!ro.project.ejb.interfaces.OfferManager");
 assertEquals(offerManager.getUsername(), "Alex");

The result of this test case is java.lang.AssertionError: expected:<null> but was:<Alex>

it fails.. It seems that how I am requesting the stateful bean is returning me a new instance...

  1. I know why this is not working. Because my test fails :P. I get a new instance..
  2. I want to check certain permissions of the logged in user in EJB because I don't want to count on the client side because I might do a mistake there or I will tell other developers to make a GUI for my project..
  3. I don't want to use Java EE Security beucause I don't know how to make the login in a RCP Application
  4. My main question is: How do I access a session bean (the same one the client own) inside an EJB.. is it possible? And how?

I am asking almost the same thing this guy is asking: Concept for reusable login session in rmi ejb calls

I want to do that but not with JAAS...

Thank you in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

七婞 2025-01-14 18:36:44

您不应该永远@Stateless bean (SLSB) 中注入@Stateful bean (SFSB)。 SFSB 的生存时间与其客户端的生存时间一样长(客户端是 SFSB 被注入的实例,在本例中是 SLSB 本身)。然而,SLSB 的目的是无状态,并且大多数容器将它们放在池中。因此,每当 SLSB 在使用后返回到池中时,它将在其他地方完全重用,但它保留与第一次创建 SLSB 时相同的 SFSB 实例!这可能会导致不良结果。

此外,每次从 JNDI 获取 SFSB 时,您都会获得一个全新实例,它与在其他地方共享的 SLSB 不同。 SFSB 的客户端就是您从 JNDI 获取 SFSB 的当前客户端类实例。您应该自己保留该实例并重复使用同一实例,直到完成在其上执行的事务为止。其中一种方法是将其存储在您自己的 HTTP 会话中或存储在您正在使用的 MVC 框架的会话范围托管 bean 中。

我并不完全清楚功能需求,因此很难给出如何解决您的特定问题的合适答案,但我的印象是您实际上需要将用户存储在 HTTP 会话中,不在 SFSB 中。初学者对于会话 bean 最常见的错误是它们错误地将 EJB 上下文中的“会话”解释为 HTTP 会话。

另请参阅有关同类问题的相关答案以获得更深入的解释:JSF 请求作用域 bean 不断在每个请求上重新创建新的有状态会话 bean请求? 根据您的问题历史记录,您熟悉 JSF,因此这个答案应该很容易理解。

You should never inject a @Stateful bean (SFSB) in a @Stateless bean (SLSB). A SFSB lives as long as its client lives (the client is the instance where the SFSB is been injected, which is in this case the SLSB itself). SLSB's are however intented to be stateless and most containers have them in a pool. So whenever the SLSB goes back to the pool after use, it will be reused entirely elsewhere, but it holds the same SFSB instance as it was when the SLSB was been created for the first time! This may lead to undesireable results.

Also, everytime when you get the SFSB from JNDI, you will get a brand new instance which is unlike SLSBs not shared elsewhere. The SFSB's client is then the current client class instance where you've got the SFSB from JNDI. You're supposed to keep hold of this instance yourself and reuse the very same instance until you're finished with performing the transaction on it. One of the ways is storing it in the HTTP session yourself or in a session scoped managed bean of the MVC framework you're using.

The functional requirement is not entirely clear to me, so it's hard to give a suitable answer how to solve your particular problem, but I have the impression that you actually need to store the user in the HTTP session, not in a SFSB. The most common beginner's mistake as to session beans is namely that they incorrectly interpret the "session" in EJB context as being the HTTP session.

See also this related answer on a question of the same kind for a more in-depth explanation: JSF request scoped bean keeps recreating new Stateful session beans on every request? According to your question history you're familiar with JSF, so this answer should be easy understandable.

眼泪淡了忧伤 2025-01-14 18:36:44

一般来说,可以访问无状态 bean 中的某些现有有状态会话 bean。例如,它可以作为无状态会话 bean 的业务方法的参数给出。

但你正在尝试的方法是行不通的。原因是依赖注入(@EJB
) 和查找 (ctx.lookup...) 保证调用 newInstance,因此您将拥有新实例。

规范中用以下文字对此进行了解释:

会话 Bean 实例的生命周期从客户端获取
通过依赖关系引用有状态会话 Bean 实例
注入或 JNDI 查找,或者当客户端调用创建时
会话 bean 的 home 接口上的方法。这会导致容器
在会话 bean 类上调用 newInstance 来创建一个新的
会话bean实例。

In general it is possible to access certain existing stateful session bean inside stateless bean. It can be for example given as argument to the business method of stateless session bean.

But what you are trying cannot work. Reason is that both, dependendy injection (@EJB
) and lookup (ctx.lookup...) are guaranteed to call newInstance and as consequence you will have new instance.

This is explained in specification with following words:

A session bean instance’s life starts when a client obtains a
reference to a stateful session bean instance through dependency
injection or JNDI lookup, or when the client invokes a create
method on the session bean’s home interface. This causes the container
to invoke newInstance on the session bean class to create a new
session bean instance.

兔姬 2025-01-14 18:36:44

如果其他人还不够清楚:你做错了! ;)

我同意这可能会令人困惑,但是 EJB 会话 bean 中的唯一会话保存在您从 InititalContext 获取的代理 bean 中。

您从此上下文中获取的不同 bean 不共享任何类型的公共会话。在 EJB 中,bean 不存储在 EJB 会话中,但它们就是此会话。

换句话说,InitialContext(代码中的 ctx)不是 HttpSession 的 EJB 等效项。

更糟糕的是,在您的代码中,用户是一个 EJB bean。这是错误的。

用户是应用程序中的一个名词。它们由 JPA 实体或简单的“普通”java bean 表示。 EJB 用于在应用程序中实现动词:服务、DAO、存储库等。

有状态会话 Bean 中的状态应该在业务流程期间保留模型数据(用于缓存、锁定、保留)等目的)。在任何情况下,该状态都不应成为模型数据。

我的建议:放弃你当前的“设计”。不要试图修复它,也不要试图为它辩护。放手吧,删除你的代码,不要回头。阅读一些有关 EJB 的好书,然后重新开始。

祝你好运!

In case the others weren't clear enough already: You're doing it wrong! ;)

I agree that it might be confusing, but the only session in EJB session beans is kept in the proxy bean that you obtain from the InititalContext.

Different beans that you obtain from this context do not share any kind of common session. In EJB, beans are not stored IN an EJB session but they ARE this session.

In other words, the InitialContext (ctx in your code) is NOT the EJB equivalence for the HttpSession.

Even worse perhaps is that in your code the User IS an EJB bean. This is WRONG.

A user is a noun in your application. These are represented by JPA entities or simple 'normal' java beans. EJBs are for implementing the verbs in your application: Services, DAOs, Repositories, etc.

The state in stateful session beans is supposed to hold on to model data during a business process ( for caching, locking, reservations, etc purposes). In no situation should this state BE the model data.

My advice: let your current 'design' go. Don't try to fix it, don't try to justify it. Let it go, delete your code, don't look back. Read some good books about EJB and then start over.

Good luck!

小姐丶请自重 2025-01-14 18:36:44

我不会验证您在使用 SFSB 和 SFSB 时是否做对/错误。 SLSB。 答案

但下面是您的问题选项 1 的 :从您的 servlet 中,执行 SFSB 的 JNDI 查找。这应该是一次。将返回的 SFSB 引用存储在 HttpSession 中。当您调用需要 SFSB 实例来存储用户详细信息的 SLSB 方法时,请将上述 SFSB 引用对象作为参数传递给 SLSB 方法。然后通过SLSB方法访问它并存储用户数据。

选项 1 的问题:您将持久性机制 (SFSB) 与 UI 代码结合在一起(因为您将其存储在 HttpSession 中并将其传递)。明天,如果您想更改为缓存等另一种持久化机制,您将需要做大量的返工。同样,如果您想将 SLSB 方法公开为 WebService,您将无法做到这一点,因为您无法对 SFSB 对象引用进行 xml 化。简而言之,这是一个糟糕的选择。

选项2:在业务层的某个类中拥有静态哈希图。假设您的每笔交易都有一些唯一的交易属性,例如 ID。当您开始事务时,从业务层创建 SFSB,将其引用存储在以 ID 作为键的静态哈希图中。当您调用 SLSB 服务方法时,请传递此 ID(我假设每个事务都可以有一个唯一的 ID)。在 SLSB 方法中,使用 ID 查找存储在静态哈希图中的 SFSB 引用。将其用于存储。在此选项中,您的 UI 和SFSB 未耦合。明天,如果您想更改持久性机制,您可以在不影响客户端的情况下进行,因为您的更改将仅限于 BC 层。

I am not validating whether you are doing right/wrong in the usage of SFSB & SLSB. But below is the answer to your problem

Option-1 : From your servlet, perform JNDI lookup for SFSB. This should be one time. Store the returned reference of SFSB in your HttpSession. When you call the SLSB method which needs the SFSB instance for storing the user details, pass the above SFSB reference object as parameter to the SLSB method. Then access it from SLSB method and store user data.

Issue with Option-1 : You are tying couple your persistence mechanism (SFSB) to your UI code (since you store it in HttpSession and pass it around). Tomorrow, if you want to change to another persistence mechanism like a cache, you will need to do a lot of rework. Again, if you want to expose your SLSB method as a WebService, you won't be able to do that as you cannot xml-ize the SFSB object reference. In short, a bad option.

Option-2 : Have a static hashmap in some class in the business tier. Assume you have some unique transaction attributes for every transaction, something like an ID. When you start transaction, from your Business Tier, create the SFSB, store its reference in the static hashmap with ID as key. When you call the SLSB service method, pass this ID along (I assume each transaction can have a unique ID). From SLSB method, use the ID to lookup SFSB reference stored in the static hashmap. Use it for your storage. In this option, your UI & SFSB is not coupled. Tomorrow, if you want to chnage your persistence mechanism, you can do with out impacting clients as your changes will be limited within BC tier.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文