当前位置: 首页 > 面试题库 >

EJB和CDI Bean序列化的最佳实践

卫弘义
2023-03-14
问题内容

我尚未遇到任何与序列化相关的问题。但是PMD和Findbugs发现了一系列关于序列化的潜在问题。典型的情况是注入的记录器被检测为不可序列化。但是还有更多-
EntityManager还有几个CDI bean。

我还没有找到有关如何正确处理序列化的最佳实践。

  • 反序列化注入的@Inject@PersistenceContext注入的字段是否会被注入?
  • 应该将它们标记为transient吗?
  • 还是应该忽略/关闭代码检查?
  • 我真的应该按照PMD的建议为所有这些字段提供访问者吗?

问题答案:

该答案将详细描述EJB 3.2(JSR 345),JPA 2.1(JSR
338
)和CDI 1.2(JSR
346
)的序列化/钝化语义。值得注意的是,Java
EE 7伞规范(JSR 342),托管Beans 1.0规范(JSR
316)和Commons Annotations规范1.2(JSR
250)在序列化/钝化。

我还将讨论静态代码分析器的主题。

相关章节为“ 4.2有状态会话Bean的会话状态”和“ 4.2.1实例钝化和会话状态”。

@Stateless并且@Singleton实例永远不会被钝化。

@Stateful实例可能被钝化。从EJB
3.2开始,类开发人员可以使用退出钝化@Stateful(passivationCapable=false)

EJB规范明确指出来的东西,如引用UserTransactionEntityManagerFactory和容器管理EntityManager由容器的照顾。除非持久化上下文中的所有实体以及EntityManager实现可序列化,否则使用扩展的持久化上下文的@Stateful实例将不会被钝化。

请注意,由应用程序管理的EntityManager始终使用扩展的持久性上下文。而且,@
Stateful实例是唯一的EJB会话实例类型,可以使用具有扩展持久性上下文的容器管理的EntityManager。此持久性上下文将绑定到@Stateful实例的生命周期,而不是单个JTA事务。

EJB规范未明确解决具有扩展的持久性上下文的容器管理的EntityManager所发生的情况。我的理解是:如果存在扩展的持久性上下文,则必须根据先前定义的规则将此人视为可序列化或不可序列化;如果是,则将进行钝化。如果进行钝化,则@Stateful类开发人员只需要关心对应用程序管理的实体管理器的引用即可。

EJB规范除了描述我们作为开发人员应该做出的假设外,没有指定瞬态字段会发生什么。

第4.2.1节说:

Bean Provider必须假定在PrePassivate和PostActivate通知之间,临时字段的内容可能会丢失。

[…]

虽然不需要该容器使用Java编程语言的序列化协议来存储钝化会话实例的状态,但它必须达到等效的结果。一个例外是,在激活期间不需要容器重置瞬态字段的值。通常不建议将会话bean的字段声明为瞬态。

坦白地说,要求容器同时“实现等效结果”作为Java的序列化协议,而对于瞬态字段的发生情况却完全不确定,这是非常可悲的。值得一提的是,不应将任何内容标记为瞬态。对于容器无法处理的字段,请使用@PrePassivate编写null@PostActivate还原。

JPA

在JPA规范中不会出现“钝化”一词。JPA也不限定系列化语义类型,例如EntityManagerFactoryEntityManagerQueryParameter。规范中与​​我们有关的唯一一句话是(第6.9节“查询执行”):

CriteriaQuery,CriteriaUpdate和CriteriaDelete对象必须可序列化。

CDI

“ 6.6.4。钝化作用域”一节将钝化作用域定义为显式标注的作用域@NormalScope(passivating=true)。此属性默认为false。

一个暗示是@Dependent-这是一个伪作用域-
不是可钝化的作用域。同样值得注意的是,javax.faces.view.ViewScoped无论出于何种原因,大多数Internet似乎都认为这不是具有钝化能力的范围。例如,“
Java 9食谱:一种问题解决方法”一书中的“ 17-2。开发JSF应用程序”一节。

具有钝化能力的作用域要求声明为“具有该作用域的类具有钝化能力”的类的实例(第6.6.4节“钝化作用域”)。“
6.6.1。具有钝化能力的Bean”部分将此类对象实例定义为一个可转移到辅助存储的对象实例。特殊的类注释或接口不是明确的要求。

EJB:@Stateless和@Singleton的实例不是“具有钝化能力的bean”。@Stateful可能是(Stateful是让CDI管理生命周期的唯一有意义的EJB会话类型-即,永远不要将CDI范围放在@Stateless或@Singleton上)。如果其他“托管bean”及其拦截器和装饰器都可序列化,则它们仅是“具有钝化能力的bean”。

不被定义为“具有钝化能力的bean”并不意味着诸如无状态,单例,EntityManagerFactory,EntityManager,Event和BeanManager之类的东西不能用作您编写的具有钝化能力的实例内的依赖项。这些东西被定义为“具有钝化能力的依赖关系”(请参见“
6.6.3。具有钝化能力的依赖关系”和“ 3.8。其他内置bean”一节)。

CDI通过使用具有钝化能力的代理来使这些伪装能力得以钝化(请参阅“ 5.4。客户代理”和“
7.3.6。资源生命周期”中的最后一个项目符号)。请注意,要使Java
EE资源(例如EntityManagerFactory和EntityManager)具有钝化能力,必须将它们声明为CDI生产者字段(“
3.7.1。声明资源”部分),除@Dependent之外,它们不支持任何其他范围(请参阅“
3.7。资源”一节),并且必须在客户端使用@Inject查找它们。

如果实例可以转移到辅助存储(即可序列化),则其他@Dependent实例(尽管未使用正常范围声明且不需要由CDI“客户端代理”进行前置)也可以用作具有钝化能力的依赖项。该人员将与客户一起被序列化(请参阅“
5.4。客户代理”部分中的最后一个项目符号)。

十分清楚并提供一些示例;@Stateless实例,对由CDI生成的EntityManager的引用和可序列化的@Dependent实例,都可以用作您的类中具有可钝化作用域的注释的实例字段。

静态代码分析器

静态代码分析器很愚蠢。我认为对于高级开发人员而言,他们不是助手,而是引起关注的原因。这些分析器针对可疑的序列化/钝化问题提出的错误标志肯定具有非常有限的价值,因为CDI要求容器验证实例“确实具有钝化能力,并且其依赖项具有钝化能力”或“抛出”异常。
javax.enterprise.inject.spi.DeploymentException的子类”(“
6.6.5。具有钝化能力的bean和依赖项的验证”和“ 2.9。容器自动检测到的问题”)。

最后,正如其他人指出的,值得重复:我们可能永远不应该将字段标记为transient



 类似资料:
  • 问题内容: 我需要为某些对象实现JSON序列化,并且在与通用集合进行集成时遇到了一个问题。 所有可序列化的类都实现此接口(JSONObject来自此库): 我基于java.util.list的集合的代码大致如下所示: 我的问题是:当我从JSONObject加载AwesomeList时,我需要创建其元素,但是这是不可能的,因为Java禁止我写 我应该如何修改此任务的方法? 问题答案: 您是否绑定到该

  • 我有一个应用程序,它有一个EJB,它注入了由CDI生成的实体管理器。同一服务器(wildfly 9)/JVM上的另一个应用程序将使用此EJB从实体管理器获取结果。 EJB的第一次调用将返回预期结果。当调用返回时,它生成实体管理器,获取数据并再次处理实体管理器。由于关闭了实体管理器,该EJB的每个后续调用都将抛出一个错误。未对新实体经理进行生产/处置。 这是预期的巴哈维奥吗?我的代码中有错误吗? 这

  • 在我们的应用程序中,我们有CDI(@Application ationScoped注释)和EJB(@无状态注释)bean,其结构如下: 我使用下面的方法获取应用程序中实现MyInterface的所有bean(CDI和EJB): 在这里,我看到了两件奇怪的事情: 我只得到CDI豆,没有EJB豆。 当创建直接实现MyInterface接口的EJB bean时,不扩展MyAbstractClass,比在

  • 问题内容: 我目前正在一个项目中,该项目需要保留任何类型的对象(我们没有任何控制权的实现),以便以后可以恢复这些对象。 我们无法实现ORM,因为我们不能在开发时限制我们库的用户。 我们的第一个选择是使用Java默认序列化对其进行序列化,但是当用户开始传递同一对象的不同版本(属性更改的类型,名称等)时,恢复对象存在很多麻烦。 我们尝试使用XMLEncoder类(将对象转换为XML),但是发现缺少功能

  • 我遇到了这个问题,OP想要改进下面的if块。我把这作为一个新问题来回答,因为我正在寻找这类问题的更一般的解决方案。 现在有获得结果的可能性,其中。一些答案建议使用多数组作为表来减少if-丛林。 但是我想知道如何用大n和k来解决这样的问题?因为使用if、switch和建议的数组方法的解决方案无法很好地扩展,因此应避免在代码中键入类似的内容。 如果我考虑组合问题,必须有一种方法来轻松评估它们。

  • 分包 建议将服务接口、服务模型、服务异常等均放在 API 包中,因为服务模型和异常也是 API 的一部分,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)。 如果需要,也可以考虑在 API 包中放置一份 Spring 的引用配置,这样使用方只需在 Spring 加载过程中引用此配置即可。配置建议放在模块的包目录下,以免冲突,如:com/alibaba/china/xxx/d