SpringBoot注解---2.组件赋值

一、@Value

1.作用范围

@Value注解可以标注在字段、方法、参数以及注解上,而且在程序运行期间生效。

2.用法

通过@Value注解将外部的值动态注入到bean的属性中,一般有如下这几种情况:

注入普通字符串

@Value("NNN")
private String name; // 注入普通字符串 

注入操作系统属性

@Value("#{systemProperties['os.name']}")
private String systemPropertiesName; // 注入操作系统属性

注入SpEL表达式结果

@Value("#{ T(java.lang.Math).random() * 100.0 }")
private double randomNumber; //注入SpEL表达式结果

注入其他bean中属性的值

@Value("#{person.name}")
private String username; // 注入其他bean中属性的值,即注入person对象的name属性中的值

注入文件资源

@Value("classpath:/config.properties")
private Resource resourceFile; // 注入文件资源

注入URL资源

@Value("http://www.baidu.com")
private Resource url; // 注入URL资源

3.@Value中#{···}和${···}的区别

  • #{...}:用于执行SpEl表达式,并将内容赋值给属性
  • ${...}:主要用于加载外部属性文件中的值
  • ${...}和#{...}:可以混合使用,但是必须#{}在外面,${}在里面
   说明  举例
${···}的用法 {}里面的内容必须符合SpEL表达式,通过@Value("${spelDefault.value}")我们可以获取属性文件中对应的值,但是如果属性文件中没有这个属性,那么就会报错。不过,我们可以通过赋予默认值来解决这个问题。
@Value("${author.name:meimeixia}")
private String name;
#{···}的用法 {}里面的内容同样也是必须符合SpEL表达式。例如,
// SpEL:调用字符串Hello World的concat方法
@Value("#{'Hello World'.concat('!')}")
private String helloWorld;

// SpEL:调用字符串的getBytes方法,然后再调用其length属性
@Value("#{'Hello World'.bytes.length}")
private String helloWorldBytes;
混合使用
// SpEL:传入一个字符串,根据","切分后插入列表中, #{}和${}配合使用时,注意不能反过来${}在外面,而#{}在里面
@Value("#{'${server.name}'.split(',')}")
private List<String> severs;

  上面片段的代码的执行顺序:通过${server.name}从属性文件中获取值并进行替换,然后就变成了执行SpEL表达式{'server1,server2,server3'.split(',')}

      在上文中#{}在外面,${}在里面可以执行成功,那么反过来是否可以呢?也就是说能否让${}在外面,#{}在里面,就像下面这样呢?

// SpEL:注意不能反过来,${}在外面,而#{}在里面,因为这样会执行失败
@Value("${#{'HelloWorld'.concat('_')}}")
private List<String> severs2;

  答案是不能。因为Spring执行${}的时机要早于#{},当Spring执行外层的${}时,内部的#{}为空,所以会执行失败!

 

二、@PropertySource加载配置文件

1.作用

从@PropertySource的源码中可以看出,我们可以通过@PropertySource注解指定多个properties文件,使用的形式如下所示。

@PropertySource(value={"classpath:/person.properties", "classpath:/car.properties"})

在@PropertySource注解的上面标注了如下的注解信息。这表示我们也可以使用@PropertySources注解来指定properties配置文件。
@Repeatable(PropertySources.class)

通过@PropertySource注解可以将properties配置文件中的key/value存储到Spring的Environment中,Environment接口提供了方法去读取配置文件中的值,参数是properties配置文件中定义的key值。当然了,也可以使用@Value注解用${}占位符为bean的属性注入值。

2.使用注解方式获取值

这里使用的@PropertySource(value={"classpath:/person.properties"})注解就相当于XML配置文件中使用的<context:property-placeholder location="classpath:person.properties" />。

MainConfigOfPropertyValues Person
package com.meimeixia.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import com.meimeixia.bean.Person;

// 使用@PropertySource读取外部配置文件中的key/value保存到运行的环境变量中,加载完外部的配置文件以后,使用${}取出配置文件中的值
@PropertySource(value={"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {

	@Bean
	public Person person() {
		return new Person();
	}
	
}
@Value("${person.nickName}")
private String nickName; // 昵称

3.使用Environment获取值

使用@PropertySource注解读取外部配置文件中的key/value之后,是将其保存到运行的环境变量中了,所以我们也可以通过运行环境来获取外部配置文件中的值。

IOCTest_PropertyValue 结果
@Test
public void test01() {
    printBeans(applicationContext);
    System.out.println("===================");
    
    Person person = (Person) applicationContext.getBean("person");
    System.out.println(person);
    
    ConfigurableEnvironment environment = applicationContext.getEnvironment();
    String property = environment.getProperty("person.nickName");
    System.out.println(property);
    
    // 关闭容器
    applicationContext.close();
}

三、自动装配组件

Spring组件的自动装配就是Spring利用依赖注入,也就是我们通常所说的DI,完成对IOC容器中各个组件的依赖关系赋值。

1.@Autowired

默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);

如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找applicationContext.getBean("bookDao");

@Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名

自动装配默认一定要将属性赋值好,没有就会报错,可以使用@Autowired(required=false);

@Primary:让spring进行自动装配的时候,默认使用首选的bean,也可以继续使用@Qualifier指定需要装配的bean的名字

2.@Qualifier

@Autowired是根据类型进行自动装配的,如果需要按名称进行装配,那么就需要配合@Qualifier注解来使用了。

3.@Primary

在Spring中使用注解时,常常会使用到@Autowired这个注解,它默认是根据类型Type来自动注入的。但有些特殊情况,对同一个接口而言,可能会有几种不同的实现类,而在默认只会采取其中一种实现的情况下,就可以使用@Primary注解来标注优先使用哪一个实现类。

4.@Resource

@Resource注解是Java规范里面的,也可以说它是JSR250规范里面定义的一个注解。该注解默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,那么默认取字段名将其作为组件的名称在IOC容器中进行查找,如果注解写在setter方法上,那么默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的一点是,如果name属性一旦指定,那么就只会按照名称进行装配。

@Resource注解和@Autowired注解的功能是一样的,都能实现自动装配,只不过@Resource注解默认是按照组件名称(即属性的名称)进行装配的。虽然@Resource注解具备自动装配这一功能,但是它是不支持@Primary注解优先注入的功能的,而且也不能像@Autowired注解一样能添加required=false属性。

5.@Inject

@Inject注解也是Java规范里面的,也可以说它是JSR330规范里面定义的一个注解。该注解默认是根据参数名去寻找bean注入,支持Spring的@Primary注解优先注入,@Inject注解还可以增加@Named注解指定要注入的bean。

@Inject注解和@Autowired注解的功能是一样的,都能实现自动装配,而且它俩都支持@Primary注解优先注入的功能。只不过,@Inject注解不能像@Autowired注解一样能添加required=false属性,因为它里面没啥属性。

6.@Resource和@Inject俩注解与@Autowired注解的区别

不同点

  1. @Autowired是Spring中的专有注解,而@Resource是Java中JSR250规范里面定义的一个注解,@Inject是Java中JSR330规范里面定义的一个注解
  2. @Autowired支持参数required=false,而@Resource和@Inject都不支持
  3. @Autowired和@Inject支持@Primary注解优先注入,而@Resource不支持
  4. @Autowired通过@Qualifier指定注入特定bean,@Resource可以通过参数name指定注入bean,而@Inject需要通过@Named注解指定注入bean

相同点

  1. 三种注解都可以实现bean的自动装配。

四、Profile

在容器中如果存在同一类型的多个组件,那么可以使用@Profile注解标识要获取的是哪一个bean。也可以说@Profile注解是Spring为我们提供的可以根据当前环境,动态地激活和切换一系列组件的功能。这个功能在不同的环境使用不同的变量的情景下特别有用,例如,开发环境、测试环境、生产环境使用不同的数据源,在不改变代码的情况下,可以使用这个注解来动态地切换要连接的数据库。

  1. @Profile注解不仅可以标注在方法上,也可以标注在配置类上。
  2. 如果@Profile注解标注在配置类上,那么只有是在指定的环境的时候,整个配置类里面的所有配置才会生效。
  3. 如果一个bean上没有使用@Profile注解进行标注,那么这个bean在任何环境下都会被注册到IOC容器中,当然了,前提是在整个配置类生效的情况下。
原文地址:https://www.cnblogs.com/nxf-rabbit75/p/14619864.html