【JavaEE】Spring框架学习

什么是Spring

是一个支持快速开发JavaEE应用程序的开源框架,同时在Spring Framework的基础上也诞生了 Spring Boot等等一系列项目。

IoC容器

容器:为某种特定组件的运行提供必要的软件环境支持。例如,Tomcat是一个Servlet容器,可以为Servlet的运行提供环境。

Spring的核心就是提供了一个IoC容器,可以用于管理所有轻量级的JavaBean组件,同时也提供了一些底层服务,例如组件的生命周期、配置和组装服务、AOP支持(面向切面编程,是OOP的补充和完善,在开发中主要用于解决一些系统层面上的问题,例如日志,事务、权限等),以及建立在AOP上的声明式事务服务等。

那么,IoC是如何对组件进行生命周期管理和配置组装服务呢。

IoC原理

IoC:Inversion of Control,直译为控制反转。

如果一个系统有大量的组件,其生命周期和相互之间的依赖关系如果由组件自身来维护,不但大大增加了系统的复杂度,而且会导致组件之间极为紧密的耦合,继而给测试和维护带来了极大的困难。

看看如下两段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class BookService {
private HikariConfig config = new HikariConfig();
private DataSource dataSource = new HikariDataSource(config);

public Book getBook(long bookId) {
try (Connection conn = dataSource.getConnection()) {
...
return book;
}
}
}

public class BookService {
private DataSource dataSource;

public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
}

在第二段代码中,我们不直接new一个DataSource,而是写了一个实例化dataSource的函数,这样,BookService不用再去关心如何创建 DataSource,而且这个dataSource由于是被注入到BookService中的,因此也可以与其他对象共享这个dataSource组件。

因此,IoC又被称为依赖注入,它将组件的创建+配置与组件的使用相分离,并且由IoC来管理组件的生命周期。

除了这种set()方法外,还可以通过构造方法注入,例如:

1
2
3
4
5
6
7
public class BookService {
private DataSource dataSource;

public BookService(DataSource dataSource) {
this.dataSource = dataSource;
}
}

IoC是一个无侵入容器,即应用程序的组件无需实现Spring的特定接口,或者说,组件根本不知道自己在Spring的容器中运行。

装配Bean

如何使用IoC容器、装配好的Bean如何使用。

编写一个特定的application.xml文件,来告诉Spring的IoC容器应该如何创建并组装Bean。

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="userService" class="com.itranswarp.learnjava.service.UserService">
<property name="mailService" ref="mailService" />
</bean>

<bean id="mailService" class="com.itranswarp.learnjava.service.MailService" />
</beans>
  • 每个bean都有一个id标识,相当于Bean的唯一ID
  • 在userService中,通过< property name=”…” ref=”…” />注入了另一个Bean
  • Bean的顺序不重要,Spring根据依赖关系会自动正确初始化

如果注入的不是bean,而是int、boolean这样的类型,则通过value注入,例如:

1
2
3
4
5
6
7
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="root" />
<property name="password" value="password" />
<property name="maximumPoolSize" value="10" />
<property name="autoCommit" value="true" />
</bean>

最后一步,需要创建一个Spring的IoC容器实例,然后加载配置文件,让Spring容器为我们创建并装配好配置文件中指定的所有Bean。

1
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

接下来,就可以从容器中取出装配好的Bean然后使用它。

1
2
3
4
// 获取Bean:
UserService userService = context.getBean(UserService.class);
// 正常调用:
User user = userService.login("bob@example.com", "password");

使用Annotation配置

每次增加一个组件,都要在配置文件中添加这个bean,很麻烦。

可以直接使用Annotation配置。

1
2
3
4
@Component
public class MailService {
...
}

这个Component就相当于定义了一个bean,它有一个可选的名称,默认是mailService,即小写字母开头的类名。

然后添加一个Autowired注释:

1
2
3
4
5
6
7
@Component
public class UserService {
@Autowired
MailService mailService;

...
}

这个注释就相当于将指定类型的bean注入到指定的字段中,这个注释可以写在set()方法上、字段上、构造方法中。

最后,编写一个AppConfig类启动容器:

1
2
3
4
5
6
7
8
9
10
@Configuration
@ComponentScan
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
User user = userService.login("bob@example.com", "password");
System.out.println(user.getName());
}
}

标注的ComponentScan,它告诉容器,自动搜索当前类所在的包以及子包,将所有标注为component的bean自动创建出来,并根据autowired进行装配。

Author: iwannaeat
Link: https://iwannaeat.github.io/2020/09/01/【javaEE】Spring框架学习/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.