美文网首页JavaJava 杂谈Java集合类源码探究
springBoot学习(二)配置环境动态切换和部分注解的运用

springBoot学习(二)配置环境动态切换和部分注解的运用

作者: 48730ba83b2d | 来源:发表于2019-04-24 21:50 被阅读3次

    SpringBoot配置环境动态切换

    建立第一个配置文件(springBoot默认读取的文件)application.properties

    test.name=default
    test.defaultAge=12
    

    建立第二个配置文件(开发环境)application-dev.properties

    test.name=dev
    test.devAge=13
    

    建立第三个配置文件(用户验收测试环境)application-uat.properties

    test.name=uat
    test.uatAge=14
    

    1.添加启动参数(--spring.profiles.active=),测试结果读取application.properties的值

    2.添加启动参数(--spring.profiles.active=dev),测试结果读取application-dev.properties的值

    3.添加启动参数(--spring.profiles.active=uat),测试结果读取application-uat.properties的值

    4.添加启动参数(--spring.profiles.active=uat,dev),测试结果读取application-dev.properties的值

    5.添加启动参数(--spring.profiles.active=dev,uat),测试结果读取application-uat.properties的值

    6.添加启动参数(--spring.profiles.active=dev),可以读到application.properties的(test.defaultAge)值,读不到uat的(test.uatAge)值。

    7.添加启动参数(--spring.profiles.active=uat),可以读到application.properties的(test.defaultAge)值,读不到dev的(test.devAge)值。

    8.添加启动参数(--spring.profiles.active=),可以读到application.properties的值,读取不到其他配置文件的值

    重点

    • 添加启动参数--spring.profiles.active=“环境代表参数”(此值为文件名“-”与“.”中间的值,此处即为dev或者uat)

    • 可以添加多个参数,通过英文逗号(,)分割

    • 如果添加多个参数,有重复key,值会被覆盖,(配置文件加载顺序详见官方文档:24. Externalized Configuration)

    • 也可以直接在application.properties配置文件中添加spring.profiles.active=“环境代表参数” 来替代启动时候添加的参数

    springBoot自动配置bean

    首先看一个正常配置的bean与打印

    建立一个接口

    package com.yxj.spring;
    
    /**
     * @ProjectName: springBootDemo
     * @Package: com.yxj.spring
     * @Description:
     * @Author:     阿杰
     * @CreateDate: 2019/1/22 22:08
     * @UpdateUser: 暂无
     * @UpdateDate: 2019/1/22 22:08
     * @UpdateRemark: The modified content
     * @Version: 1.0
     */
    public interface MakeApp {
    }
    

    建立两个实现-第一个

    package com.yxj.spring;
    
    /**
     * @ProjectName: springBootDemo
     * @Package: com.yxj.spring
     * @Description:
     * @Author: 阿杰
     * @CreateDate: 2019/1/22 22:13
     * @UpdateUser: 暂无
     * @UpdateDate: 2019/1/22 22:13
     * @UpdateRemark: The modified content
     * @Version: 1.0
     */
    public class Wechat implements MakeApp {
    }
    

    建立两个实现-第二个

    package com.yxj.spring;
    
    /**
     * @ProjectName: springBootDemo
     * @Package: com.yxj.spring
     * @Description:
     * @Author: 阿杰
     * @CreateDate: 2019/1/22 22:14
     * @UpdateUser: 暂无
     * @UpdateDate: 2019/1/22 22:14
     * @UpdateRemark: The modified content
     * @Version: 1.0
     */
    public class PipiXia implements MakeApp {
    }
    

    通过@SpringBootConfiguration与@Bean加载bean

    package com.yxj.spring;
    
    import org.springframework.boot.SpringBootConfiguration;
    import org.springframework.context.annotation.Bean;
    
    /**
     * @ProjectName: springBootDemo
     * @Package: com.yxj.spring
     * @Description:  @SpringBootConfiguration继承自@Configuration,
     * 二者功能也一致,标注当前类是配置类,
     * 并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,
     * 并且实例名就是方法名。
     * @Author: 阿杰
     * @CreateDate: 2019/1/22 22:14
     * @UpdateUser: 暂无
     * @UpdateDate: 2019/1/22 22:14
     * @UpdateRemark: The modified content
     * @Version: 1.0
     */
    @SpringBootConfiguration
    public class LoadMyBean {
    
        @Bean
        public MakeApp createWechat(){
            return new Wechat();
        }
    
    
        @Bean
        public MakeApp createPipiXia(){
            return new PipiXia();
        }
    }
    

    springBoot启动类测试

    package com.yxj.spring;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.context.annotation.PropertySources;
    
    import java.util.List;
    
    /**
     * @ProjectName: springBootDemo
     * @Package: com.yxj.spring
     * @Description:
     * @Author: 杨小杰
     * @CreateDate: 2019/1/18 20:18
     * @UpdateUser: 暂无
     * @UpdateDate: 2019/1/18 20:18
     * @UpdateRemark: The modified content
     * @Version: 1.0
     */
    @SpringBootApplication
    public class SpringBootTestRun {
    
        /**
         * getBeansOfType(MakeApp.class)会装配bean类型是MakeApp的所有实例
         * @param args
         */
        public static void main(String[] args) {
            ConfigurableApplicationContext run = SpringApplication.run(SpringBootTestRun.class, args);
            System.out.println("------------------分割线------------------");
            System.out.println(run.getBeansOfType(MakeApp.class));
        }
    }
    

    测试结果

    ------------------分割线------------------
    {createWechat=com.yxj.spring.Wechat@5cad8b7d, createPipiXia=com.yxj.spring.PipiXia@7b02e036}
    
    可以看到结果把通过@Bean加载的两个MakeApp实现类对象全部打印出来了
    了解Condition接口,实现自定义bean的加载

    源代码

    /*
     * Copyright 2002-2017 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.context.annotation;
    
    import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    /**
     * A single {@code condition} that must be {@linkplain #matches matched} in order
     * for a component to be registered.
     *
     * <p>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.
     *
     * <p>Conditions must follow the same restrictions as {@link BeanFactoryPostProcessor}
     * and take care to never interact with bean instances. For more fine-grained control
     * of conditions that interact with {@code @Configuration} beans consider the
     * {@link ConfigurationCondition} interface.
     *
     * @author Phillip Webb
     * @since 4.0
     * @see ConfigurationCondition
     * @see Conditional
     * @see ConditionContext
     */
    @FunctionalInterface
    public interface Condition {
    
        /**
         * Determine if the condition matches.
         * @param context the condition context
         * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
         * or {@link org.springframework.core.type.MethodMetadata method} being checked
         * @return {@code true} if the condition matches and the component can be registered,
         * or {@code false} to veto the annotated component's registration
         */
        boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
    
    }
    

    上诉代码描述了matches返回值如果是ture就会再加bean,反之则反

    实现自定义Condition

    新建Wechat自定义Condition,默认返回false(不装配bean)

    package com.yxj.spring;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    import org.springframework.util.StringUtils;
    
    /**
     * @ProjectName: springBootDemo
     * @Package: com.yxj.spring
     * @Description:
     * @Author: 阿杰
     * @CreateDate: 2019/1/22 22:35
     * @UpdateUser: 暂无
     * @UpdateDate: 2019/1/22 22:35
     * @UpdateRemark: The modified content
     * @Version: 1.0
     */
    public class WechatCondition implements Condition {
    
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return false;
        }
    }
    

    新建PipiXia自定义Condition,默认返回true(装配bean)

    package com.yxj.spring;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    import org.springframework.util.StringUtils;
    
    /**
     * @ProjectName: springBootDemo
     * @Package: com.yxj.spring
     * @Description:
     * @Author: 阿杰
     * @CreateDate: 2019/1/22 22:35
     * @UpdateUser: 暂无
     * @UpdateDate: 2019/1/22 22:35
     * @UpdateRemark: The modified content
     * @Version: 1.0
     */
    public class PipiXiaCondition implements Condition {
    
        /**
         *当name不为空的时候,判断如果name中包含appName的时候返回true
         * @param context
         * @param metadata
         * @return
         */
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return true;
        }
    }
    

    在@Bean所在的类中添加自定义条件,配合@Conditional注解来实现

    package com.yxj.spring;
    
    import org.springframework.boot.SpringBootConfiguration;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    
    /**
     * @ProjectName: springBootDemo
     * @Package: com.yxj.spring
     * @Description:  @SpringBootConfiguration继承自@Configuration,
     * 二者功能也一致,标注当前类是配置类,
     * 并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,
     * 并且实例名就是方法名。
     * @Author: 阿杰
     * @CreateDate: 2019/1/22 22:14
     * @UpdateUser: 暂无
     * @UpdateDate: 2019/1/22 22:14
     * @UpdateRemark: The modified content
     * @Version: 1.0
     */
    @SpringBootConfiguration
    public class LoadMyBean {
    
        @Bean
        @Conditional(WechatCondition.class)
        public MakeApp createWechat(){
            return new Wechat();
        }
    
    
        @Bean
        @Conditional(PipiXiaCondition.class)
        public MakeApp createPipiXia(){
            return new PipiXia();
        }
    }
    

    再次测试,测试结果

    ------------------分割线------------------
    {createPipiXia=com.yxj.spring.PipiXia@420bc288}
    
    可以看到只打印了一个pipixia实例bean,微信没有装配进来
    SpringBoot中自带的Condition实现

    <figcaption style="margin: 10px 0px 0px; padding: 0px; max-width: 100%; box-sizing: border-box; overflow-wrap: break-word !important; font-size: 0.7em; color: rgb(153, 153, 153); line-height: inherit; text-align: center;"></figcaption>

    image

    可以看到这个是继承了@Conditional注解,传了自定义的class对象,变成了一个新的注解
    常用@Conditional注解使用,可以查看大佬博客https://blog.csdn.net/u012437781/article/details/78626617

    @Import注解

    用处
    • @Import其实就是引入一个或多个配置,可以导入普通类,也可以导入配置类(上述的LoadMyBean为配置类,主要通过@Bean生成bean给spring管理)

    • @Import用来导入一个或多个类(会被spring容器管理),或者配置类(配置类里的@Bean标记的类也会被spring容器管理)

    测试

    还是以上的例子,去掉配置类(LoadMyBean)中的@SpringBootConfiguration注解

    package com.yxj.spring;
    
    import org.springframework.boot.SpringBootConfiguration;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    
    /**
     * @ProjectName: springBootDemo
     * @Package: com.yxj.spring
     * @Description:  @SpringBootConfiguration继承自@Configuration,
     * 二者功能也一致,标注当前类是配置类,
     * 并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,
     * 并且实例名就是方法名。
     * @Author: 阿杰
     * @CreateDate: 2019/1/22 22:14
     * @UpdateUser: 暂无
     * @UpdateDate: 2019/1/22 22:14
     * @UpdateRemark: The modified content
     * @Version: 1.0
     */
    public class LoadMyBean {
    
        @Bean
        @Conditional(WechatCondition.class)
        public MakeApp createWechat(){
            return new Wechat();
        }
    
    
        @Bean
        @Conditional(PipiXiaCondition.class)
        public MakeApp createPipiXia(){
            return new PipiXia();
        }
    }
    

    修改springboot启动类,添加@Import注解

    package com.yxj.spring;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.annotation.*;
    
    import java.util.List;
    
    /**
     * @ProjectName: springBootDemo
     * @Package: com.yxj.spring
     * @Description:
     * @Author: 杨小杰
     * @CreateDate: 2019/1/18 20:18
     * @UpdateUser: 暂无
     * @UpdateDate: 2019/1/18 20:18
     * @UpdateRemark: The modified content
     * @Version: 1.0
     */
    @SpringBootApplication
    @Import(LoadMyBean.class)
    public class SpringBootTestRun {
    
        /**
         * getBeansOfType(MakeApp.class)会装配bean类型是MakeApp的所有实例
         * @param args
         */
        public static void main(String[] args) {
            ConfigurableApplicationContext run = SpringApplication.run(SpringBootTestRun.class, args);
            System.out.println("------------------分割线------------------");
            System.out.println(run.getBeansOfType(MakeApp.class));
        }
    }
    

    测试结果

    ------------------分割线------------------
    {createPipiXia=com.yxj.spring.PipiXia@6548bb7d}
    
    测试结果表明了,虽然配置类没有加入@SpringBootConfiguration,@Component,@Service,@Controller等交给spring管理的注解,但是通过启动类添加@Import引入方式,仍然可以在spring进行依赖注入,交由spring管理

    相关文章

      网友评论

        本文标题:springBoot学习(二)配置环境动态切换和部分注解的运用

        本文链接:https://www.haomeiwen.com/subject/lsgngqtx.html