(二)spring 高级装配-Condition -条件化的bean

Condition:满足某个特定条件的情况下创建bean

条件化配置bean:

a:@Conditional 指定一个class ,它指明了通过条件对比的类。如果没有指定class则通过Conditon接口进行条件对比:

b:@Conditional 指定的类可以是任意实现了Condition接口的类

c:指定的类需要重写matches方法

 1.例子1:

@Bean
@Conditional(MagicExistsConditon.class) //条件化的创建bean
public MagicBean magicBean(){
   return new MagicBean();  
}

Condition接口:

public interface Condition{
  boolean matches(ConditionContext context,AnnotatedTypeMetadata metadata);
}

MagicExistsConditon实现类:

1 public class MagicExistsCondition implements Condition{
2     public boolean matches(ConditionContext context,
3        AnnotatedTypeMetadata metadata)
4      Environment env = context.getEnvironment();
5      return env.containsProperty("magic");
6     }
7 }    

例子1,Conditional注解指定了实现类作为条件,如果环境中包含magic属性,则会创建magicBean;

ConditionContext 是一个接口:

1 public interface ConditionContext{
2   BeanDefinitionRegistry getRegistry();
3   ConfigurableListableBeanFactory getBeanFactory();
4   Environment getEnvironment();
5   ResourceLoader getResourceLoader();
6   ClassLoader getClassLoader();
7 }

通过ConditionContext可以检查bean的定义;

通过BeanFactory,可以检查bean是否存在,甚至探查bean的属性;

检查环境变量是否存在以及它的值是什么;

ResourceLoader所加载 的资源;

ClassLoader加载并检查类是否存在;

AnnotatedTypeMetadata接口:能够让我们检查带有@Bean注解的方法上还有什么其他的注解;

publlic interface AnnotatedTypeMetadata{
  boolean isAnnotated(String annotationType);
  Map<String,Object> getAnnotationAttributes(String annotationType);
  Map<String,Object> getAnnotationAttributes(String annotationType,boolean classValuesAsString);
  MultiValueMap<String,Object> getAllAnnotationAttributes(
String annotationType);
   MultiValueMap<String,Object> getAllAnnotationAttributes(String annotationType,boolean classValuesAsString);
}

a:判断是否还有其他注解;

b:检查@Bean注解的方法上其他注解的属性;

 

例子2:@Profile注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.Type,ElementType.METHOD})
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile{
  String[] value();  
}

Profile注解使用了@Conditional注解。

通过查看ProfileConditon的源码,可以发现,它借助ConditonContext得到Environment来检查该Profile是否处于激活状态。

public boolean matches(ConditionContext contex,AnnotatedTypeMeatadata metadata){
    if(context.getEnvironment() != null){
      MultiValueMap<String,Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());  
      if(atts != null){
         for(Object value: attrs.get("value")){
           if(context.getEnvironment().acceptsProfiles((String[]) value)){
              return true;
            }
            return false;
         }
    }
      return true;
  }  
}        

例子3:处理自动装配的歧义性:

当通过@Autowared注入一个接口的时候,如果该接口有多个实现类的时候,spring,不知道该注入那个实现类的代理。

解决方法:

a:通过在实现类上添加注解@Primary与@Component同时使用,代表当出现多个的时候,此类优先注入。

b:存在多个首选的时候,通过@Qualifier注解,@Qualifier(“iceCream”),value的值代表想要注入的bean的ID

c:出现多个ID相同的时候,创建自定义限定符,即@Qualifier(“iceCream”),自定义value的值,如下,cold即自定义的限定符

@Component
@Qualifier("cold")
public class IceCream implements Dersert{......}

d:当出现重复的自定义符时,通过自定义限定符注解,自定义一个注解,加上@Qualifier注解,则自定义的注解也有了Qualifier的功能。当出现自定义限定符重复的时候,可以通过添加多个自定义限定符注解,实现要注入的是哪个bean

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.Constructor,ElementType.FILED,ElementType.METHOD,ElementType.TYPE})
@Qualifier
public @interface cold{.....}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.Constructor,ElementType.FILED,ElementType.METHOD,ElementType.TYPE})
@Qualifier
public @interface creamy{.....}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

posted on 2019-09-24 23:03  我是你爷爷的爷爷  阅读(670)  评论(0编辑  收藏  举报

导航