CDI对象不能用注入的构造函数代理

时间:2017-10-03 11:36:03

标签: java dependency-injection cdi weld

当尝试将参数注入CDI bean(ApplicationScoped)的构造函数时,我遇到了以下问题:

Caused by: org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001435: Normal scoped bean class xx.Config is not proxyable because it has no no-args constructor - Managed Bean [class xx.Config] with qualifiers [@Default @Named @Any].
    at org.jboss.weld.bean.proxy.DefaultProxyInstantiator.validateNoargConstructor(DefaultProxyInstantiator.java:50)
    at org.jboss.weld.util.Proxies.getUnproxyableClassException(Proxies.java:217)
    at org.jboss.weld.util.Proxies.getUnproxyableTypeException(Proxies.java:178)

但是,我在类上有一个注射构造函数:

@Inject
public Config(ConfigLocator configLocator) {
    defaultConfigPath = configLocator.getPath();
    doStuff();
}

使用默认构造函数,变量注入和postconstruct方法,这一切都可以正常工作,但在这种情况下我更喜欢构造函数注入。

有什么想法,这里出了什么问题?

5 个答案:

答案 0 :(得分:3)

我们解决了将类拆分为接口和实现的类似问题。 在你的情况下像这样:

public interface Config
{
  // API here
}

@ApplicationScoped @Priority(0)
public class ConfigImpl implements Config
{
  @Inject
  public ConfigImpl(ConfigLocator configLocator) { ... }

  // API implementation here
}

答案 1 :(得分:2)

实现创建托管bean的代理时需要非私有的非arg构造函数根据非私有的存在,您不会丢失注入的构造函数的功能,不 - arg构造函数。

容器使用代理来允许拦截,修饰和在取消引用bean时检索正确的上下文实例。它还需要允许在bean之间循环注入。

答案 2 :(得分:1)

此示例可能会对您有所帮助:

@ApplicationScoped
public class Config {

    private String defaultConfigPath;  

    @Inject
    public Config(ConfigLocator configLocator) {
       this.defaultConfigPath = configLocator.getPath();
       doStuff();
    }

    // create a no-args constructor which is required for any scoped bean.
    public Config() {
    }

}

您需要在@ApplicationScoped bean中有一个公共的非参数构造函数。

注意:此类的bean仅创建一次,并在应用程序的整个生命周期中都得到维护。该bean将在所有托管bean之间共享。 @ApplicationScoped Bean本质上是单例的。

提到的问题:

Caused by: org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001435: Normal scoped bean class xx.Config is not proxyable because it has no no-args constructor - Managed Bean [class xx.Config] with qualifiers [@Default @Named @Any].
  

可能的原因是需要非依赖范围的bean   为CDI提供一个公共的无参数构造函数,以便它可以选择   在运行时设置所需的代理Bean。

答案 3 :(得分:0)

我认为弗拉基米尔指的是正确的方向。

我只是在学习CDI(和Weld),因此我的答案在所有方面可能都不是100%准确,但似乎你需要在注入点选择一个没有arg构造函数的类型。

我今天在下一个类型层次结构中遇到了同样的错误:

  • 提供了AuthenticationInterceptor界面,
  • 有一个自定义实现InjectableAuthenticationInterceptor,它有一个构造函数,它接受依赖(有趣的是:这对(C)DI一无所知)
  • AuthenticationInterceptor只有一个注入的构造函数。

我有另一个bean,我想注入一个IServerInterceptor的实例。当我将字段定义为类型AuthenticationInterceptor时(因为它是一个接口而焊接可以为它创建代理(?)),它可以正常工作,但是当我将字段定义为// IServerInterceptor.java public interface IServerInterceptor { } // AuthenticationInterceptor.java public class AuthenticationInterceptor extends InterceptorAdapter { private final Predicate<String> validAccessTokenString; private final Function<String, AccessToken> toAccessTokenModel; private final LoginManager<AccessToken> loginManager; public AuthenticationInterceptor(Predicate<String> validAccessTokenString, Function<String, AccessToken> toAccessTokenModel, LoginManager<AccessToken> loginManager) { this.validAccessTokenString = validAccessTokenString; this.toAccessTokenModel = toAccessTokenModel; this.loginManager = loginManager; } // ... } // InjectableAuthenticationInterceptor.java @ApplicationScoped public class InjectableAuthenticationInterceptor extends AuthenticationInterceptor { @Inject public InjectableAuthenticationInterceptor(LoginManager<AccessToken> loginManager) { super(isWelformedAccessToken(), toAccessToken(), loginManager); } } 时它会停止工作。

使用一些代码:

@Inject private IServerInterceptor authenticationInterceptor;

现在,

@Inject private AuthenticationInterceptor authenticationInterceptor;

效果很好,但

{{1}}

没有。

答案 4 :(得分:0)

Splitting中的

interface,实现无法完全解决问题。 问题是interface不会是ApplicationScoped,因为ApplicationScoped Bean需要默认"no args" Construcutor才能被代理。 这样,它将始终创建实现的新实例。 因此,实现的行为就像一个@Dependent带注释的bean。

如果您想通过这种方式解决问题,则需要使用带有@PostConstruct的方法来处理argument的注入,而只能使用non arg constructor