Spring除了支持读取自身配置文件外,也可以读取其他常见格式的配置(如properties、yaml等等),Spring对于配置管理提供了大量支持。
1.配置管理
1.1 @Value
@Value注解由Spring3.0提供,用于将外部的值动态注入到Bean中。@Value注解有@Value(“#{}”)和@Value(“${}”)两种形式,其中@Value(“#{}”)表示使用SpEL表达式,可以通过SpEL表达式获取Bean的属性和方法,SpEl表达式中也可以包含常量;@Value(“${}”)用于读取配置文件中定义的属性值。
1.1.1 使用@Value注解将外部的值动态注入到Bean中
package com.example;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
/**
* 下面列举了@Value注解的几种方式使用场景,例如:
* 注入普通字符串
* 注入操作系统属性
* 注入表达式结果
* 注入其他Bean属性:注入beanInject对象的属性author
* 注入文件资源
* 注入URL资源
*/
public class Project {
@Value("normal")
private String normal; // 注入普通字符串
@Value("#{systemProperties['os.name']}")
private String systemPropertiesName; // 注入操作系统属性
@Value("#{ T(java.lang.Math).random() * 100.0 }")
private double randomNumber; //注入表达式结果
@Value("#{beanInject.author}")
private String fromAnotherBean; // 注入其他Bean属性:注入beanInject对象的属性author,详情看BeanInject.class
@Value("classpath:text.txt")
private Resource resourceFile; // 注入文件资源,在项目的src/main/resources下创建text.txt
@Value("http://www.baidu.com")
private Resource testUrl; // 注入URL资源
public String getNormal() {
return normal;
}
public void setNormal(String normal) {
this.normal = normal;
}
public String getSystemPropertiesName() {
return systemPropertiesName;
}
public void setSystemPropertiesName(String systemPropertiesName) {
this.systemPropertiesName = systemPropertiesName;
}
public double getRandomNumber() {
return randomNumber;
}
public void setRandomNumber(double randomNumber) {
this.randomNumber = randomNumber;
}
public Resource getResourceFile() {
return resourceFile;
}
public void setResourceFile(Resource resourceFile) {
this.resourceFile = resourceFile;
}
public Resource getTestUrl() {
return testUrl;
}
public void setTestUrl(Resource testUrl) {
this.testUrl = testUrl;
}
public String getFromAnotherBean() {
return fromAnotherBean;
}
public void setFromAnotherBean(String fromAnotherBean) {
this.fromAnotherBean = fromAnotherBean;
}
@Override
public String toString() {
return "Project{" +
"normal='" + normal + '\'' +
", systemPropertiesName='" + systemPropertiesName + '\'' +
", randomNumber=" + randomNumber +
", fromAnotherBean='" + fromAnotherBean + '\'' +
", resourceFile=" + resourceFile +
", testUrl=" + testUrl +
'}';
}
}
package com.example;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("beanInject")
public class BeanInject {
@Value("z乘风")
public String author;
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
package com.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CustomConfig {
@Bean
public Project getProject(){
return new Project();
}
}
package com.example;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test{
public static void main(String[] args) {
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext("com.example");
Project project =(Project)context.getBean("getProject");
System.out.println(project);
}
}
执行结果:
Project{normal='normal', systemPropertiesName='Mac OS X', randomNumber=23.056497713387113, fromAnotherBean='z乘风', resourceFile=class path resource [text.txt], testUrl=URL [http://www.baidu.com]}
1.1.2 使用@PropertySource加载外部配置文件@Value读取外部配置文件动态注入Bean
Spring提供了@PropertySource注解用于加载外部配置文件并注入到Spring环境中,@PropertySource注解使用value属性(value属性是一个字符串数组)指定一个或多个配置文件的地址,可以是classpath地址也可以是磁盘地址。@Property注解@Value的结合可以实现读取外部配置文件并动态到注入Bean。
#此文件为外部配置文件,以供@PropertySource注解获取数据,该文件位于项目的src/main/resources/application.properties
user.name=z乘风
user.age=18
user.hobby=编程,音乐,黑丝美女
user.attrMap={name:"z乘风",address:"中国"}
package com.example;
import org.springframework.beans.factory.annotation.Value;
import java.util.List;
import java.util.Map;
public class UserInfo {
@Value("${user.name}") // 使用@Value("${}")形式读取配置文件中的属性
private String userName;
@Value("${user.age}")
public Integer age;
@Value("#{'${user.hobby}'.split(',')}") // 读取配置文件的list格式并以,号分割转为字符串数组
public List<String> hobby;
@Value("#{${user.attrMap}}") // 读取配置文件的map格式
public Map<String,String> attrMap;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public List<String> getHobby() {
return hobby;
}
public void setHobby(List<String> hobby) {
this.hobby = hobby;
}
public Map<String, String> getAttrMap() {
return attrMap;
}
public void setAttrMap(Map<String, String> attrMap) {
this.attrMap = attrMap;
}
@Override
public String toString() {
return "UserInfo{" +
"userName='" + userName + '\'' +
", age=" + age +
", hobby=" + hobby +
", attrMap=" + attrMap +
'}';
}
}
package com.example;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
/**
* 使用@PropertySource注解加载指定配置文件到Spring环境中,encoding为解码编码,
* 解码编码若不指定正确则可能导致读取配置乱码。
* @PropertySource等同于Spring配置文件中的
<context:property-placeholder location="classpath:application.properties" />
*/
@PropertySource(value = {"classpath:application.properties"},encoding="utf8")
@Configuration
public class CustomConfig {
@Bean
public UserInfo getUserInfo(){
return new UserInfo();
}
}
package com.example;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.example");
UserInfo userInfo = (UserInfo) context.getBean("getUserInfo");
System.out.println(userInfo);
/**
* 由于@PropertySouce将外部配置文件加载到Spring环境,除了结合@Value注解读取配置文件中 的数据外,也可以通过Spring上下文的getEnvironment方法获取Spring环境中所有环境变量。
*/
ConfigurableEnvironment environment = context.getEnvironment();
/**
* 打印apple,apple是我本机的用户名,user.name环境变量是Spring内部提供的环境变量,
* 优先级高于外部配置文件中的同名变量。
*/
System.out.println(environment.getProperty("user.name"));
System.out.println(environment.getProperty("user.age")); // 18
}
}
执行结果为:
UserInfo{userName='apple', age=18, hobby=[编程, 音乐, 黑丝美女], attrMap={name=z乘风, address=中国}}
apple
18
在Spring4.0中,Spring提供了一个新的注解——@PropertySources,此注解与@PropertySource注解作用类似,都用于导入外部配置文件到Spring环境中,而@PropertySources是以@PropertySource的形式用于多文件导入。
package com.example;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
/**
* 使用@PropertySource注解加载指定配置文件到Spring环境中,encoding为解码编码,
* 解码编码若不指定正确则可能导致读取配置乱码。
*
* @PropertySources注解用于以@PropertySource注解的形式导入多个配置文件。
*/
@PropertySources({
@PropertySource(value = {"classpath:application.properties"},encoding="utf8")
})
@Configuration
public class CustomConfig {
@Bean
public UserInfo getUserInfo(){
return new UserInfo();
}
}
1.2 @ImportSouce
@ImportResource注解用于导入一个或多个spring配置文件.xml。Spring在启动时会默认加载classpath目录下的spring.xml作为配置文件,若要加载指定的spring.xml配置文件,则可以通过@ImportResource注解指定xml配置文件地址,@ImportResource注解可以引入一个或多个spring配置文件.xml,注意不能引入其他格式的配置文件,否则将抛出异常。
package com.haha;
public class User {
private String userName;
private Integer age;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
}
<!-- 该文件为加载的spring配置文件,文件位于src/main/resources/application.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.haha.User">
<property name="userName" value="z乘风"/>
<property name="age" value="18"/>
</bean>
</beans>
package com.haha;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
/**
* Spring在启动时会默认加载classpath目录下的spring.xml作为配置文件,
* 若要加载指定的spring.xml配置文件,则可以通过@ImportResource注解指定xml配置文件
* 地址,@ImportResource注解可以引入一个或多个spring配置文件.xml,
* 注意不能引入其他格式的配置文件,否则将抛出异常。
*/
@ImportResource(value = {"classpath:application.xml"})
@Configuration
public class CustomConfig {
}
package com.haha;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context=
new AnnotationConfigApplicationContext("com.haha");
User user =(User)context.getBean("user");
System.out.println(user.toString());// User{userName='z乘风', age=18}
}
}
1.3 @Import
@Import注解提供与XML中
该注解仅限用于类上,如果需要导入XML或其他非@Configuration bean定义资源,请改用@ImportResource注释。下面列举了@Import注解的四种用法:
1.3.1 @Import注解将标记的类注册成Bean
package com.haha;
public class UserComponent {
public void hello(){
System.out.println("hello");
}
}
package com.haha;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @Import注解可以将标注的类注入到Spring IOC容器。UserComponent.class无需使用@Component、
* @Service等注解注入。
*/
@Import({UserComponent.class})
@Configuration
public class CustomConfig {
}
package com.haha;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context=
new AnnotationConfigApplicationContext("com.haha");
UserComponent userComponent =context.getBean(UserComponent.class);
userComponent.hello(); // hello
}
}
1.3.2 @Import组合@Configuration类
当项目中的配置类比较繁杂时根据”大化小,小聚多”的思想可以对配置类进行拆分,然后通过@Import组合拆分的配置类。
package com.haha;
public class Config {
private String name;
public Config(String name) {this.name = name;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
}
package com.haha;
import org.springframework.context.annotation.Bean;
/**
* 项目配置,由于使用@Import可以注入标识的类,所以@Configuration不是必须的。
*/
public class ProjectConfig {
@Bean
public Config initProjectConfig(){return new Config("ProjectConfig");}
}
package com.haha;
import org.springframework.context.annotation.Bean;
/**
* 数据库配置类,由于使用@Import可以注入标识的类,所以@Configuration不是必须的。
*/
public class DBConfig {
@Bean
public Config initDBConfig(){
return new Config("DBConfig");
}
}
package com.haha;
import org.springframework.context.annotation.Bean;
/**
* 自定义配置类,由于使用@Import可以注入标识的类,所以@Configuration不是必须的。
*/
public class CustomConfig {
@Bean
public Config initCustomConfig(){
return new Config("CustomConfig");
}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* 使用@Import将配置类组合为一个配置类
*/
@Import({CustomConfig.class,ProjectConfig.class,DBConfig.class})
@Configuration
public class ComposeConfig {
}
package com.haha;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
/**
* 由于ComposeConfig.class使用@Import导入了多个@Configuration配置类,
* @Import会将标注的类注入到Spring容器,所以只要扫描ComposeConfig.class即可。
*/
AnnotationConfigApplicationContext context=
new AnnotationConfigApplicationContext(ComposeConfig.class);
Config projectConfig =(Config)context.getBean("initProjectConfig");
System.out.println(projectConfig.getName()); // ProjectConfig
Config customConfig =(Config)context.getBean("initCustomConfig");
System.out.println(customConfig.getName()); // CustomConfig
Config dbConfig =(Config)context.getBean("initDBConfig");
System.out.println(dbConfig.getName()); // DBConfig
}
}
执行结果:
ProjectConfig
CustomConfig
DBConfig
1.3.3 @Import导入ImportBeanDefinitionRegistrar接口的实现类
Spring中的Bean大多都是由BeanFactory创建的,Spring中默认对扫描的路径下的类中带有@Configuration和@Componet、@Service、@Controller、@Repository的类创建并添加到Spring容器中。Spring也提供了ImportBeanDefinitionRegistrar接口,通过实现ImportBeanDefinitionRegistrar重写registerBeanDefinitions
�方法就能动态的注入Bean。
所有实现了ImportBeanDefinitionRegistrar接口的类的都会被ConfigurationClassPostProcessor处理,ConfigurationClassPostProcessor实现了BeanFactoryPostProcessor接口,所以ImportBeanDefinitionRegistrar中动态注册的bean是优先于依赖其的bean初始化,也能被aop、validator等机制处理。
package com.hehe;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Mapper {
}
package com.hehe;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface CustomBean {
}
package com.hehe;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import java.util.Set;
/**
* 继承ClassPathBeanDefinitionScanner类来扫描获取需要注册的Bean
*/
public class MapperBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
public MapperBeanDefinitionScanner(BeanDefinitionRegistry registry,boolean useDefaultFilters) {
super(registry,useDefaultFilters);
}
protected void registerFilters() {
addIncludeFilter(new AnnotationTypeFilter(Mapper.class));
}
/**
* 重写doScan方法,用于指定扫描范围
* @param basePackages 包路径
* @return
*/
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
return super.doScan(basePackages);
}
}
package com.hehe;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
public class AutoConfigureRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
ResourceLoader resourceLoader;
/**
* 此方法用于注册Bean信息,我们常说的Bean在Spring中抽象成BeanDefinition接口,之后放入Spring容器中,
* Spring IOC容器其实就是Beanfactory中的一个 Map,key是Bean的名称,
* value是Bean对应的BeanDefinition,注册Bean的方法由BeanFactory子类实现。
*
* @param metadata 注解元信息,获取当前类上的注解元信息
* @param registry Bean注册器,用于动态的注册Bean
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
/**
* 打印:[org.springframework.context.annotation.Import, org.springframework.context.annotation.Configuration]
* 说明:由于AutoConfig.class通过@Import注解导入了AutoConfigureRegistrar.class(当前类),
* metadata可以获取到@Import和@Configuration注解
*/
System.out.println(metadata.getAnnotationTypes());
/**
* BeanDefinitionRegistry根据Bean的全限定类路径来注册Bean。首先通过containsBeanDefinition
* 方法判断Spring容器中是否存在Bean Name为beanComponent的Bean,若不存在则初始化
* 一个RootBeanDefinition实例,RootBeanDefinition类继承自beanDefinition,
* 然后通过BeanDefinitionRegistry的registerBeanDefinition将RootBeanDefinition实例
* 注册到Spring容器。registerBeanDefinition方法参数1为Bean的Name,参数2是一个需要注册到
* Spring容器的BeanDefinition对象。
*/
// 判断Spring容器中是否存在Bean Name beanComponent的Bean
boolean bool=registry.containsBeanDefinition("beanComponent");
if(!bool){
/**
* 初识化一个RootBeanDefinition,RootBeanDefinition继承自BeanDefinition接口,
* RootBeanDefinition也提供了根据beanClassName获取RootBeanDefinition实例的构造函数,
* 例如:new RootBeanDefinition("com.hehe.BeanComponent")
*/
RootBeanDefinition beanDefinition=new RootBeanDefinition(BeanComponent.class);
// 将beanDefinition注册到Spring容器
registry.registerBeanDefinition("beanComponent",beanDefinition);
}
/**
* MapperBeanDefinitionScanner继承自ClassPathBeanDefinitionScanner,
* 借助MapperBeanDefinitionScanner实现类来扫描获取需要注册的Bean,由于MapperBeanDefinitionScanner类
* 通过registerFilters方法已经添加注解类型过滤器,注解类型为Mapper.class,下面示例代码中又通过
* MapperBeanDefinitionScanner实例添加了一个注解类型过滤器,注解类型为CustomBean.class,
* 所以如果使用了@Mapper或@CustomBean注解的Bean都会被注入到SpringIoc容器。
*
* MapperBeanDefinitionScanner构造函数,参数一为Bean定义注册器,参数二是否使用默认过滤器处理Bean,
* 由于下面示例中自定义了过滤器,所以不使用默认过滤器。
*/
MapperBeanDefinitionScanner scanner=new MapperBeanDefinitionScanner(registry,false);
// 设置资源处理器
scanner.setResourceLoader(resourceLoader);
// 注册过滤器
scanner.registerFilters();
/**
* 添加要包含的过滤器,AnnotationTypeFilter是最常用的过滤器,根据指定注解进行过滤,
* 除了AnnotationTypeFilter过滤器还有RegexPatternTypeFilter过滤器,根据正则表达式
* 进行过滤Bean。
*/
scanner.addIncludeFilter(new AnnotationTypeFilter(CustomBean.class));
// 设置扫描包范围
scanner.doScan("com.hehe");
}
/**
* 通过实现ResourceLoaderAware接口重写setResourceLoader方法获取ResourceLoader对象
* @param resourceLoader 资源处理器
*/
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader=resourceLoader;
}
}
package com.hehe;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
// 将AutoConfigureRegistrar.class注入到Spring容器
@Import({AutoConfigureRegistrar.class})
@Configuration
public class AutoConfig {
}
package com.hehe;
@CustomBean
public class UserBean {
public String getUser(){
return "userBean";
}
}
package com.hehe;
@Mapper
public class UserMapper {
public String getUser(){
return "{name:'z乘风',age:18}";
}
}
package com.hehe;
public class BeanComponent {
public String getBeanName(){
return "beanComponent";
}
}
package com.hehe;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context=new
AnnotationConfigApplicationContext(AutoConfig.class);
UserMapper userMapper = context.getBean(UserMapper.class);
System.out.println(userMapper.getUser()); // {name:'z乘风',age:18}
UserBean bean = context.getBean(UserBean.class);
System.out.println(bean.getUser()); // userBean
BeanComponent beanComponent =(BeanComponent)context.getBean("beanComponent");
System.out.println(beanComponent.getBeanName());
}
}
执行结果:
[org.springframework.context.annotation.Import, org.springframework.context.annotation.Configuration]
{name:'z乘风',age:18}
userBean
beanComponent
1.3.4 @Import导入ImportSelector接口的实现类
ImportSelector接口用于注册指定Bean的Class名称的Bean。实现ImportSelector接口需要重写selectImports方法,该方法接收一个当前类注解元数据作为参数,返回一个需要注册为Bean的Class的字符串数组,可以在该数组指定需要注册为Bean的Class名称。
package com.aa;
public class Hard {
public String getText(){return "Hard";}
}
package com.aa;
public class Simple {
public String getText(){return "Simple";}
}
package com.aa;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
* ImportSelector接口用于注册指定Bean的Class名称的Bean。
* 实现ImportSelector接口需要重写selectImports方法,该方法接收一个当前类注解元数据作为参数,
* 返回一个需要注册为Bean的Class的字符串数组,可以在该数组指定需要注册为Bean的Class名称。
*/
public class AppConfigSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 将Hard和Simple都注入到Spring容器
return new String[]{
Hard.class.getName(), // Bean Name为com.aa.Hard
Simple.class.getName(), // Bean Name为com.aa.Simple
};
}
}
package com.aa;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Import({AppConfigSelector.class})
@Configuration
public class AppConfig {
}
package com.aa;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context=
new AnnotationConfigApplicationContext(AppConfig.class);
Hard hard=(Hard) context.getBean("com.aa.Hard");
System.out.println(hard.getText()); // Hard
Simple simple = context.getBean(Simple.class);
System.out.println(simple.getText()); // Simple
}
}
执行结果:
Hard
Simple
1.4 @ConfigurationProperties
@ConfigurationProperties这个注解由SpringBoot提供(使用时需要添加SpringBoot依赖),SpringBoot是Spring的超集,SpringBoot相较于Spring提供了更多封装与功能扩展。之所以要介绍@ConfigurationProperties注解是因为应对繁多且有规则的配置文件是非常便捷的,无需使用@Value注解一个一个标注属性,通过@ConfigurationProperties指定需要配置属性的前缀就能根据属性名注入到同名的属性中。
1.4.1 使用@ConfigurationProperties标注类并将读取的数据注入到类
# 该配置文件位于src/main/resources/application.properties。Spring启动时会默认加载此配置文件。
# 注意:读取配置文件中的数据出现乱码时,首先检查配置的编码格式,建议设置为utf-8
server.port=8888
project.version=1.0.0
project.name=dogAdmin
# 解析日期格式
project.lastUpdateTime=2021-01-01 09:01:00
# 解析List格式
project.versionList[0]=1.0.0
project.versionList[1]=1.0.1
project.versionList[2]=1.0.2
# 解析Map格式
project.map.author=z乘风
project.map.email=2684837849@qq.com
project.map.mode=light
package com.fly.config;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Configuration
@ConfigurationProperties(prefix = "project")
/**
* 由于读取配置文件可能会乱码,这里使用@PropertySource注解指定配置文件地址并指定解码编码
*/
@PropertySource(value = {"classpath:application.properties"}, encoding = "utf8")
public class ProjectConfiguration implements Serializable{
private static final long serialVersionUID = -8357041624408744707L;
private String version;
private String name;
/**
* 将Date转换成String,一般后端向前端返回数据时使用。@JsonFormat注解的作用是
* 完成json字符串到java对象的转换工作。
* 注意:使用@JsonFormat注解时推荐类实现Serializable(序列化)接口,因为有时候会出现序列化失败。
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm",timezone="GMT+8")
/**
* 将String转为Date,一般用于前端向后端传递参数时使用,@ConfigurationProperties注解读取的lastUpdateTime
* 属性是字符串,故要转成Date类型。
* 简单来说@DateTimeFormat是处理外部传递过来的参数,而@JsonFormat将内部数据处理后返回给外部。
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastUpdateTime;
private List<String> versionList;
private Map<String,String> map;
public ProjectConfiguration(){}
public ProjectConfiguration(String version, String name, Date lastUpdateTime) {
this.version = version;
this.name = name;
this.lastUpdateTime = lastUpdateTime;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getLastUpdateTime() {
return lastUpdateTime;
}
public void setLastUpdateTime(Date lastUpdateTime) {
this.lastUpdateTime = lastUpdateTime;
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public List<String> getVersionList() {
return versionList;
}
public void setVersionList(List<String> versionList) {
this.versionList = versionList;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
@Override
public String toString() {
// 线程不安全
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
return "ProjectConfiguration{" +
"version='" + version + '\'' +
", name='" + name + '\'' +
", lastUpdateTime=" + format.format(lastUpdateTime) +
", versionList=" + versionList +
", map=" + map +
'}';
}
}
package com.fly;
import com.fly.config.ProjectConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class TestStartApp implements ApplicationRunner {
@Autowired
ProjectConfiguration projectConfiguration;
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(TestStartApp.class);
}
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(projectConfiguration.toString());
}
}
执行结果:
ProjectConfiguration{version='1.0.0', name='dogAdmin', lastUpdateTime=2021-01-01, versionList=[1.0.0, 1.0.1, 1.0.2], map={author=z乘风, email=2684837849@qq.com, mode=light}}
1.4.2 将@ConfigurationProperties和@Bean标注在方法上
@Configuration
public class DataSourceConfig {
@Primary
@Bean(name = "primaryDataSource")
// 将前缀为“spring.datasource.primary”的属性,赋值给DataSource对应的属性值
@ConfigurationProperties(prefix="spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
}
#application.properties
spring.datasource.primary.name=root
spring.datasource.primary.password=123456
1.4.3 使用@ConfigurationProperties注解标注普通类,通过@EnableConfigurationProperties将其注入到IOC容器
@EnableConfigurationProperties用于将标记的一组类注入到Spring容器。
@ConfigurationProperties(prefix = "user1") // User 并没有注入到IOC容器
public class User {
private String name;
// 省略getter/setter方法
}
@SpringBootApplication
// 通过@EnableConfigurationProperties注解将User.class注入到IOC容器,注入后便会使用@ConfigurationProperties注解对属性进行匹配赋值
@EnableConfigurationProperties({User.class})
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
2.SpEL表达式
Spring Expression Language(Spring表达式语言,简称SpEL)是一种强大的表达式语言,支持在运行时查询和操作对象图。语言语法类似于统一 EL,但提供了额外的功能,最显著的是方法调用和基本的字符串模板功能。
虽然还有其他几种可用的 Java 表达式语言——OGNL、MVEL 和 JBoss EL等等,但SpEL的设计目的是向Spring 社区提供一种单一的、支持良好的表达式语言。SpEL 基于与技术无关的 API,所以你也可以集成其他表达式语言。虽然SpEL作为Spring产品的基础,但是它不直接与 Spring 相关联,可以独立使用。SpEL表达式一般在注解中使用的比较多,例如Spring提供的@Value注解或自定义注解,基于SpEL的强大的表达能力能大大提供扩展能力。