我知道,如果通过生产者方法实例化,不符合JSP-299的类可以用于注入。
这意味着,如果我想用一个接受参数的构造函数使bean可注入,我可以通过使用生产者方法来实现。
然而,当我这样做时,我在部署时会遇到以下异常:
2015-11-11T21:35:12.099+0000|Grave: Exception during lifecycle processing
org.glassfish.deployment.common.DeploymentException: CDI deployment failure:Exception List with 2 exceptions:
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001435 Normal scoped bean class org.....MongoConfiguration is not proxyable because it has no no-args constructor - Producer Method [MongoConfiguration] with qualifiers [@Any @Default] declared as [[BackedAnnotatedMethod] @Produces @ApplicationScoped public org.....PropertiesProducer.produceMongoConfiguration()].
这是生产商:
public class PropertiesProducer {
private static final String PROPERTIES_FILE = "mongo.properties";
private Properties properties = new Properties();
public static final String DATABASE_NAME = "database.name";
public static final String PORT = "database.port";
public static final String HOST = "database.host";
public static final String USERNAME = "database.username";
public static final String PASSWORD = "database.password";
@Produces
@ApplicationScoped
public MongoConfiguration produceMongoConfiguration(){
final InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(PROPERTIES_FILE);
if (in == null) {
return new MongoConfiguration(properties);
}
try {
properties.load(in);
} catch (IOException e) {
throw new RuntimeException("Failed to load properties", e);
}
finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
// don't care
}
}
return new MongoConfiguration(properties);
}
}
以下是用法:
public class MongoDatastore {
@Inject
MongoConfiguration mongoConfiguration;
@Inject
MongoClient mongoClient;
Datastore datastore;
@PostConstruct
private void setupDatastore() {
Morphia morphia = new Morphia();
datastore = morphia.createDatastore(mongoClient, mongoConfiguration.getDatabaseName());
}
}
我错过了什么显而易见的东西吗?
最简单的解决方案是将范围从@ApplicationScoped
更改为@Singleton
:
import javax.inject.Singleton;
@Produces
@Singleton
public MongoConfiguration produceMongoConfiguration(){
// ...
return new MongoConfiguration(properties);
}
为了澄清,你可以看到这个SO的回答。
BTW:普通作用域@ApplicationScoped
通常优于@Singleton
伪作用域。为什么?例如,因为这样的bean的序列化+反序列化将完美地工作。但在日常工作中,有时我们会遇到不可氧化的第三部分类,我们无法更改它。因此,我们有可能的解决方案:
- 使用
@Singleton
伪作用域 - 创建一个接口,并使用它来代替具体的bean(在生产者方法返回类型和普通代码中)