Spring基础篇-条件注解的实现!

基于条件,向Spring容器中注册Bean.

适用于,不同环境下,代码的生效,以及多环境切换!

以下,以一个例子来进行记录!

基于不同的操作系统,来展示不同的文件展开命令。

首先,定义一个接口!

public interface ShowCmd {
    String cmd();
}

然后,写出两种环境不同的实现类。

public class LinuxCmd implements ShowCmd{
    @Override
    public String cmd() {
        return "ls";
    }
}

public class WindowsCmd  implements ShowCmd{
    @Override
    public String cmd() {
        return "dir";
    }
}

紧接着,创建两个条件,系统根据条件判断是否将bean注册到Spring容器中!

public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String property = context.getEnvironment().getProperty("os.name");
        return property.toLowerCase().contains("linux");
    }
}

public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String property = context.getEnvironment().getProperty("os.name");
        return property.toLowerCase().contains("window");
    }
}

最后,则进行注册


public class JavaConfig {
     @Bean
     @Conditional(WindowsCondition.class)
    ShowCmd winCmd(){
        return  new WindowsCmd();
    }

    @Bean
    @Conditional(LinuxCondition.class)
    ShowCmd linuxCmd(){
        return new LinuxCmd();
    }
}

获取,调用!

  public static void main(String[] args) {
        AnnotationConfigApplicationContext javaConfig = new AnnotationConfigApplicationContext(JavaConfig.class);
        ShowCmd bean = javaConfig.getBean(ShowCmd.class);

        System.out.println(bean.cmd());
    }

多环境切换,基于java代码!

多环境切换的例子,使用Profile实现!
定义一个多数据源,这边是例子,所以很多都是简写!

public class DataSource {

    private String username;
    private String password;
    private String url;
//省略,get  set toString等方法!
}

进行注册


public class JavaConfig {

    @Bean
    @Profile("dev")
    DataSource devDataSource(){
        DataSource dataSource = new DataSource();
        dataSource.setUrl("jdbc:mysql:///dev");
        dataSource.setUsername("dev");
        dataSource.setPassword("dev");
        return dataSource;
    }

    @Bean
    @Profile("prod")
    DataSource prodDataSource(){
        DataSource dataSource = new DataSource();
        dataSource.setUrl("jdbc:mysql:///prod");
        dataSource.setUsername("prod");
        dataSource.setPassword("prod");
        return dataSource;
    }
}

进行调用!

  public static void main(String[] args) {
        //这里需要注意,不能直接添加配置类,如果添加了,refresh方法会被直接调用
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ConfigurableEnvironment environment = ctx.getEnvironment();
        //这里表示,设置当前环境为prod
        environment.addActiveProfile("prod");
        //再去加载配置类
        ctx.register(JavaConfig.class);
        //初始化容器
        ctx.refresh();
        DataSource prodDataSource = ctx.getBean("prodDataSource", DataSource.class);
        System.out.println(prodDataSource);
    }

多环境切换,基于配置类!

 <beans profile="dev">
        <bean class="com.tongzhou.demo.DataSource">
            <property name="password" value="dev"/>
            <property name="url" value="jdbc:mysql:///dev"/>
            <property name="username" value="dev"/>
        </bean>
    </beans>

    <beans profile="prod">
        <bean class="com.tongzhou.demo.DataSource">
            <property name="password" value="prod"/>
            <property name="url" value="jdbc:mysql:///prod"/>
            <property name="username" value="prod"/>
        </bean>
    </beans>

调用!

 public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
        ConfigurableEnvironment environment = ctx.getEnvironment();
        environment.addActiveProfile("dev");
        ctx.setConfigLocation("datasource.xml");
        ctx.refresh();
        DataSource prodDataSource = ctx.getBean(DataSource.class);
        System.out.println(prodDataSource);
    }

原理解析

profile注解定义了一个组合注解,本质上,就是一个条件注解ProfileCondition。

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

紧接着,查看ProfileCondition,可以看到,这可类就实现了Condition 接口


class ProfileCondition implements Condition {
    ProfileCondition() {
    }

    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    //查看profile全部属性,对于condition来说,实际上就只有一个value属性
        MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
        if (attrs != null) {
        //获取value,value是一个数组,所以需要遍历
            Iterator var4 = ((List)attrs.get("value")).iterator();

            Object value;
            do {
                if (!var4.hasNext()) {
                    return false;
                }

                value = var4.next();
            } 
            
            //判断当前系统是否包含这个value
            while(!context.getEnvironment().acceptsProfiles(Profiles.of((String[])((String[])value))));

            return true;
        } else {
            return true;
        }
    }
}

自定义一个profile

首先,定义一个接口

//注解的生命周期,不仅保存在class,jvm加载class后依然存在
@Retention(RetentionPolicy.RUNTIME)
//方法级别上生效
@Target(ElementType.METHOD)
//生效的类
@Conditional(MyProfileCondition.class)
public @interface MyProfile {
    String[] value();
}

定义实现类


public class MyProfileCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        MultiValueMap<String, Object> allAnnotationAttributes = metadata.getAllAnnotationAttributes(MyProfile.class.getName());
        if(allAnnotationAttributes != null){
            List<Object> values = allAnnotationAttributes.get("value");
            for (Object value : values){
                boolean b = context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value));
                if(b){
                    return true;
                }
            }
        }

        return false;
    }
}

最后,则进行测试,与系统中的@profile效果一致!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值