问题
使用CDI,我希望生成@ApplicationScoped
bean。
此外,我希望为注入点提供配置注释,例如:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Configuration {
String value();
}
我不想为value
的每个不同可能性编写一个单独的生产者。
方法
通常的方法是创建一个生产者并处理注入点注释:
@Produces
public Object create(InjectionPoint injectionPoint) {
Configuration annotation = injectionPoint.getAnnotated().getAnnotation(Configuration .class);
...
}
因此,bean不能再被应用程序限定范围,因为每个注入点可能不同(producer的参数injectionpoint不适用于@aplicationscope
注释的生产者)。
所以这个解决方案不起作用。
问题
我需要具有相同值的注入点获得相同bean实例的可能性。
是否有一种内置的CDI方式?或者我是否需要在列表中以某种方式“记住”bean,例如在包含生产者的类中?
我需要的基本上是为每个不同的值
提供一个应用程序范围
实例。
您尝试实现的不是CDI中的开箱即用功能,而是由于其SPI和便携式扩展,您可以实现所需的功能。
此扩展将分析给定类型的所有注入点,在每个注入点上获取@Configuration
注释,并将在应用程序中为注释中成员value()
的每个不同值创建一个bean。
由于您将使用同一类型注册多个bean,因此首先必须将注释转换为限定符
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
@Documented
public @interface Configuration {
String value();
}
在用于创建bean实例的类下面:
@Vetoed
public class ConfiguredService {
private String value;
protected ConfiguredService() {
}
public ConfiguredService(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
请注意@Vetoed
注释,以确保CDI不会像我们自己那样选择这个类来创建bean。这个类必须有一个没有参数的默认构造函数才能用作钝化bean的类(在应用程序范围内)
然后需要声明自定义bean的类。将其视为工厂和元数据持有者(范围、限定符等)你的豆子。
public class ConfiguredServiceBean implements Bean<ConfiguredService>, PassivationCapable {
static Set<Type> types;
private final Configuration configuration;
private final Set<Annotation> qualifiers = new HashSet<>();
public ConfiguredServiceBean(Configuration configuration) {
this.configuration = configuration;
qualifiers.add(configuration);
qualifiers.add(new AnnotationLiteral<Any>() {
});
}
@Override
public Class<?> getBeanClass() {
return ConfiguredService.class;
}
@Override
public Set<InjectionPoint> getInjectionPoints() {
return Collections.EMPTY_SET;
}
@Override
public boolean isNullable() {
return false;
}
@Override
public Set<Type> getTypes() {
return types;
}
@Override
public Set<Annotation> getQualifiers() {
return qualifiers;
}
@Override
public Class<? extends Annotation> getScope() {
return ApplicationScoped.class;
}
@Override
public String getName() {
return null;
}
@Override
public Set<Class<? extends Annotation>> getStereotypes() {
return Collections.EMPTY_SET;
}
@Override
public boolean isAlternative() {
return false;
}
@Override
public ConfiguredService create(CreationalContext<ConfiguredService> creationalContext) {
return new ConfiguredService(configuration.value());
}
@Override
public void destroy(ConfiguredService instance, CreationalContext<ConfiguredService> creationalContext) {
}
@Override
public String getId() {
return getClass().toString() + configuration.value();
}
}
请注意,限定符是唯一的参数,允许我们将限定符的内容链接到create()
方法中的实例。
最后,您将创建一个扩展,该扩展将从注入点集合中注册bean。
public class ConfigurationExtension implements Extension {
private Set<Configuration> configurations = new HashSet<>();
public void retrieveTypes(@Observes ProcessInjectionPoint<?, ConfiguredService> pip, BeanManager bm) {
InjectionPoint ip = pip.getInjectionPoint();
if (ip.getAnnotated().isAnnotationPresent(Configuration.class))
configurations.add(ip.getAnnotated().getAnnotation(Configuration.class));
else
pip.addDefinitionError(new IllegalStateException("Service should be configured"));
}
public void createBeans(@Observes AfterBeanDiscovery abd, BeanManager bm) {
ConfiguredServiceBean.types = bm.createAnnotatedType(ConfiguredService.class).getTypeClosure();
for (Configuration configuration : configurations) {
abd.addBean(new ConfiguredServiceBean(configuration));
}
}
}
通过将其完全限定的类名添加到META-INF/services/javax,可以激活此扩展。企业注射spi。扩展名
文本文件。
有其他方法可以通过扩展创建功能,但我尝试给您一个从CDI 1.0开始工作的代码(除了@Vetoed
注释)。
您可以在Github上的MyCDI沙箱中找到此扩展的源代码。
代码非常直截了当,但如果您有疑问,请不要犹豫。
Spring Security的Java配置没有公开每个配置对象的每一个属性,这简化了广大用户的配置。毕竟如果要配置每一个属性,用户可以使用标准的Bean配置。 虽然有一些很好的理由不直接暴露所有属性,用户可能任然需要更多高级配置,为了解决这个Spring Security引入了 ObjectPostProcessor 概念,用来修改或替换Java配置的对象实例。例如:如果你想在FilterSec
使用焊接1.1.13。最终在测试与Arquillian...... 假设我向一个字段注入了一些不稳定的东西。比如一个受更改影响的属性,我希望拥有注入点的bean接收更改事件。考虑创建一个CDI扩展。 捕获ProcessAnnotatedType事件并查找在字段注入点上具有自定义注释的所有字段: 之后,他甚至抓取了字段的所有注入点,并用对应于“包装器”类型的新字段替换了底层的WeldField。否则
我运行Kafkajava客户端使用0.10.1.0。根据这里建议的配置https://cwiki.apache.org/confluence/display/KAFKA/Compression 我把 在生产者财产中。但是,当我运行时,生成器会执行配置已提供,但不是已知配置。将显示此警告。 根据API文件,http://home.apache.org/~jgus/kafka-0.10.1.0-rc0
我正在尝试将一个.ear应用程序部署到WildFly10.1Final。ear有2个嵌套的.war文件。war文件中没有“jboss-web.xml”文件。 信息[org.jboss.as.server.deployment.scanner](DeploymentScanner-Threads-1)WFLYDS0004:在部署目录中找到MyApp.ear。要触发部署,请创建一个名为myapp.ea
我部署了我的Rails应用程序,但当我打开它时,我在Web浏览器中收到此错误: 应用程序错误应用程序中发生错误,无法查看您的页面。如果您是应用程序所有者,请查看日志以了解详细信息。 以下是我的日志错误: 2018-03-19T04:48:12.360662 00:00 heroku[路由器]:at=错误代码=H10 desc=“应用程序崩溃”方法=获取路径=“/”主机=marmelade1。her
试图在我的应用程序中实现GCM。编译成功。但当我运行我的应用程序时,它崩溃了。堆栈跟踪: 而且 java.lang.IncompatibleClassChangeError:方法“java.io.file android.support.v4.content.contextCompat.GetNoBackupFilesDir(android.content.context)”应为virtual类型