对于属性的赋值以及如何自动装配是我们在实际编程中经常要实现的功能,spring为我们提供了应有尽有的方式来实现,特别地方便,用好spring还是先用好spring给我们提供的注解开始。理解它们的不同之处也是面试中常问的点。

1. @Value赋值

给一个Person

1
2
3
4
5
6
7
8
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Person {
private String name;
private Integer age;
}

注册到容器中:

1
2
3
4
5
6
7
@Configuration
public class MainConfig3 {
@Bean
public Person person(){
return new Person();
}
}

启动查看一下:

1
2
3
4
5
6
7
8
@Test
public void test03(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig3.class);
System.out.println("容器已经启动成功...");
Person person = applicationContext.getBean(Person.class);
System.out.println(person);//Person(name=null, age=null)
applicationContext.close();
}

那么在以前写配置文件的时候,我们可以在xml中给属性注入值。

1
2
3
4
<bean id="person" class="com.swg.bean.Person">
<property name="age" value="10"/>
<property name="name" value="张三"/>
</bean>

那么现在的注解可以实现这样的功能吗?

  • @Value
1
2
@Value("hello")
private String name;
  • @SpEL表达式
1
2
@Value("#{20-6}")
private Integer age;

2. @PropertySource加载外部配置文件

${}注入属性文件的值

  • 新建一个配置文件db.properties,在里面写:

person.nickname = hello

  • 首先在配置类中声明要引入的配置文件:

@PropertySource(value = “classpath:/db.properties”)

  • 然后再引入:
1
2
@Value("${person.nickname}")
private String nickname;
  • 以前在用xml的时候,是这样引入这个值的:
1
2
3
4
5
<context:property-placeholder location="db.properties"/>


//然后下面就引入这个属性文件的值
<property name="nickname" value="${person.nickname}"/>

自动装配:spring利用依赖注入DI,完成对IOC容器中各个组件依赖关系赋值

3. @Autowired & @Qualifier & @Primary

@Autowired:默认是按照类型去容器中找相应的组件。找到就赋值。

applicationContext.getBean(Person.class)

如果找到多个相同类型的组件,再将属性名(默认是小写字母开头的id或者用@Bean("xxx")中的xxx为属性名)作为组件的id去容器中查找。

applicationContext.getBean(“person”)

所以,最好名字不一样。

如果有多个相同类型的组件,可以用@Qualifier("xxx")可以指定装配的id,而不是属性名。

@Primary:让spring自动装配的时候,默认使用首选的bean;但是如果@Qualifier明确指定了要装配哪一个,还是以@Qualifier为准。

默认,如果容器中没有这个组件,那么@Autowired就会报错。那么可不可以有就装配,没有就算了呢?

@Autowired(required=false)

4. @Resource & @Inject

这两个都是java规范的注解。

  • @Resource–JSR250

默认是按照组件名称进行装配的。没有能支持@Primary@Autowired(required=false)这个功能。

  • @Inject–JSR330

还需要一个依赖:javax.inject

@Autowired差不多,但是比@Autowired稍弱,虽然支持@Primary,但是没有required=false

@Autowiredspring定义的,后两者都是java的规范。

那么这些自动装配功能的注解是如何实现的呢?原来是AutowiredAnnotationBeanPostProcessor来实现的。

5. 方法、构造器位置的自动装配

@Autowired能标注的位置:构造器、参数、方法、属性

  • 写在属性上面:
1
2
@Autowired
private Car car;
  • 写在方法上:
1
2
3
4
5
6
//spring容器创建当前对象,就会调用方法,完成赋值;
//方法使用的参数,自定义类型的值从ioc容器中获取,就是这里的参数car。
@Autowired
publlic void setCar(Car car){
this.car = car;
}
  • 写在构造器上:

因为注册到ioc容器的组件,容器启动的时候回调用无参构造器创建对象,然后在进行初始化赋值等操作。

1
2
3
4
5
6
//放在有参构造器上面,这样容器启动的时候就会调用这个有参构造器
//构造器中要用的组件car,也是从容器中获取
@Autowired
publlic Boss(Car car){
this.car = car;
}

如果当前类只有一个有参构造器,@Autowired是可以省略的。

  • 写在参数前面:
1
2
3
4
//car都是从容器中获取的
publlic void setCar(@Autowired Car car){
this.car = car;
}

6. Aware注入Spring底层组件及原理

自定义组件想使用spring容器底层的一些组件,比如applicationContext或者beanFactory等。只需要实现xxxAware接口即可。在创建对象的时候,会调用接口规定的方法注入相关组件。

比如ApplicationContextAware

1
2
3
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext var1) throws BeansException;
}

那么我们可以将它传进来的ApplicationContext保存一下:

1
2
3
4
5
6
7
8
9
public class Snail implements ApplicationContextAware{

private ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

7. @Profile环境搭建和根据环境注册bean

spring为我们提供的可用根据当前环境,动态地激活和切换一系列组件的功能。

开发环境、测试环境、生产环境,可能用不同的数据源,那么不想改动很多代码的话,就可以用@Profile切换。

@Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,在任何环境下都能注册这个组件

加了@Profile的@Bean,只有这个环境被激活的时候才能注册到容器中,但是有一个默认注册的:@Profile(“default”)

那么如何指定某个环境注册到spring容器中呢?

  • 第一种方式:使用命令行动态参数

VM arguments: -Dspring.profiles.active=test

  • 第二种方式:代码
1
2
3
4
5
6
7
//1,创建一个applicationContext
//2,设置需要激活的环境
applicationContext.getEnvironment().setActiveProfiles("test","dev");
//3,注册配置类
applicationContext.register(MainConfigOfProfile.class);
//4,启动刷新容器
applicationContext.refresh();

8. 总结

  1. @Value赋值
  2. @PropertySource加载外部配置文件
  3. @Autowired & @Qualifier & @Primary & @Resource & @Inject以及@Autowired在方法、构造器、参数位置的自动装配
  4. 通过实现Aware接口可以注入Spring底层的一些组件
  5. @Profile环境搭建和根据环境注册bean