后端——框架——容器框架——spring_boot——《官网》阅读笔记——第三章节3(使用SpringBoot)——核心配置

1、自动注入

1.1   原理

  当类上添加@SpringBootApplication注解时,就可以实现自动注入的功能,在第二章的末尾介绍它等价于@Configuration,@EnableAutoConfiguration,@ComponentScan注解。真正实现自动注入功能的是@EnableAutoConfiguration。

  查看@EnableAutoConfiguration的源码,发现它又等价于@AutoConfigurationPackage,并且引入了AutoConfigurationImportSelector对象。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};
}

  其中@AutoConfigurationPackage用于自动扫描相关的包。

  AutoConfigurationImportSelector中有个方法getCandidateConfigurations,它的调用栈为getCandidateConfiguration---->SpringFactoriesLoader.loadFactoryNames--->loadSpringFactories,查看loadSpringFactories代码如下:

Enumeration<URL> urls = (classLoader != null ?
		ClassLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
		ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));

  其中常量值为:

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

它会加载spring-boot-autoconfiguration-version.jar包,META-INF目录下的spring.factories文件,这个文件就是spring boot自动注入的配置。

1.2  禁用自动配置

  当想要禁用某个自动配置项时,在启动类的SpringBootApplication注解上添加exclude属性,它指定禁用的自动配置项,多个时使用逗号分割。示例如下:

// 禁用了数据源的自动注入功能
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DemoApplication {
	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}
}

  效果如下:

Exclusions:
-----------
    org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

2、配置信息

  在使用Spring时,有两种方式,XML方式,注解方式,它们都是在配置Bean,本质是将bean注入到IOC容器中。在spring boot有个很明显的变化,自动注入,它注入的这些bean虽然有默认值,但是遇到具体的需求,还是需要手动设置这些bean的值。

  例如日志框架logback,之前是添加一份logback.xml,logback框架会根据这份配置文件创建一些对象,如Logger,Appender,这些对象并不在IOC容器中。Spring boot项目自动检测logback相关依赖,存在便自动注入bean,如ConsoleAppender,它有默认的pattern属性值,当不满足我们的需求时,就需要手动配置这些信息。

  大部分的配置信息本质上都是给对象的属性赋值,我把它分为两类,

  1. 第一类为集成框架,框架核心对象的配置信息。
  2. 第二类为自定义的对象赋值。

  少部分的配置信息是给容器上下文中添加全局变量。

2.1  定义配置信息

  Spring boot获取配置信息的方式和顺序如下,如果找到则不会再继续往下查找。

  1. Devtools global settings properties:略
  2. @TestPropertySource:略
  3. @SpringBootTest:略
  4. Command line arguments:命令行的参数
  5. spring.application.json:变量spring.application.json,它的值是一个JSON字符串
  6. ServletConfig:ServletConfig对象中的初始化参数
  7. ServletContext:ServletContext对象中的初始化参数
  8. JNDI:略
  9. System.getProperties:JVM的系统变量
  10. OS environment:操作系统的环境变量
  11. RandomValuePropertySource:随机数。
  12. Profile-specific outside of the package jar:它是指当前项目中的application-profile配置文件
  13.  Profile-specific inside of the package jar:它是指项目依赖的jar包下存在application-profile配置文件。
  14. Application outside of the package jar:当前项目中的applicaton配置文件。
  15. Application inside of the package jar:项目依赖的jar包下存在的application配置文件
  16.  @PropertySource:使用注解引入的xx.properties文件中定义的变量
  17.  SpringApplication.setDefaultProperties方法或SpringBootBuilder.properties方法。

  Spring的变量确实比较复杂,所以在编写时规范一些,使用一种方式即可。例如都写在xx.properties文件中,然后引入。

2.1.1   命令行参数

  参考CommandLineRunner接口

2.1.2   spring_application_json

  它的值是JSON字符串,会将JSON中所有变量添加到容器中,例如'{"user":{"name":"jack","age":20}}'会把user.name,user.age添加到容器中

  注:spring_application_json只有在命令行时才有效,在配置文件中无效

2.1.3   系统变量

  系统变量有两种,操作系统的变量和JVM的系统变量,JVM也可以获取操作系统变量,调用System.getProperties方法即可,也可以向JVM中添加系统变量,调用System.setProperties。这些变量类似于全局变量,在程序的任何地方都可以获取,例如获取os.name系统变量,程序方式@Value("${os.name}"),配置文件中使用${os.name}。

2.1.4   RandomValuePropertySource

  它的作用是为变量设置随机数(随机数不一定是数字,例如UUID),原著中的示例如下

my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}

2.1.5  配置文件

  配置文件分为两类,一类是名称有profile,另一类是无profile。

  查找无profile的配置文件分为两步:

  1. 第一步:首先需要找到配置文件存放的文件夹,它的默认查找步骤如下:
    • 首先查找current directory下的config子目录,其中current directory为项目的根路径。
    • 其次查找current directory目录。
    • 之后查找classpath下的config子目录,一般这个文件夹为resources/config
    • 最后查找classpath。

  2.第二步:查找配置文件名称,它的默认查找步骤如下:

    • 首先查找application.properties,
    • 其次查找application.yml。

  查找有profile的配置文件步骤不变,配置文件名变为application-{profile}.properties

  可以通过设置spring.config.location指定文件夹的路径,设置spring.config.name指定配置文件的名称。

  例如在resources下创建spring文件夹,配置文件名称为application-context.properties。

  需要指定如下配置

--spring.config.location=classpath:/spring/
--spring.config.name=application-context

  注:spring.config.name与spring.config.location写在配置文件中无效,可以设置为JVM变量或者是添加到命令行中

2.1.6  @PropertySource

  是spring 框架的注解,功能是引入xx.properties文件,它有局限性,只在它标注的类上有效。例如多个@Configuration配置类上各自的@PropertySource只对自己有效。

2.1.7  API

  调用SpringBuilder.setDefaultProperties或者SpringBootBuilder.properties方法。我感觉使用System.setProperties更好,JVM系统变量拥有更高的优先级。

2.2   对象的属性(无前缀)

  当变量无前缀时,变量映射为属性遵循驼峰方式,例如userName属性,它会查找:

  1. user-name变量,
  2. user.name变量
  3. userName变量

  注:变量名是不区分大小写的。

  示例如下:

  • 第一步定义变量,我在application.properties中定义变量app.name=learn spring boot
  • 第二步在任何类中定义属性appName,在属性上添加@value注解
@Value("${app.name}")
private String appName;
  • 第三步验证,
********************
项目名称是:learn spring boot

  它与类无关,只与属性的名称有关,极大可能会引起重名。

2.3  对象的属性(有前缀)

  当变量有前缀时,首先前缀映射到具体的类,变量名去除前缀的部分映射为属性,例如需要为User类属性赋值

  1. 第一步,定义User类,拥有三个属性
/**
 * 
 * @Title: User.java
 * @Package learn.spring.boot.bean
 * @Description: 用户类
 * @version V1.0
 */
@Component
@ConfigurationProperties(prefix = "test-user")
public class User {
	// 用户姓名
	private String name;
	// 用户地址
	private String address;
	// 用户年龄
	private Integer age;
	// get & set省略
}

  2.第二步,定义变量,这里我单独定义了user.properties文件,并且通过@PropertySource引入,也可以直接定义在application.proerties文件中

# user name
testUser.name=Jack
# user age
testUser.age=20
# user address
testUser.address=some place

  3.第三步:通过ApplicationContext获取User对象

// 获取用户对象
ApplicationContext ac = builder.context();
User user = ac.getBean("user",User.class);
System.out.println("***********************");
System.out.println("user Name:"+user.getName());
System.out.println("user Age:"+user.getAge());
System.out.println("user Address:"+user.getAddress());

  4.第四步:验证

***********************
user Name:Jack
user Age:20
user Address:some place

  注:

  • 在设置对象属性时,不再使用@Value注解。
  • 需要深刻变量名与属性名之间的映射关系

3、Profiles

  Profile指针对不同场景加载不同的配置文件,此时配置文件的名称默认为application-profile.properties。

  使用Profile有两个步骤,

    1. 创建application-{profile}.properties文件,本示例中创建application-test和application-production
    2. 激活profile。

  激活profile的方式有三种

    1. 第一种设置spring.profiles.active变量
    2. 第二种方式在启动类上添加@ActiveProfiles注解
    3. 第三种方式调用SpringBootBuilder的profiles方法。
原文地址:https://www.cnblogs.com/rain144576/p/12498486.html