Spring中的自动装配(三)

Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值。

一、@Autowired&@Qualifier&@Primary
  • 默认优先按照类型去容器中找对应的组件,找到就赋值;
  • 如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找;
  • 使用@Qualifier(“bookDao”)明确指定需要装配的组件id,而不是根据属性名进行装配;
  • 自动装配默认一定要将属性赋值好,没有找到组件就会报错,@Autowired(required=false),添加required=false之后,如果找不到相应的组件,则不会赋值,也不会报错;
  • @Primary,让Spring进行自动装配的时候,默认使用首选的bean进行装配,也可以使用@Qualifier指定装配的组件;
1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
@ComponentScan({"com.jt.bean.controller","com.jt.bean.dao","com.jt.bean.service"})
public class MainConfigOfAutowired {

@Primary
@Bean("bookDao2")
public BookDao bookDao(){
BookDao bookDao = new BookDao();
bookDao.setLabel("2");
return bookDao;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@Service
public class BookService {

@Qualifier("bookDao")
@Autowired(required=false)
private BookDao bookDao2;

@Override
public String toString() {
return "BookService [bookDao=" + bookDao2 + "]";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//组件默认的id是类名首字母小写,即bookDao
@Repository
public class BookDao {

private String label="1";

public String getLabel() {
return label;
}

public void setLabel(String label) {
this.label = label;
}

@Override
public String toString() {
return "BookDao [label=" + label + "]";
}
}
二、@Resource&@inject

Spring还支持使用@Resource(JSR250)和@Inject(JSR330),这两个注解都是Java规范的注解。

  • @Resource:可以和@Autowired一样实现自动装配功能,默认使用组件名称进行装配不支持@Primary功能和@Autowired(required=false)功能;
  • @inject:需要导入javax.inject包,和@Autowired的功能一样,没有required=false的功能;
1
2
3
   //@Resource(name="bookDao")
@Inject
private BookDao bookDao2;
三、方法、构造器位置的自动注解

@Autowired注解可以标注于构造器、参数、方法、属性等。不管怎么放置,都是从容器中获取。

  • 标注于方法位置;
1
2
3
4
5
6
7
8
   /**
* 标注在方法上时,Spring容器创建当前对象,就会调用方法,完成赋值
* 方法使用的参数,自定义类型的值从IOC容器中获取
* */
@Autowired
public void setCar(Car car) {
this.car = car;
}
  • 标注于构造器上:
    如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以从容器中获取。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//默认加载进IOC容器中的组件,容器会调用无参构造器创建对象,再进行初始化赋值等操作
@Component
public class Boss {


private Car car;

//需要获取的组件也是从容器中获取
@Autowired
public Boss(Car car){
this.car = car;
System.out.println("Boss...有参构造器...");
}
//...
}
  • 标注于参数上;
1
2
3
public void setCar(@Autowired Car car) {
this.car = car;
}

@Autowired标注于构造器和参数位置时,是可以省略的,他们都默认是从容器中获取实例对象。

四、把Spring底层组件注入到Bean中

自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx)时,自定义组件只要实现xxxAware即可,在创建对象的时候,会调用规定的方法注入相应的组件,把Spring底层的一些组件注入到自定义Bean中,每一个xxxAware,都有对应的xxxAwareProcessor后置处理器做增强操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Component
public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware{

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//这里就可以使用applicationContext容器
System.out.println("传入的ioc容器:"+applicationContext);
}

@Override
public void setBeanName(String name) {
//修改bean的id操作
System.out.println("当前bean的名字:"+name);
}

@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
//解析字符串
String stringValueResolver = resolver.resolveStringValue("helle:${os.name}"+"I am #{20*18}");
System.out.println("解析的字符串是:"+stringValueResolver);
}

}
五、@Profile

@Profile注解,是Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能。指定组件在哪种环境下才能被注册到容器中,不指定时,任何环境下都能注册这个组件。

以开发中的数据源为例:

  • 加了环境标识的bean,只有环境被激活的时候才能注册到容器中,默认是default环境。
  • 标注在配置类上时,只有环境被激活时,整个配置类中的配置才能生效。
  • 没有标注环境标识的bean,任何环境下都能加载。前提是整个配置类被加载的情况下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//@Profile("test")
@PropertySource("classpath:/dbconfig.propertis")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{

@Value("${db.user}")
private String user;

private StringValueResolver resolver;

private String driverClass;

@Profile("test")
@Bean
public DataSource dataSourceTest(@Value("${db.pwd}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setDriverClass(driverClass);
return dataSource;
}

@Profile("dev")
@Bean
public DataSource dataSourceDev(@Value("${db.pwd}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/dev");
dataSource.setDriverClass(driverClass);
return dataSource;
}

@Profile("prod")
@Bean
public DataSource dataSourceProd(@Value("${db.pwd}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/prod");
dataSource.setDriverClass(driverClass);
return dataSource;
}

@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.resolver = resolver;
this.driverClass = resolver.resolveStringValue("${db.driver}");

}
}

dbconfig.properties

1
2
3
db.user=root
db.pwd=root
db.driver=com.mysql.jdbc.Driver

使用方式:

  • 使用动态命令行参数:在虚拟机位置加载-Dspring.profiles.active=test。
  • 使用ApplicationContext的无参构造器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   //1、使用动态命令行参数:在虚拟机位置加载-Dspring.profiles.active=test
//2、使用ApplicationContext的无参构造器
@Test
public void test01(){
//2.1、使用ApplicationContext的无参构造器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//2.2、激活环境
applicationContext.getEnvironment().setActiveProfiles("test");
//2.3、注册配置类
applicationContext.register(MainConfigOfProfile.class);
//2.4、刷新容器
applicationContext.refresh();

String[] dataSources = applicationContext.getBeanNamesForType(DataSource.class);

for (String dataSource : dataSources) {
System.out.println(dataSource);
}
applicationContext.close();
}
-------------本文结束感谢您的阅读-------------