Spring实战读书笔记 高级装配(1)

一、条件化装配

1、

当你希望你的bean在特殊条件下才能装配时,比如在声明了特定的bean时,或者配置了特定的环境变量的时候。那么就可以使用 @Conditional注解,可以用在 @Bean注解下。
比如

@Configuration
public class MagicBean {
    @Bean
    @Conditional(MagiExistCondition.class)
    public MagicBean magicBean() {
        return new MagicBean();
    }
}
public class MagiExistCondition implements Condition{
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        //检查magic属性是否存在
        return environment.containsProperty("magic");
    }
}

我们可以看到 @Conditional(MagiExistCondition.class)中的MagiExistCondition实现了Condition接口,而它只有一个matches方法,只有matches方法返回true的时候,magicBean 才会创建。

2、在自定义注解的时候同样也可以用到。

下面这个例子用到了选择性注解和条件注解
①、创建接口
条件接口

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({OnSystemCondition.class})   //这里不再是Import接口,而是Conditional
public @interface ConditionalSystem {
    String system();
}

选择接口

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({HelloWorldConfigSelecltor.class})  //HelloWorldConfigSelecltor 自定义的配置类
public @interface HelloWorldSelector {
    boolean isLinux() default false;
}

选择配置类

//选择性装配
public class HelloWorldConfigSelecltor implements ImportSelector{

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        Map<String, Object> attributesMap = annotationMetadata.getAnnotationAttributes(HelloWorldSelector.class.getName());
        //获取接口中islinux值,根据不同的值装配不同的配置
        boolean islinux = (boolean) attributesMap.get("isLinux");
        if(islinux) {
            return new String[]{HelloWorldConfig.class.getName()};
        } else {
            return new String[]{HelloWorldConfig2.class.getName()};
        }
    }
}

条件配置类

public class OnSystemCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Map<String, Object> attributesMap = annotatedTypeMetadata.getAnnotationAttributes(ConditionalSystem.class.getName());
        System.out.println("------------------?system-->" + attributesMap.get("system"));

        //条件配置,返回true是才装配
        return "linux".equals(attributesMap.get("system").toString());
    }
}

条件配置

@ConditionalSystem(system = "windows")  //条件装配
public class HelloWorldConfig {
    @Bean
    Lfh lfh () {
        System.out.println("-------------->初始化");
        return new Lfh();
    }
}
@ConditionalSystem(system = "linux")  //条件装配
public class HelloWorldConfig2 {
    @Bean
    Lfh lfh () {
        System.out.println("-------------->初始化22222222222222");
        return new Lfh();
    }
}

启动加载

@EnableCaching
@MapperScan("com.example.mapper")
//@HelloWorld  //自定义注解 启动时装配
@HelloWorldSelector(isLinux = false)  //自定义注解 启动时装配 false ,装配HelloWorldConfig2
@SpringBootApplication
public class SpringbootLearnApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringbootLearnApplication.class, args);
	}
}

启动时isLinux = false,根据选择装配,加载HelloWorldConfig2,而根据HelloWorldConfig2上的注解进行条件判断,linux 等于@ConditionalSystem(system = “linux”) 中的system,返回true。

二、自动化装配的歧义

由于 @Autowired是按类型进行装配的。那么当某个接口有多个实现时,就会抛出NoUniqueBeanDefinitionException。
1、在某个实现类上加上 @Primary注解,表明首选bean。

@Component
@Primary
public class Cake implements Dessert{
}

这种方法有限制。当你在多个实现类上加了@Primary注解,还会出现歧义。
2、@Qualifier

	@Autowired
    @Qualifier("cake")
    private Dessert dessert;

Qualifier的参数就是需要注入的bean的ID。
提到Qualifier,必须谈一下 @Resource
@Resource属于J2EE,默认是名称进行装配。如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

那么也可以写成

 @Resource(name="cake")
    private Dessert dessert;

限制: 与 bean的name紧耦合。

3、创建自定义限定符

创建限定符

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD,ElementType.FIELD,ElementType.TYPE})
@Qualifier //代表时Qualifier注解
public @interface Soft {
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD,ElementType.FIELD,ElementType.TYPE})
@Qualifier
public @interface Code {
}

添加在需要创建bean的类上

@Component
@Code
@Soft
public class Cake implements Dessert{
}

自动装配

 @Autowired
    @Code
    @Soft
    private Dessert dessert;

这样就会低耦合,可以随意重构是实现类。

你可能感兴趣的:(spring,读书笔记)