• Spring 条件装配


    定义

    从Spring Framework 3.1开始,允许Bean 装配时增加前置条件判断

    判断方式

    @Profile: 配置化条件装配,Spring Framework 3.1
    @Conditional:编程条件装配,Spring Framework 4.0

    实现方式

    • 注解方式-- @Profile
    首先定义一个接口
    /**
     * 计算整数求和
     */
    public interface CalculateService {
    
        Integer sum(Integer... values);
    }
    
    分别用两个实现类去实现,在类上使用 `@Profile`注解进行配置
    @Profile("java7")
    @Service
    public class Java7CalculateServiceImpl implements CalculateService {}
    
    
    @Profile("java8")
    @Service
    public class Java8CalculateServiceImpl implements CalculateService {}
    
    在进行服务的调用时使用 profiles 的方式进行指定
        public static void main(String[] args) {
            ConfigurableApplicationContext context = new SpringApplicationBuilder(CalculateServiceBootStrap.class)
                    .web(WebApplicationType.NONE)
                    .profiles("java7")
                    .run(args);
                    
           // 这种方式如果没有指定profile,会出现异常(NoSuchBeanDefinitionException: No qualifying bean of type *** available)
            CalculateService calculateService = context.getBean(CalculateService.class); 
         }
    
    • 编程方式
      上面描述的profile注解实现方式,从注解的定义上可以看到,他的底层就是用@Conditional实现的,而ProfileCondition类是通过实现Condition接口的matches方法,在这个方法中通过编程条件进行过滤,返回true即可对使用了Profile注解的类进行装配
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional({ProfileCondition.class})
    public @interface Profile {
        String[] value();
    }
    
    class ProfileCondition implements Condition {
        ProfileCondition() {
        }
    
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
            if (attrs != null) {
                Iterator var4 = ((List)attrs.get("value")).iterator();
    
                Object value;
                do {
                    if (!var4.hasNext()) {
                        return false;
                    }
    
                    value = var4.next();
                } while(!context.getEnvironment().acceptsProfiles(Profiles.of((String[])((String[])value))));
    
                return true;
            } else {
                return true;
            }
        }
    }
    

    结合上面的这个实现下面进行手工的配置,仿造上面实现的方法:

    1. 新建类实现 Condition接口的matches方法
    public class HelloWorldCondition implements Condition {
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        	// 这里的annotatedTypeMetadata可以获取指定类的一些属性(TestCondition是我自己新建的一个注解)
            Map<String, Object> attrs = annotatedTypeMetadata.getAnnotationAttributes(TestCondition.class.getName());
            // 这里是获取这个注解的属性
            String name = String.valueOf(attrs.get("name"));
            String value = String.valueOf(attrs.get("value"));
            // 这里我直接获取了系统配置的值,用来进行判断
            String propertyName = System.getProperty(name);
            return propertyName.equals(value);
        }
    }
    
    1. 新建注解,使用@Conditional去关联上面的HelloWorldCondition 实现,来进行条件的判断
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional({HelloWorldCondition.class})
    public @interface TestCondition {
        String name();
        String value();
    }
    
    1. 使用注解,放在需要被装配上,这里我放在了一个bean上
        @Bean
        // name 设置成user.name是为了配合上面的获取系统配置的user.name的值,后面的value值会和系统的name值进行判断,如果相同matches方法就会返回true,这样就能将helloWorld这个bean进行自动装配
        @TestCondition(name = "user.name", value = "Administrator")
        public String helloWorld() {
            return "Hello, World";
        }
    
    1. 验证是否装配成功
        public static void main(String[] args) {
            ConfigurableApplicationContext context = new SpringApplicationBuilder(HelloWorldConditionBootStrap.class)
                    .web(WebApplicationType.NONE)
                    .run(args);
            // 上面如果通过注解成功进行条件筛选后,容器中是可以直接获取到helloWorld这个bean的,如果能够输出helloWorld返回的值就说明装配成功了
            String helloWorld = context.getBean("helloWorld", String.class);
            System.out.println("helloWorld:" + helloWorld);
            context.close();
        }
    
    1. 假设上面的注解中使用了不匹配的value值,看看报什么错:
        @Bean
        @TestCondition(name = "user.name", value = "Administrator1")
        public String helloWorld() {
            return "Hello, World";
        }
       // 这里在value后面加了一个1,应该和系统默认名称不匹配的,此时启动后出现报错如下:
       NoSuchBeanDefinitionException: No bean named 'helloWorld' available
       此时说明没有装配需要的Bean
    
  • 相关阅读:
    2017年下半年软考合格标准出炉啦
    练网软考知识点整理-项目配置管理流程
    简练网软考知识点整理-项目招标投标中的法律责任
    简练网软考知识点整理-软件维护类型
    简练网软考知识点整理-软件质量保证及质量评价
    简练网软考知识点整理-项目配置管理配置审计
    简练网软考知识点整理-项目问题日志(Issue Log)
    简练网软考知识点整理-风险应对措施(应急计划、弹回计划和权变措施)
    简练网软考知识点整理-项目组织分解结构OBS
    简练网软考知识点整理-项目配置管理计划
  • 原文地址:https://www.cnblogs.com/bolbo/p/10595296.html
Copyright © 2020-2023  润新知