一、Spring简介

Spring是一款开源的轻量级Java框架,旨在提高开发人员的开发效率以及系统的可维护性。

Spring Framework主要包括几个模块,以5.x为例,如图:

1

Spring 各个模块的依赖关系如下:

1

Core Container

Spring 框架的核心模块,也可以说是基础模块,主要提供 IoC 依赖注入功能的支持。Spring 其他所有的功能基本都需要依赖于该模块。

  • spring-core:Spring 框架基本的核心工具类。
  • spring-beans:提供对 bean 的创建、配置和管理等功能的支持。
  • spring-context:提供对国际化、事件传播、资源加载等功能的支持。
  • spring-expression:提供对表达式语言(Spring Expression Language) SpEL 的支持,只依赖于 core 模块,不依赖于其他模块,可以单独使用

AOP、Aspects、Instrumentation、Messaging

  • spring-aop:提供了面向切面的编程实现。
  • spring-aspects:该模块为与 AspectJ 的集成提供支持,是一个功能强大且成熟的面向切面编程(AOP)框架。
  • spring-instrument:提供了为 JVM 添加代理(agent)的功能。 具体来讲,它为 Tomcat 提供了一个织入代理,能够为Tomcat传递类文件,就像这些文件是被类加载器加载一样。
  • spring-messaging:Spring 4.0 以后新增了消息(Spring-messaging)模块,该模块提供了对消息传递体系结构和协议的支持。

Data Access/Integration

  • spring-jdbc:提供了对数据库访问的抽象 JDBC。不同的数据库都有自己独立的 API 用于操作数据库,而 Java 程序只需要和 JDBC API 交互,这样就屏蔽了数据库的影响。
  • spring-Transactions:提供对事务的支持。
  • spring-orm:提供对 Hibernate、JPA、iBatis 等 ORM 框架的支持。
  • spring-oxm:提供一个抽象层支撑 OXM(Object-to-XML-Mapping),例如:JAXB、Castor、XMLBeans、JiBX 和 XStream 等。
  • spring-jms : 提供一套 “消息生产者、消息消费者”模板用于更加简单的使用 JMS,JMS 用于用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。

Spring Web

  • spring-web:对 Web 功能的实现提供一些最基础的支持。

  • spring-webmvc:提供对 Spring MVC 的实现。

  • spring-websocket:提供了对 WebSocket 的支持,WebSocket 可以让客户端和服务端进行双向通信。

  • spring-webflux:提供对 WebFlux 的支持。WebFlux 是 Spring Framework 5.0 中引入的新的响应式框架。与 Spring MVC 不同,它不需要 Servlet API,是完全异步。

Messaging

spring-messaging 是从 Spring4.0 开始新加入的一个模块,主要职责是为 Spring 框架集成一些基础的报文传送应用。

Spring Test

Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。

Spring Bean

Spring bean 代指那些被IOC(控制反转)容器所管理的对象。

声明bean的方式

xml 配置

顾名思义,就是将bean的信息配置.xml文件里,通过Spring加载文件为我们创建bean。这种方式出现很多早前的SSM项目中,将第三方类库或者一些配置工具类都以这种方式进行配置,主要原因是由于第三方类不支持Spring注解。

1
2
3
4
5
6
7
8
9
<?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
 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- services -->
    <bean id="userService" class="tech.pdai.springframework.service.UserServiceImpl">
    </bean>
</beans>

Java 配置

将类的创建交给我们配置的JavcConfig类来完成,Spring只负责维护和管理,采用纯Java创建方式。其本质上就是把在XML上的配置声明转移到Java配置类中

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@Configuration
public class BeansConfig {
    /**
     * @return user service
     */
    @Bean("userService")
    public UserServiceImpl userService() {
        UserServiceImpl userService = new UserServiceImpl();
        return userService;
    }
}

注解配置

通过@Controller、@Service、@Repository、@Component注解将bean交给IOC容器管理

  • @Component:通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。
  • @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
  • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
  • @Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面
1
2
3
@Service
public class UserServiceImpl {
}

@Component和@Bean的区别

  • @Component 注解作用于类,而@Bean注解作用于方法。
  • @Component通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了 Spring 这是某个类的实例,当我需要用它的时候还给我。
  • @Bean 注解比 @Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册 bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。

注入bean的方式

在Spring中我们需要使用申明的bean,首先就是要将bean注入到需要使用的地方,注入的方式主要有接口注入属性注入构造函数注入java配置XML配置注解注入,实际开发中主要以注解注入为主。

注入bean的注解主要有:@Autowired@Resource@Inject

@Autowired

@Autowired属于Spring内置的注解,默认的注入方式为byType(根据类型进行匹配),如果一个接口有多个实现,这时候注入方式会变为 byName(根据名称进行匹配),但建议这种情况下使用@Qualifier 注解来显式指定名称而不是依赖变量的名称。

  • 假设IUserService有两个实现类分别是UserServiceImpl1UserServiceImpl2
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 报错,byName 和 byType 都无法匹配到 bean
@Autowired
private IUserService userService;

// 正确注入 UserServiceImpl1对象对应的 bean
@Autowired
private IUserService userServiceImpl1;

// 正确注入  UserServiceImpl2 对象对应的 bean
// userServiceImpl2 就是我们上面所说的名称
@Autowired
@Qualifier(value = "userServiceImpl2")
private IUserService smsService;

@Resource

@Resource属于JDK(JSR250)提供的注解,默认注入方式为 byName(根据名称进行匹配)。如果无法通过名称匹配到对应的 Bean 的话,注入方式会变为byType(根据类型进行匹配)。

如果指定 name 属性则注入方式为byName,如果指定type属性则注入方式为byType,如果同时指定nametype属性(不建议)则注入方式为byType+byName

  • 仍以IUserService有两个实现类UserServiceImpl1UserServiceImpl2为例。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 报错,byName 和 byType 都无法匹配到 bean
@Resource
privat IUserService userServiceImpl;

// 正确注入 UserServiceImpl1 对象对应的 bean
@Resource
private IUserService userServiceImpl1;

// 正确注入 userServiceImpl2对象对应的 bean(比较推荐这种方式)
@Resource(name = "userServiceImpl2")
private IUserService userServiceImpl;

@Inject

@Inject属于JDK(JSR330)提供的注解,默认的注入方式为byType(根据类型进行匹配),如果需要 byName(根据名称进行匹配)方式进行匹配需要配合@Named一起使用

  • 仍以IUserService有两个实现类UserServiceImpl1UserServiceImpl2为例。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 报错,byName 和 byType 都无法匹配到 bean
@Inject
private IUserService userService;

// 正确注入 UserServiceImpl1对象对应的 bean
@Inject
private IUserService userServiceImpl1;

// 正确注入  UserServiceImpl2 对象对应的 bean
@Inject
@Named("userServiceImpl2")
private IUserService smsService;

总结

1、@Autowired是Spring自带的,@Resource是JSR250规范实现的,@Inject是JSR330规范实现的

2、@Autowired、@Inject用法基本一样,不同的是@Inject没有required属性

3、@Autowired、@Inject是默认按照类型匹配的,@Resource是按照名称匹配的

4、@Autowired如果需要按照名称匹配需要和@Qualifier一起使用,@Inject和@Named一起使用,@Resource则通过name进行指定