• 控制反转 Inversion of Control

  • Spring中每一个需要管理的对象称为Spring Bean(简称Bean),而Spring管理这些Bean的容器,我们称之为Spring IOC容器。

  • IOC容器两个基本功能:管理Bean;完成Bean之间的依赖关系。

  • 所有的IOC容器都需要实现BeanFactory接口(顶级接口),因其功能不够强大,还涉及了其子接口即ApplicationContext接口。现实中大部分IOC容器是ApplicationContext接口的实现类,即基于注解的IOC容器,AnnotationConfigApplicationContext

  • 装配Bean

    1、一个个装配,麻烦

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
/*POJO*/
public class User {
private Long id;
private String useName;
private String note;
/*setter and getter*/
}

@Configuration //表示这是Java配置文件,Spring根据它去装配Bean
public class AppConfig {
@Bean(name = "user") //@Bean代表将initUser方法返回的POJO装配到IOC容器中
public User initUser() {
User user = new User();
user.setId(1L);
user.setUserName("user_name_1");
user.setNote("note_1");
return user;
}
}

public class ApplicationDemo {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
User user = ctx.getBean(User.class); //于是可以使用getBean获取对应POJO
}
}

2、通过扫描

使用@Component,@ComponentScan。前者标明哪个类被扫描进IOC容器,后者标明扫描策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Component("user")	//@Service也实现了@Component的功能,也会被扫描到IOC容器中
public class User {
@Value("1")
private Long id;
@Value("user_name_1")
private String userName;
@Value("note_1")
private String note;
/*setter and getter*/
}

@Configuration
@ComponentScan //但是只会扫描AppConfig所在包和其子包 可实现过滤等策略
//@SpringBootApplication也实现了@ComponentScan功能
public class AppConfig {

}
  • 将第三方包的类对象也放到IOC容器中
1
2
3
4
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
1
2
3
4
5
6
7
@Bean(name = "dataSource")
public DataSource getDataSource() {
Properties props = new Properties();
props.setProperty("driver", "com.mysql.jdbc.Driver");
/*...*/
return dataSource;
}
  • 依赖注入DI
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
public interface Person {
public void service();
public void setAnimal(Animal animal);
}

public interface Animal {
public void use();
}

@Component
public class Dog implements Animal {
@Override
public void use() {
System.out.println("看门");
}
}

@Component
public class BusinessPersion implements Persion {

@Autowired
private Animal animal = null; //默认为null,注入后为Dog

@Override
public void service() {
this.animal.use();
}

// 除自动注入外,你也可手动重新指定别的Animal
@Override
public void setAnimal(Animal animal) {
this.animal = animal;
}
}

@Autowired会根据类型(by type)找到对应的Bean进行注入,这里匹配到狗,所以Spring IOC将狗的实例注入到BusinessPersion中。

但如果存在相同类型,比如还存在一个猫,这时无法唯一匹配,会抛异常。解决方案是优先注入或者新增名称匹配。

1
2
3
4
5
6
7
8
9
@Component
@Primary // 优先注入
public class Cat implements Animal {
// ...
}

@Autowired
@Qualifier("dog") // 同时根据名称匹配
private Animal animal = null;

@Autowired也可以用于标注方法

  • 另外,有关@Bean何时销毁,延时初始化和依赖注入(只将Bean的定义发布到IOC容器而不做实例化和依赖注入,取出时再做,通过配置@ComponentScan的lazyInit来实现),条件装配Bean,XML装配Bean,待后续整理。。。