JavaJava 杂谈Java集合类源码探究

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

2019-04-24  本文已影响3人  48730ba83b2d

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的值,读取不到其他配置文件的值

重点

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注解

用处
测试

还是以上的例子,去掉配置类(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管理
上一篇下一篇

猜你喜欢

热点阅读