springBoot学习(二)配置环境动态切换和部分注解的运用
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}