Java 让您的业务(服务)层依赖于用户会话是一种糟糕的设计吗?
在一个普通的MVC设计的应用程序中,让服务层依赖于用户会话是一个坏主意吗?假设有一个服务方法可以从数据库中获取一些对象,您希望根据初始化调用的人返回不同的结果-例如,管理员可能会得到10行对象,而普通用户可能只得到7行,因为最后3行是“仅限管理员”的对象。解决这一问题的几种方法是:Java 让您的业务(服务)层依赖于用户会话是一种糟糕的设计吗?,java,architecture,ejb,Java,Architecture,Ejb,在一个普通的MVC设计的应用程序中,让服务层依赖于用户会话是一个坏主意吗?假设有一个服务方法可以从数据库中获取一些对象,您希望根据初始化调用的人返回不同的结果-例如,管理员可能会得到10行对象,而普通用户可能只得到7行,因为最后3行是“仅限管理员”的对象。解决这一问题的几种方法是: 引入一个新的方法参数,其中包括调用用户。依赖性较小,但在许多方法中必须加入用户参数,这很麻烦 为不同的用户角色创建不同的方法(具有多个结果)。此外,依赖性较小,但有许多方法基本上做相同的事情,这增加了代码重复的风险
- 引入一个新的方法参数,其中包括调用用户。依赖性较小,但在许多方法中必须加入用户参数,这很麻烦
- 为不同的用户角色创建不同的方法(具有多个结果)。此外,依赖性较小,但有许多方法基本上做相同的事情,这增加了代码重复的风险
- 让该方法在存储当前用户会话的静态上下文中读取ThreadLocal变量。此变量在每次请求之前设置
你对此有何看法?如果这是一个糟糕的解决方案,那么哪一个更强大呢?我强烈建议采用aginst ThreadLocal风格的方法-这似乎太像一种“全局变量”设计味道了。这有许多问题,最明显的是:
- 当您在测试之前设置越来越多的隐式全局状态时,您的代码变得越来越难测试
- 您将无法清楚地看到某段代码使用的参数。这可能会让维护人员非常困惑,或者如果您在几个月后回到代码中
- 如果您将工作交给不同的线程,它可能会导致非常严重的错误/复杂性。您已经有效地使代码执行依赖于它在哪个线程上运行。。。。什么可能出错?:-)李>
- 您正在创建循环依赖项(服务层用户界面层)。这绝对不是一个好主意,您应该尝试保持依赖关系只单向流动(几乎总是用户界面层->服务层)
- 如果用户本质上是数据模型的一部分(例如,您有一个社交图数据库),那么将用户作为参数传递似乎很自然
- 如果用户数据只是用于前端的东西,如身份验证等,那么我倾向于最小化对特定用户详细信息的依赖,而是为不同的角色创建不同的方法(或者等效地添加一个“角色”参数)
另一种选择是将“上下文”对象传递给包含一组相关会话数据(即,不仅仅是用户名)的服务层。如果希望最小化参数膨胀,这可能是有意义的。小心它变成了一种“绕过”好的分层原则的方式。如果只是“数据”,那么它可能没问题,但一旦人们开始在上下文中传递回调对象/UI组件,那么您可能就有点乱了……从架构的角度来看,我认为您的最后一个选项是唯一明智的
ThreadLocal
s提供了一种有效而高效的解决方案。不完美?当然不会,但如果正确实施,它会比其他解决方案更干净。尽管如此,确实如此
@Stateless
public class AService {
@Resource
private SessionContext sessionContext;
@PersistenceContext
private EntityManager entityManager;
public List<AObject> fetchAFewObjects() {
String query = "aUserQuery";
if (sessionContext.isCallerInRole("ADMIN")
query = "aAdminQuery";
return entityManager.createNamedQuery(query, AObject.class)
.getResultList();
}
}