[英]using @Qualifier + @Bean(autowire=Autowire.BY_TYPE) in javaConfig
[英]Spring: Autowire bean that does not have qualifier
是否可以在春季自动装配没有给定限定符的 bean? 用例是拥有所有 bean 的列表,但排除一个:
@Autowired
@NotQualifier("excludedBean") // <-- can we do something like this?
List<SomeBean> someBeanList;
public class Bean1 implements SomeBean {}
public class Bean2 implements SomeBean {}
@Qualifier("excludedBean")
public class Bean3 implements SomeBean {}
在上面的示例中, someList
应该包含Bean1
和Bean2
但不包含Bean3
的实例。
(备注:我知道反之亦然,即向Bean1
和Bean2
添加一些限定符,然后使用该限定符自动装配。)
编辑:一些进一步的澄清:
List<SomeBean> someBeanList;
,但我想在其他地方自动接线。您可以使用元注释@Conditional
和@Qualifier
引入自己的注释
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
@Conditional(MyCondition.class)
public @interface ExcludeBean {
然后介绍可以执行条件逻辑的类
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !metadata.equals(ExcludeBean.class);
}
}
在您的配置类中
@Bean
@ExcludeBean
public BeanA beanA() {
return new BeanA();
}
您还可以通过在特定 bean 上设置autowire-candidate
或通过default-autowire-candidates="list of candidates here"
来将 bean 排除在自动装配候选者之外
要点它的排除 bean 是在上下文中,但没有注入到排除条件的某些情况下。
您可以使用自定义注释和 BeanPostProcessor 排除带有限定符的 bean。 (我作为简单案例的示例,用于 bean 类型的集合,但您可以扩展它)
排除注释:
@Component
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcludeBeanByQualifierForCollectionAutowired {
String qualifierToExcludeValue();
Class<?> aClass();
}
带有注入的 bean 后处理器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
@Component
public class ExcludeAutowiredBeanPostProcessor implements BeanPostProcessor {
@Autowired
private ConfigurableListableBeanFactory configurableBeanFactory;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
ExcludeBeanByQualifierForCollectionAutowired myAutowiredExcludeAnnotation = field.getAnnotation(ExcludeBeanByQualifierForCollectionAutowired.class);
if (myAutowiredExcludeAnnotation != null) {
Collection<Object> beanForInjection = new ArrayList<>();
String[] beanNamesOfType = configurableBeanFactory.getBeanNamesForType(myAutowiredExcludeAnnotation.aClass());
for (String injectedCandidateBeanName : beanNamesOfType) {
Object beanCandidate = configurableBeanFactory.getBean(injectedCandidateBeanName);
Qualifier qualifierForBeanCandidate = beanCandidate.getClass().getDeclaredAnnotation(Qualifier.class);
if (qualifierForBeanCandidate == null || !qualifierForBeanCandidate.value().equals(myAutowiredExcludeAnnotation.qualifierToExcludeValue())) {
beanForInjection.add(beanCandidate);
}
}
try {
field.set(bean, beanForInjection);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
和例子:
public class ParentBean {}
public class Bean1Included extends ParentBean {}
public class Bean2Included extends ParentBean {}
public class Bean3Included extends ParentBean {}
@Qualifier("excludedBean")
public class BeanExcluded extends ParentBean {}
配置
@Configuration
public class BeanConfiguration {
@Bean
public Bean1Included getBean1(){
return new Bean1Included();
}
@Bean
public Bean2Included getBean2(){
return new Bean2Included();
}
@Bean
public Bean3Included getBean3(){
return new Bean3Included();
}
@Bean
public BeanExcluded getExcludedBean(){
return new BeanExcluded();
}
@Bean
public ExcludeAutowiredBeanPostProcessor excludeAutowiredBeanPostProcessor(){
return new ExcludeAutowiredBeanPostProcessor();
}
}
结果:
@ExtendWith(SpringExtension.class) // assumes Junit 5
@ContextConfiguration(classes = BeanConfiguration.class)
public class ExcludeConditionTest {
@Autowired
private ApplicationContext context;
@Autowired
private BeanExcluded beanExcluded;
@ExcludeBeanByQualifierForCollectionAutowired(qualifierToExcludeValue = "excludedBean" , aClass = ParentBean.class)
private List<ParentBean> beensWithoutExclude;
@Test
void should_not_inject_excluded_bean() {
assertThat(context.getBeansOfType(ParentBean.class).values())
.hasOnlyElementsOfTypes(Bean1Included.class,
Bean2Included.class,
Bean3Included.class,
BeanExcluded.class);
assertThat(beansWithoutExclude)
.hasOnlyElementsOfTypes(Bean1Included.class,
Bean2Included.class,
Bean3Included.class)
.doesNotHaveAnyElementsOfTypes(BeanExcluded.class);
assertThat(beanExcluded).isNotNull();
}
}
可能有两种情况:
案例1:Bean3不在spring上下文中;
案例 2:Bean3 在 spring 上下文中,但在某些情况下没有使用 @Autowired 注入,
如果您需要从上下文中排除带有限定符的bean,请使用
@Autowired List someBeanList; -- 这里注入了所有的bean instanceof SomeBean 并在应用程序上下文中注册。
条件 为了注册组件而必须匹配的单个条件。 在 bean 定义即将注册之前立即检查条件,并且可以根据当时可以确定的任何标准自由否决注册。
使用限定符自动装配:
2.1 如果您想在某些 bean/beans 和 xml 配置中从 autowired 值中排除带有 some qualifier 的 bean,您可以使用 autowire-candidate
2.2 您还可以通过 Setter Injection 获取所有自动装配的值并仅过滤您需要的 bean。
//no Autowired. Autowired in method private List<ParentBean> someBeen = new ArrayList<>(); @Autowired public void setSomeBeen(List<ParentBean> beens){ // if you use java 8 use stream api for (ParentBean bean:beens) { Qualifier qualifier = bean.getClass().getAnnotation(Qualifier.class); if(qualifier == null ||!qualifier.value().equals("excludedBean")){ someBeen.add(bean); } } }
2.3 如果您需要真正自定义的东西,您可以使用自定义AutowiredAnnotationBeanPostProcessor :) 并根据您的要求自定义 @Autowired。
来自 spring api AutowiredAnnotationBeanPostProcessor :
注意:默认的 AutowiredAnnotationBeanPostProcessor 将由“context:annotation-config”和“context:component-scan”XML 标签注册。 如果您打算指定自定义 AutowiredAnnotationBeanPostProcessor bean 定义,请删除或关闭默认注释配置。
另一种方法是使用@Qualifier
创建自定义组件
@Component
@Qualifier
public @interface MyComponent {
public boolean isMock() default false;
}
@Autowired
@MyComponent(true)
List<SomeBean> mockList; // will inject just component with "isMock = true"
@Autowired
@MyComponent(false)
List<SomeBean> notMockList; // will inject just component with "isMock = false"
@MyComponent
public class Bean1 implements SomeBean {}
@MyComponent
public class Bean2 implements SomeBean {}
@MyComponent(isMock = true)
public class Bean3 implements SomeBean {}
Obs:此代码未经测试,只是提供一个想法
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.