[英]Spring: Autowire bean that does not have qualifier
Is it possible to autowire a bean that does NOT have the given qualifier in spring?是否可以在春季自动装配没有给定限定符的 bean? The use case would be to have a list of all beans, but exclude one:
用例是拥有所有 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 {}
In the example above someList
should contain an instance of Bean1
and Bean2
but not Bean3
.在上面的示例中,
someList
应该包含Bean1
和Bean2
但不包含Bean3
的实例。
(Remark: I'm aware that the opposite would work, ie add some qualifier to Bean1
and Bean2
and then autowire with that qualifier.) (备注:我知道反之亦然,即向
Bean1
和Bean2
添加一些限定符,然后使用该限定符自动装配。)
EDIT : Some further clarifications:编辑:一些进一步的澄清:
List<SomeBean> someBeanList;
List<SomeBean> someBeanList;
, but I want to autowire it somewhere else. You can introduce you own annotation with meta annotations @Conditional
and @Qualifier
您可以使用元注释
@Conditional
和@Qualifier
引入自己的注释
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
@Conditional(MyCondition.class)
public @interface ExcludeBean {
and then introduce class where you can do your conditional logic然后介绍可以执行条件逻辑的类
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !metadata.equals(ExcludeBean.class);
}
}
In your Configuration class在您的配置类中
@Bean
@ExcludeBean
public BeanA beanA() {
return new BeanA();
}
You can also exclude bean from being candidate for autowiring by setting autowire-candidate
on particular bean or by specifying default-autowire-candidates="list of candidates here"
您还可以通过在特定 bean 上设置
autowire-candidate
或通过default-autowire-candidates="list of candidates here"
来将 bean 排除在自动装配候选者之外
main point it's bean for exclude is in context but not injected into some cases with exclude condition .要点它的排除 bean 是在上下文中,但没有注入到排除条件的某些情况下。
you can do exclude bean with qualifier with custom annotaion and BeanPostProcessor.您可以使用自定义注释和 BeanPostProcessor 排除带有限定符的 bean。 (I did as example for simple case , for collection of bean type , but you can extend it)
(我作为简单案例的示例,用于 bean 类型的集合,但您可以扩展它)
annotaion for exclude :排除注释:
@Component
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcludeBeanByQualifierForCollectionAutowired {
String qualifierToExcludeValue();
Class<?> aClass();
}
bean post processor with injection带有注入的 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;
}
}
and example:和例子:
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配置
@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();
}
}
and result:结果:
@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();
}
}
There might be two cases :可能有两种情况:
case 1 : Bean3 in not in spring context;案例1:Bean3不在spring上下文中;
case 2 : Bean3 is in spring context but not injected in some cases with @Autowired ,案例 2:Bean3 在 spring 上下文中,但在某些情况下没有使用 @Autowired 注入,
if you need to exclude bean with Qualifier from context at all ,use如果您需要从上下文中排除带有限定符的bean,请使用
@Autowired List someBeanList;
@Autowired List someBeanList; -- here injected all beans instanceof SomeBean and registered in application context.
-- 这里注入了所有的bean instanceof SomeBean 并在应用程序上下文中注册。
from spring api来自spring api
Condition A single condition that must be matched in order for a component to be registered.
条件 为了注册组件而必须匹配的单个条件。 Conditions are checked immediately before the bean-definition is due to be registered and are free to veto registration based on any criteria that can be determined at that point.
在 bean 定义即将注册之前立即检查条件,并且可以根据当时可以确定的任何标准自由否决注册。
autowired with qualifier :使用限定符自动装配:
2.1 if you want to exclude bean with the some qualifier from autowired value in some bean/beans and in xml configuration you can use autowire-candidate 2.1 如果您想在某些 bean/beans 和 xml 配置中从 autowired 值中排除带有 some qualifier 的 bean,您可以使用 autowire-candidate
2.2 also you can get all autowired values by Setter Injection and filter only beans that you need. 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 you can use custome AutowiredAnnotationBeanPostProcessor :) and customise @Autowired for you requirements if you need something realy custom. 2.3 如果您需要真正自定义的东西,您可以使用自定义AutowiredAnnotationBeanPostProcessor :) 并根据您的要求自定义 @Autowired。
from spring api AutowiredAnnotationBeanPostProcessor :来自 spring api AutowiredAnnotationBeanPostProcessor :
Note: A default AutowiredAnnotationBeanPostProcessor will be registered by the "context:annotation-config" and "context:component-scan" XML tags.
注意:默认的 AutowiredAnnotationBeanPostProcessor 将由“context:annotation-config”和“context:component-scan”XML 标签注册。 Remove or turn off the default annotation configuration there if you intend to specify a custom AutowiredAnnotationBeanPostProcessor bean definition.
如果您打算指定自定义 AutowiredAnnotationBeanPostProcessor bean 定义,请删除或关闭默认注释配置。
Another way to do this, is creating a custom component with @Qualifier
另一种方法是使用
@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: this code is not tested, just giving an idea Obs:此代码未经测试,只是提供一个想法
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.