当前位置: 首页 > 知识库问答 >
问题:

为什么我需要一个无参数的构造函数来使用ApplicationScoped bean并在CDI中注入构造函数?

富钧
2023-03-14

我试图将构造函数注入模式应用于CDI应用程序中的bean,但遇到以下错误消息

15:18:11,852 ERROR [izone.adams.webapp.error.IzoneExceptionHandler] (default task-40) org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001435: Normal scoped bean class webapp.util.LoginManagerAction is not proxyable because it has no no-args constructor - <unknown javax.enterprise.inject.spi.Bean instance>.
        at org.jboss.weld.bean.proxy.DefaultProxyInstantiator.validateNoargConstructor(DefaultProxyInstantiator.java:50)

的确,为了使用构造函数注入模式,我有意地设计了一个需要参数的构造函数的类:

@ApplicationScoped
@Typed(LoginManagerAction.class)
public class LoginManagerAction extends UtilBasicDispatchAction {

  @Inject
   public LoginManagerAction( SessionManager sessionManager, JMSHealthCheckService jmsHealthCheckService) {
       super();
       this.sessionManager = sessionManager;
       this.jmsHealthCheckService = jmsHealthCheckService;
   }

    ...
    ...

}

通过查看不可代理bean类型的CDI规范,我看到:

3.15.不可修复的bean类型

容器使用代理提供某些功能。容器不能代理某些合法bean类型:

  • 没有不带参数的非私有构造函数的类,
  • 被宣布为最终的类,
  • 具有非静态的、具有公共可见性、受保护可见性或默认可见性的最终方法的类,
  • 基元类型,
  • 和数组类型。

如果注入点解析为bean,则bean类型必须是可代理的:

  • 需要客户端代理,或
  • 具有关联的修饰符,或
  • 具有绑定拦截器

否则,容器将自动检测问题,并将其视为部署问题。

在进一步的“正常作用域”和“伪作用域”一节中,它指出:

所有普通作用域必须显式声明为@NormalScope,以向容器指示需要客户端代理。

如果@applicationscopedbean定义为@normalscope,我需要一个非私有的无参数构造函数。所以我需要一个受保护的无参数构造函数来满足CDI规范?我试过使用受保护的无参数构造函数,它似乎可以工作,但我不明白WELD在这种情况下是如何工作的;它在哪些条件下使用no-args构造函数?为什么这是CDI中的一个要求呢?

Weld是否只使用no-arg来创建代理,但在实际调用底层实现时,使用带参数的基于inject的构造函数?

共有1个答案

关学
2023-03-14

我将尝试一个更广泛的方式来回答它,如果我错过了什么,请在下面告诉我。

焊接需要做什么?

Weld需要的是实例化@normalscopedbean的代理。这样的代理不携带太多信息,它或多或少只是一个委托,而不是上下文实例。代理将是一个扩展bean的类--这里没有说明这一点,但这是Weld(和OWB)的方法。你想想就有道理...型式安全、拦截/装饰冲击等。它如何做到这一点的里程数各不相同。(因为它扩展了bean,所以使用protected无参数构造函数就足够了。它必须调用超类的某个构造函数)

为什么要限制?

无参数构造函数的限制来自于Java本身,在那里,编程实例化对象的唯一合法方法是调用构造函数。请注意,我们讨论的不是代理的实例化,不是bean!调用参数化构造函数来创建代理实际上不是一个选项,因为您没有关于参数应该是什么的上下文。

bean可能有一个带有注入的构造函数(@inject),但代理需要创建一个无参数的构造函数。

此外,它还可能防止一些循环注入的情况。此外,它还可能触发链接到它的其他对象的不希望的初始化。您无法知道在一个带有参数的构造函数中可能会发生什么。

因此,CDI规范要求您具有no-args构造函数,以便Weld可以确保它始终存在,并且可以用于安全地实例化它的代理,而不会产生任何副作用。

当你真的不能有无参数的构造函数时的救命程序

事实上,这种限制是有办法绕开的。一个不可移植的焊接配置选项,它可以使用unsafe代替使用构造函数。如果你想知道如何启用它,请参阅文档。

 类似资料:
  • 一个更一般的问题。如果在常规Spring托管类中使用构造函数注入,则这些类将自动连接,而不需要@autowired注释,即: 在@SpringBootTest类中遵循相同的构造函数注入原则,您需要将@Autowired注释设置为构造函数参数,否则它将无法注入该类,即: 为什么会出现这种差异?

  • 问题内容: 必须使用无参数构造函数(像Hibernate这样的工具会在此构造函数上使用反射来实例化对象)。 我得到了这个手挥手的答案,但是有人可以进一步解释吗?谢谢 问题答案: hibernate,并且通常通过反射创建对象的代码用于创建类的新实例。此方法需要一个公共的无参数构造函数才能实例化该对象。对于大多数用例,提供无参数构造函数不是问题。 有一些基于序列化的技巧可以解决没有no-arg构造函数

  • 问题内容: 在编组期间,JAXB需要一个公共的无参数构造函数吗? 我正在传递一个对象,而不是一个类。为什么JAXB需要构造函数?要构造什么? 问题答案: 在执行封送操作期间,JAXB实现不应需要无参数构造函数。JAXB确实需要一个解组。通常,在创建JAXBContext时,缺少no- arg构造函数会导致错误。您正在使用的JAXB实现可能会延迟初始化,直到执行实际操作为止。 通常,在将来的JAXB

  • 我问这个问题是因为在Python和Java中,如果父类构造函数需要0参数,则不需要调用super()。 Javascript 蟒蛇 Java

  • 想改进这个问题吗 通过编辑此帖子,添加详细信息并澄清问题。 我问这个问题是因为在Python和Java中,如果父类构造函数需要0参数,则不需要调用super()。 Javascript 蟒蛇 Java语言

  • 问题内容: 我对此代码有疑问:https : //github.com/reactjs/redux/blob/master/examples/async/containers/App.js 特别: 我猜这是一个两部分的问题。 为什么我需要将句柄更改设置为类的实例,我不能只对handleChange使用静态函数并直接在类中调用它 ? 我不知道这是怎么回事: 谢谢 问题答案: 以相反的顺序回答… 返回