当尝试将参数注入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方法,这一切都可以正常工作,但在这种情况下我更喜欢构造函数注入。
有什么想法,这里出了什么问题?
答案 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
。