spring boot 三:5.底层注解@ConfigurationProperties配置绑定
1 前言:配置绑定
使用java读取properties文件中的内容,并且把它封装到JavaBean中:
在domain下新建一个组件getProperties:
package com.xiaoxu.domain;
import org.springframework.stereotype.Component;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
/**
* @author xiaoxu
* @date 2022-01-11
* Ymybatis:com.xiaoxu.domain.getProperties
*/
@Component
public class getProperties {
public void getSrcProperties() throws IOException {
Properties p=new Properties();
p.load(new FileInputStream("src/main/resources/jdbc.properties"));
Enumeration<?> enumeration = p.propertyNames();
System.out.println("配置文件名字:"+enumeration);
while(enumeration.hasMoreElements()){
String key = (String)enumeration.nextElement();
String value = p.getProperty(key);
System.out.println("key:"+key+";"+"value:"+value);
//封装到JavaBean中
}
}
}
然后主程序类中调用该方法:
package com.xiaoxu;
import com.xiaoxu.domain.User;
import com.xiaoxu.domain.getProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import java.io.IOException;
/**
* @author xiaoxu
* @date 2022-01-07
* Ymybatis:com.xiaoxu.MainApplication
*/
@SpringBootApplication(scanBasePackages = {"com.xiaoxu"})
//@EnableAutoConfiguration
//@ComponentScan
//@SpringBootConfiguration
public class MainApplication {
public static void main(String[] args) throws IOException {
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
System.out.println("*******开始*********");
getProperties bean1 = run.getBean(getProperties.class);
bean1.getSrcProperties();
System.out.println("*******结束*********");
}
}
结果如下:
*******开始*********
配置文件名字:java.util.Hashtable$Enumerator@4912d525
key:url;value:jdbc:mysql://localhost:3306/xiaoxu?useUnicode=true&characterEncoding=utf-8
key:password;value:******
key:driver;value:com.mysql.cj.jdbc.Driver
key:username;value:root
*******结束*********
但是,上述方式读取配置文件中,含有中文时,是会出现乱码的,比如:
package com.xiaoxu.domain;
import org.springframework.stereotype.Component;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
/**
* @author xiaoxu
* @date 2022-01-11
* Ymybatis:com.xiaoxu.domain.getProperties
*/
@Component
public class getProperties {
public void getSrcProperties() throws IOException {
Properties p=new Properties();
p.load(new FileInputStream("src/main/resources/ts.properties"));
Enumeration<?> enumeration = p.propertyNames();
System.out.println("配置文件名字:"+enumeration);
while(enumeration.hasMoreElements()){
String key = (String)enumeration.nextElement();
String value = p.getProperty(key);
System.out.println("key:"+key+";"+"value:"+value);
//封装到JavaBean中
}
}
}
执行springboot的MainApplication主程序类,读取数据如下:
使用InputStreamReader增加properties文件读取的encoding:
package com.xiaoxu.domain;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Properties;
/**
* @author xiaoxu
* @date 2022-01-11
* Ymybatis:com.xiaoxu.domain.getProperties
*/
@Component
public class getProperties {
public void getSrcProperties() throws IOException {
Properties p=new Properties();
InputStream resourceAsStream = Object.class.getResourceAsStream("/ts.properties");
p.load(new InputStreamReader(resourceAsStream,"utf-8"));
Enumeration<?> enumeration = p.propertyNames();
System.out.println("配置文件名字:"+enumeration);
while(enumeration.hasMoreElements()){
String key = (String)enumeration.nextElement();
String value = p.getProperty(key);
System.out.println("key:"+key+";"+"value:"+value);
//封装到JavaBean中
}
}
}
重新执行springboot主程序类:
2 @ConfigurationProperties配置绑定
2.1 对于实体类Fruit,使用配置绑定:@ConfigurationProperties(prefix = “new-fruit”),就会默认读取application.yml配置文件中,以new-fruit开头的,自动装配为bean:
package com.xiaoxu.domain;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author xiaoxu
* @date 2022-01-07
* Ymybatis:com.xiaoxu.domain.Fruit
*/
//@Component
@ConfigurationProperties(prefix = "new-fruit")
public class Fruit {
/**
* 水果名称
*/
private String fname;
/**
* 水果价格
*/
private BigDecimal price;
/**
* 水果数目
*/
private long count;
/**
* 水果过期时间
*/
private Date dropDate;
public Fruit() {
}
public Fruit(String fname, BigDecimal price, long count, Date dropDate) {
this.fname = fname;
this.price = price;
this.count = count;
this.dropDate = dropDate;
}
public Date getDropDate() {
return dropDate;
}
public void setDropDate(Date dropDate) {
this.dropDate = dropDate;
}
public String getFname() {
return fname;
}
public void setFname(String fname) {
this.fname = fname;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public long getCount() {
return count;
}
public void setCount(long count) {
this.count = count;
}
@Override
public String toString() {
return "水果{" +
"fname='" + fname + '\'' +
", price=" + price +
", count=" + count +
", dropDate=" + dropDate +
'}';
}
}
注意,如果这里不给Fruit类加上@Component(或者@Service、@Repository、@Controller注解),那么即使使用了配置绑定,这个组件(bean)也没有注册到springboot中,无法通过run.getBeanNamesForType(Fruit.class)来获得该fruit组件(@Component,默认的组件名称,是类的小驼峰写法),如下:
为实体类Fruit增加@Component注解,重新执行主程序类:
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
使用run.getBeanNamesForType可以拿到Fruit类相关的全部组件bean:
针对这三个Fruit相关的组件,另外两个如下:
package com.xiaoxu.config;
import com.xiaoxu.domain.Fruit;
import com.xiaoxu.domain.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.*;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author xiaoxu
* @date 2021-12-27
* Ymybatis:com.xiaoxu.config.MyConfig
*/
//@Import({User.class})
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = "my")
@ImportResource(value = "classpath:beans.xml",locations = "classpath:beans.xml")
public class MyConfig {
// @Bean(name = "fruit")
@Bean(name = "myfruit",value = "myfruit")
// @ConditionalOnBean(name = "myuser")
public Fruit getFruit() throws ParseException {
Fruit fruit = new Fruit();
fruit.setFname("桃子");
fruit.setPrice(new BigDecimal("12.5"));
fruit.setCount(120);
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(s.format(new Date()));
String d = s.format(new Date());
System.out.println(s.parse(d));
fruit.setDropDate(s.parse(d));
return fruit;
}
@Bean
public User getUser(){
User u=new User();
u.setName("xiaoxu");
u.setAge((byte)29);
u.setMoney(new BigDecimal("10"));
u.setId(1234);
return u;
}
}
这是config下的MyConfig配置类,因为使用了@ImportResource(value = “classpath:beans.xml”,locations = “classpath:beans.xml”)注解,所以也导入了beans.xml里面的lizhi_fruit组件:
2.2 针对配置绑定、配置类@Bean、以及@ImportResource(value = “classpath:beans.xml”,locations = “classpath:beans.xml”)这几种方式为springboot导入组件bean,就不能单独使用@Autowired注入组件了:
如果Fruit的Controller下要自动注入Fruit相关的组件,springboot会提示:
所以这时不能仅使用@Autowired,还需要使用@Qualifier(value=“myfruit”)来指定这个组件
postman调用结果如下:
可见,即便是@Qualifier指定的bean是myfruit或者lizhi_fruit,不会抛错,但是springboot拿到的只会是配置绑定的fruit组件。
2.3 上面演示了在实体类Fruit上,增加@Component、@ConfigurationProperties(prefix = “new-fruit”),如果实体类上只有@ConfigurationProperties(prefix = “new-fruit”),那么可以通过在配置类上(使用了@Configuration注解的类为配置类)增加@EnableConfigurationProperties(Fruit.class)来实现配置绑定:
package com.xiaoxu.config;
import com.xiaoxu.domain.Fruit;
import com.xiaoxu.domain.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.*;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author xiaoxu
* @date 2021-12-27
* Ymybatis:com.xiaoxu.config.MyConfig
*/
//@Import({User.class})
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = "my")
@ImportResource(value = "classpath:beans.xml",locations = "classpath:beans.xml")
@EnableConfigurationProperties(Fruit.class)
public class MyConfig {
// @Bean(name = "fruit")
@Bean(name = "myfruit",value = "myfruit")
// @ConditionalOnBean(name = "myuser")
public Fruit getFruit() throws ParseException {
Fruit fruit = new Fruit();
fruit.setFname("桃子");
fruit.setPrice(new BigDecimal("12.5"));
fruit.setCount(120);
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(s.format(new Date()));
String d = s.format(new Date());
System.out.println(s.parse(d));
fruit.setDropDate(s.parse(d));
return fruit;
}
@Bean
public User getUser(){
User u=new User();
u.setName("xiaoxu");
u.setAge((byte)29);
u.setMoney(new BigDecimal("10"));
u.setId(1234);
return u;
}
}
然后,该组件名称会改为如下(prefix+"-"+全限定Fruit类名):
然后重新调用FruitController结果还是配置绑定的:
注意:如果去掉Fruit实体类上方的@ConfigurationProperties(prefix = “new-fruit”)配置绑定注解,也需要去掉配置类上的@EnableConfigurationProperties(Fruit.class),否则springboot抛错,配置类找不到配置绑定:
java.lang.IllegalStateException: No ConfigurationProperties annotation found on 'com.xiaoxu.domain.Fruit'.
故而,一般是实体类@Component和@ConfigurationProperties(prefix = “new-fruit”)一起使用;或者是实体类使用@ConfigurationProperties(prefix = “new-fruit”),配置类使用@EnableConfigurationProperties(Fruit.class)。