Spring-Boot中properties的使用:@Component与@Autowired注解

版权声明:本文为博主原创文章,未经博主允许不得用于任何商业用途,转载请注明出处。 https://blog.csdn.net/fyyyr/article/details/83621188

首先打开src/main/resources/application.properties,添加配置:

com.template.name=this is a test name
com.template.age=21
  • 用配置类来操作application.properties

在pom.xml中添加一个依赖:

<dependencies>
   ...
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-configuration-processor</artifactId>
       <optional>true</optional>
   </dependency>
</dependencies>

该依赖的主要作用是:spring-boot-configuration-processor jar中提供了一个编译时调用的Java注解处理器,提供对@ConfigurationProperties注解的支持。

在src/main/java/com/项目名/下添加一个java类,用于application.properties属性的获取和存储。

import org.springframework.stereotype.Component;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Component
@ConfigurationProperties(prefix="com.template")
public class Config {
    public String name;
    public int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

注意:

  1. 使用@Component将该类注解为spring的管理类,也就是将一个java类注入到spring容器中,这样注入到spring中的其他类就可以使用该类了。详见附录。
  2. 使用@ConfigurationProperties(prefix="com.template")application.properties中的属性注入到Config类中。其中prefix指定了application.properties中属性的前缀,也就是只有这部分指定的属性才会被注入。Config类的成员变量名与各个指定的application.properties属性名一一对应。例如属性com.template.name,指定了前缀为com.template,那么在Config类中对应的成员变量名就是name。
  3. @ConfigurationProperties(prefix="com.template")是对整个类进行映射。可以使用@Value("${com.template.xxx}")来对单个值进行映射。详见附录。
  • 引用:
@Autowired
private Config cg;
这样就可以使用已注入spring的Config对象cg的值。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.template.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
    @Autowired
    private Config cg;

    @RequestMapping("/test")
    public JSON index() {
        JSON r = new JSONObject();
        ((JSONObject) r).put("name", cg.getName());
        ((JSONObject) r).put("age", cg.getAge());
        return r;
    }
}

整体思路:

  1. 定义一个Config类,使用@ConfigurationProperties(prefix="com.template")@Value("${com.template.xxx}")来作为该类的初始化参数值。这样,当该类的实例注入到spring时,就会以application.properties中的值来初始化该实例。
  2. 为Config类添加@Component注解,这样就会将类注入到spring中。由于1中的设置,注入的Config类实例中各成员变量就是application.properties中的值。
  3. 在需要使用application.properties值的地方,使用:
    @Autowired
    private Config cg;
    来获取到spring中的Config实例。
  4. 调用Config实例的get函数来获取具体值。

以上为通用的properties文件读取方式。无论是默认的application.properties还是用户自定义的properties,都可以用上面的方式来读取。但由于上面没有指定数据源,会默认读取application.properties

  • 用配置类来操作自定义配置文件

设在src/main/resources/下,创建了一个config文件夹,下面添加了一个配置文件template.properties

自定义配置文件使用上面一中的通用方案时,需要在Config类前使用@PropertySource注解设置数据源:

@PropertySource(value = {"classpath:config/template.properties"},ignoreResourceNotFound = false, encoding = "UTF-8", name = "template.properties")

后续的操作就与一完全相同了。

特别注意:自定义的配置文件的内容,与application.properties的内容不能相同,特别是不能出现相同的前缀,否则读出的配置值是application.properties中的,即使通过@PropertySource指定了数据源。

例如:

为src/main/resources/config/template.properties,添加配置:

com.template.name=测试名
com.template.age=21

这个配置与application.properties有相同的前缀,也就是prefix="com.template"

指定数据源为config/template.properties,编译,运行,都是正常的。但获取到name属性,会发现其值是this is a test name,而非测试名

修改template.properties的前缀:

config.template.name=测试名
config.template.age=21

同时需要修改:

@ConfigurationProperties(prefix="config.template")

再次获取name属性,会发现其值已经是测试名

  • Environment变量操作application.properties

对于默认的application.properties,Spring-Boot本身提供了一个Environment类,且已注入到spring容器中。因此可以直接使用@Autowired获取:

@Autowired
private Environment env;

读取配置时:

String name = env.getProperty("com.template.name");

因此,对于application.properties,使用Environment类更方便。

  • Environment变量操作自定义配置文件

三中的Environment类,不仅可用于读取默认的application.properties,也可以用于操作自定义配置文件。

Environment类定义如下:

public interface Environment extends PropertyResolver {
    String[] getActiveProfiles();

    String[] getDefaultProfiles();

    boolean acceptsProfiles(String... var1);
}

提供了一个acceptsProfiles()函数。该函数可接受多个逗号隔开的String变量,用于为Environment添加新的配置文件。

例如,要将template.properties加入到Environment中来:

boolean r = env.acceptsProfiles("/config/template.properties");

然后就可以使用key来读取配置:

String name = env.getProperty("config.template.name");

然而这也意味着,不同配置文件中的配置项,key一定不可以重复。

  • 通用方案:获取配置文件所有的键值对

上面的一和二,需要对配置文件创建对应的类。这意味着,配置文件的每一个配置项,都要写一个对应的类属性。每增删一个属性,都要同时维护配置文件和对应的类。

上面的三则不存在这些问题,只需要维护一个配置文件,取值的时候传入正确的配置项名即可。推荐使用

除了上面的方式,还可以获取配置文件所有的键值对并保存,这样也能实现读取配置文件的目的。该方式同时适用于application.properties和用户自定义配置文件。

因为配置文件也是个文件,且其格式是固定的。只要读取配置文件,然后按照其格式进行解析,保存为键值对即可。

实际上,Spring-Boot本身提供了一个Properties类,可用于属性的保存,且接受InputStream作为输入。所以只需要将文件读取为一个InputStream,然后传给Properties对象即可。

Properties prop = new Properties();
try {
    InputStream in = Object.class.getResourceAsStream("/config/template.properties");
    prop.load(in);
} catch (IOException e) {
    e.printStackTrace();
}
String name = prop.getProperty("config.template.name").trim();

如上,即可正确取到自定义的属性config.template.name

于是,只需要创建一个单件,在程序启动文件中将配置文件进行加载,然后保存所有的键值对。当需要获取配置文件值的时候,调用该单件取其保存的值。

 

附录

一.关于@Component@Autowired

在spring框架中,有控制反转和依赖注入的特性。spring实现的方式是:

  • 是要求开发者配置一个xml,指定类的名称,路径,以及初始化时传入的参数。
  • spring读取该xml,对该类进行实例化,将其实例化对象(而非类)保存在spring容器中,称之为注入。

有的java类需要这样注入到spring容器中,有的不需要。因此,对于需要注入的,添加xml配置;不需要注入的不用添加。

然而这样意味着开发者除了编写java类,还要编写一个配套的xml配置,于是出现了注解@Component@Component的作用就是告诉spring, 我需要被注入到spring容器中,请按照我自身提供的参数来实例化一个类对象,并放入spring容器中。初始化参数可以通过类的参数默认值定义或者其他注解来提供。详见附录二。

对于已经存在于spring容器中的实例化对象,要引用,同样需要通过xml来配置。例如,一个类Person有一个Car类的属性。实例化类Person时,需要提供Car类的实例化对象做参数。此时,从spring容器中取出已经注入的Car类对象传入即可。

spring的做法,同样是通过xml,来为要实例化的Person类指定已经实例化的Car对象。因为每个实例化的对象都可以定义一个id,所以这个指定可以通过id来进行。

但这样同样意味着需要编写xml。

于是spring提供了@Autowired注解:当需要引用一个spring容器中已注入的类实例时,直接在前面加入@Autowired注解,spring就会自动对已注入的所有类对象进行类型匹配,一旦匹配成功,就直接将其返回。这样就省略掉了xml配置。

这也意味着,spring容器中每个类型的对象有且只有一个。否则,对类型进行匹配后,得到的实例对象为0个或多个,都会报错。

总之,一个类要求按照自身提供的初始化参数进行实例化,并将实例化后的对象注入到spring中,使用@Component;要使用spring中已注入的某个类的实例化对象,使用@Autowired。这两个注解往往配套使用:使用@Component来注入对象,使用@Autowired来使用已注入的对象。

二.类的初始化参数

类的初始化参数最常见的是java所提供的默认值:

public class Config {
    public String name = "this is a name";
}
或:
public class Config {
    public String name; 

    public Config() {
        name = "this is a name";
    }
}

如上,上面两种方式都提供了一个默认的初始化参数name的方式。

对该类添加@Component注解,使用@Autowired来引用后,得到的实例对象是做了对应的初始化的。

@ConfigurationProperties注解的作用是将指定的配置文件映射到该类。也就是:配置文件值→同名类属性。
例如:
配置文件:
com.template.name=this is a test name

类:

@ConfigurationProperties(prefix="com.template")
public class Config {
    public String name; 
}

这样,@ConfigurationProperties会将com.template.name映射给Config类的属性name

也就是相当于:

public class Config {
    public String name = "this is a name";
}

三.注解

spring常用的注解有4种:

@Controller@Service@Repository@Component

这些注解的作用都是将实例化对象注入到spring容器中,本质上是相同的。

然而,除了注入功能,spring还提供抛出异常功能。不同的层,其异常是不同的,例如Controller层与Service层的异常是不同的。

所以,spring通过对类添加不同的注解,来执行对应的异常处理。

这也是为什么一个Controller类只能添加@Controller注解,而不能添加@Service注解。

四.application.properties映射到类

application.properties映射到类有两种方式:

  • @ConfigurationProperties(prefix="com.template")
@ConfigurationProperties(prefix="com.template")
public class Config {
    public String name;
    public int age = 21;
}

这样,Config类进行spring注入时,就会将application.properties中的值赋给Config类同名的成员变量。

  • @Value("${com.template.xxx}")

该方式是对单个值进行映射:

public class Config {
    @Value("${com.template.name}")
    public String name;
    @Value("${com.template.age}")
    public int age = 21;
}

这样,Config类进行spring注入时,就会将application.properties中的值一个一个对应地赋给指定的Config类的成员变量。可以名称不同

注意:@ConfigurationProperties@Value注解都不可以用于局部变量,也就是不能在方法体内使用这两个注解来初始化对象。

 

 

猜你喜欢

转载自blog.csdn.net/fyyyr/article/details/83621188