环己三烯的冬眠舱

天天网抑云,偶尔读点书。

0%

Spring IoC

什么是IoC

IoC全名为Inversion of Control,即控制反转。为了便于解释应用IoC带来的变化,我们先从一个没有使用IoC的例子开始说起。

在这个例子中有两个Class,一个是UserRepository,代表数据库访问层;另一个是UserService,代表服务层。在没有IoC时,代码应该这么写:

UserRepository:

为了方便(偷懒),就直接返回字符串了。

1
2
3
4
5
public class UserRepository {
public String getUser() {
return "{'id': 3200104203, 'name': 'Cyclohexatriene'}";
}
}

UserService:

1
2
3
4
5
6
7
8
9
10
11
public class UserService {
private UserRepository userRepository;

public UserService() {
this.userRepository = new UserRepository();
}

public String getUserInfo() {
return userRepository.getUser();
}
}

可以看到,在没有使用IoC的例子中,当UserService类需要依赖UserRepository类时,我们需要手动在UserService的构造函数里手动new一个UserRepository类的对象出来,然后保存在UserService里。

这就带来了一些问题:

  1. 以上只是一个简单的例子,但当依赖关系变得复杂的时候,由程序员手动进行管理会变得很麻烦。
  2. 在实际应用中,依赖于UserRepository的服务通常不会只有UserService一个。如果每个服务都给自己创建一个UserRepository对象的话就会存在浪费服务器和数据库资源的问题。

使用IoC容器就可以解决以上问题。程序员可以把对这些依赖关系的控制权交给IoC容器,让IoC容器来完成这些繁琐的任务。由于控制权由程序员交给了容器,所以才叫控制反转。从逻辑上,使用IoC后,UserService的代码是这样的:

1
2
3
4
5
6
7
8
9
10
11
public class UserService {
private UserRepository userRepository;

public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}

public String getUserInfo() {
return userRepository.getUser();
}
}

IoC容器会调用setUserRepository方法,从外部“注入”一个实例进来,而这个实例是如何创建和配置的就不用程序员来操心了,而且共享实例也变的非常简单。因此,IoC又叫依赖注入(Dependency Injection, DI)。

Spring的IoC

在Spring的IoC容器中,我们把所有组件统称为JavaBean。配置一个组件就是配置一个Bean。在默认情况下,Bean是一个单例,Spring会在容器初始化时创建Bean,容器关闭前销毁Bean。

由于要让Spring来管理这些Bean,我们必须告诉Spring这些Bean之间的依赖关系。常用的方法有XML方式配置和Annotation方式配置。由于Annotation方式比XML方式方便太多,笔者在实际工作中也只用过Annotation方式,所以本文只介绍Annotation方式。在这种情况下,代码应该这么写:

UserRepository:

1
2
3
4
5
6
7
@Component
public class UserRepository {
public String getUser() {
System.out.println("Running: UserRepository.getUser()");
return "{'id': 3200104203, 'name': 'Cyclohexatriene'}";
}
}

UserService:

1
2
3
4
5
6
7
8
9
10
@Component
public class UserService {
@Autowired
private UserRepository userRepository;

public String getUserInfo() {
System.out.println("Running: UserService.getUserInfo()");
return userRepository.getUser();
}
}

在上面代码中,我们使用了两个注解:@Component@Autowired

@Component就是告诉Spring,这个类是一个Bean,要把这个类交给Spring进行管理。我们可以使用@Component(value = "name")来指定名称,不指定的话默认就是小写字母开头的类名(如本例中就是userRepositoryuserService)。

@Autowired就是告诉Spring,这个地方的实例需要Spring去找一个已经定义好的Bean来注入进来。至于这个Bean怎么装配,就全是Spring的事情了。

除此之外,还可以使用配置类来定义一个Bean:

1
2
3
4
5
6
7
8
@Configuration
@ComponentScan
public class AppConfig {
@Bean
public UserRepository userRepository() {
return new UserRepository();
}
}

我们可以使用@Bean注解来修饰一个方法,意思就是告诉Spring需要调用这个方法来创建一个Bean。

好了,这些差不多够用了,还有些更加个性化的用法就放着先吧。


有的没的

🤓

无内鬼

没事听点歌(Rick Astley - Never Gonna Give You Up)