1.Spring概述

官方网站:https://spring.io

Spring是一个开源的轻量级Java开发框架,它由Rod Johnson创建。

它是为了解决企业应用开发的复杂性而创建的。

在Spring框架中,提出了两种重要的思想

  1. IOC(控制反转)
  2. AOP(面向切面编程)

Spring组成模块

2.IOC容器

2.1 程序中的硬编码

我们先来回顾一下我们之前的程序设计结构

1.程序结构实现

2.Action类

1
2
3
4
5
6
7
8
9
public class UserAction {

private UserService userService = new UserService();

public String login() {
User user = userService.login(new User());
return null;
}
}

3.Service类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class UserService {

private UserDAO userDAO = new UserDAO();

public User login(User user) {
try {
return userDAO.login(user);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

4.DAO类

1
2
3
4
5
6
7
public class UserDAO {

public User login(User user) {

return new User();
}
}

以上是我们之前常用的程序编写结构,从jsp到dao。基本可以看作上层依赖于下层。

但在层与层的依赖调用中,频繁出现硬编码

2.2 IOC概述与作用

Spring提出了一种思想:就是由spring来负责控制对象的生命周期和对象间的关系。所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转(IOC)。

IOC的作用其实就是通过接口降低程序中层与层的依赖关系

2.3 IOC环境搭建

IOC环境搭建预备条件

IOC的环境搭建有两种方式

  1. 基于XML的配置方式
  2. 基于注解的配置方式

那我们先以XML的配置方式作为示例

创建Maven项目,并在pom.xml添加Spring依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.max.spring</groupId>
<artifactId>spring-demo</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
</dependencies>
</project>

在resources目录下创建applicationContext.xml,并添加如下配置

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">

<!-- 讲对象的创建交由spring进行管理 -->
<bean id="userService" class="com.web.service.UserService" />

<bean id="userDao" class="com.web.dao.UserDao" />

</beans>

编写测试类

1
2
3
4
5
6
7
8
9
10
11
public class SpringTest {

public static void main(String[] args) {
//创建spring ioc容器,并加载xml文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取spring管理的对象
UserService userService = (UserService)context.getBean("userService");
//执行对象方法
userService.list();
}
}

2.4 ApplicationContext体系结构

顶层接口

image-20190603212528518

通过上图可以看到,ApplicationContext并不是一个顶层接口,在ApplicationContext接口之上还有一个非常重要的接口,就是BeanFactory接口

The BeanFactory

1
The BeanFactory API provides the underlying basis for Spring’s IoC functionality. Its specific contracts are mostly used in integration with other parts of Spring and related third-party frameworks.

翻译

1
BeanFactory API为Spring的IOC功能提供了基础。其主要用于与Spring和相关第三方框架的其他部分集成

The ApplicationContext

1
2
3
4
5
ApplicationContext is a sub-interface of BeanFactory. It adds:
1.Easier integration with Spring’s AOP features
2.Message resource handling (for use in internationalization)
3.Event publication
4.Application-layer specific contexts such as the WebApplicationContext for use in web applications.

翻译

1
2
3
4
5
applicationContext是BeanFactory的子接口,它补充了如下几点:
1.更容易与Spring的AOP功能集成
2.消息资源处理(用于国际化)
3.事件发布
4.应用层特定上下文,如用于Web应用程序的WebApplicationContext
1
In short, the BeanFactory provides the configuration framework and basic functionality, and the ApplicationContext adds more enterprise-specific functionality. The ApplicationContext is a complete superset of the BeanFactory and is used exclusively in this chapter in descriptions of Spring’s IoC container.

翻译

1
简而言之,BeanFactory提供了配置框架和基本功能,ApplicationContext添加了更多特定于企业的功能。applicationContext是BeanFactory的一个完整的超集

ApplicationContext接口实现类

image-20190604111643497

  • ClassPathXmlApplicationContext:从类路径下加载Spring配置文件
  • FileSystemXmlApplicationContext:从任何的文件路径加载Spring配置文件
  • AnnotationConfigApplicationContext 通过注解的方式配置Spring框架

3.Bean概述

3.1 Bean创建

通过Spring IOC管理的一个或多个Java对象,统称为Bean对象

创建Bean对象的三种方式

  • 构造函数(默认)
  • 静态工场方法
  • 实例工场方法

构造函数(默认)

1
2
3
4
5
6
7
8
9
10
<?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默认的创建方法 -->
<bean id="clientService" class="com.web.service.ClientService" />

</beans>

静态工场方法

1
2
3
4
5
6
7
8
9
10
<?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="clientService" class="com.web.service.ClientService" factory-method="createInstance" />

</beans>

实例工场方法

静态工场

1
2
3
4
5
6
7
8
public class StaticFactory {
private static ClientService clientService = new ClientService();

public ClientService createClientServiceInstance() {
return clientService;
}

}

xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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="staticFactory" class="com.web.factory.StaticFactory" />

<!-- 实例工场方法 -->
<bean id="clientService" factory-bean="staticFactory" factory-method="createClientServiceInstance" />

</beans>

3.2 Bean对象作用范围

Scope Description
singleton (默认)IOC容器创建Bean时,该Bean对象为单例对象
prototype IOC容器创建Bean时,每次会创建一个新的Bean对象
request 将单个Bean对象限定在http请求的生命周期中
session 将单个Bean对象限定在http session的生命周期中
application 将单个Bean对象限定在ServletContext的生命周期中
websocket 将单个Bean对象限定在WebSocket的生命周期中

代码演示说明

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
https://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="clientService" class="com.web.service.ClientService" scope="prototype" />

</beans>

3.3 依赖注入

几乎任何一个典型的企业应用程序,都不会存在只通过一个对象来完成某个业务功能

即使最简单的应用程序也需要多个对象进行协同工作,以完成对应的业务功能

也就是说对象之间会存在相互依赖的情况

在Spring IOC容器中,为了有效的对象与对象之间的依赖,提出了依赖注入(Dependency injection, DI)的概念

所谓依赖注入,即在IOC容器在启动运行时,由容器本身来完成对象与对象之间的依赖关系

依赖注入的三种配置方式

  • 基于构造函数的依赖注入
  • 基于setter方法的依赖注入
  • 基于注解的依赖注入

基于构造函数的依赖注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class UserService {

private UserDao userDao;

public UserService() {}

public UserService(UserDao userDao) {
this.userDao = userDao;
}

public void list() {
userDao.list();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
<?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.web.service.UserService">
<constructor-arg ref="userDao"/>
</bean>

<bean id="userDao" class="com.web.dao.UserDao"/>

</beans>

基于setter方法的依赖注入

1
2
3
4
5
6
7
8
9
10
11
12
public class UserService {

private UserDao userDao;

public void list() {
userDao.list();
}

public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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.web.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>

<bean id="userDao" class="com.web.dao.UserDao"/>

</beans>

3.4 生命周期

对于Spring IOC容器管理的Bean对象,它们也存在一定的生命周期,每个Bean都分别具有init(初始化)和destory(销毁)的阶段

单例Bean对象

1
2
3
4
5
6
7
8
9
10
11
public class UserService {

public void init() {
System.out.println("bean init....");
}


public void destory() {
System.out.println("bean destory....");
}
}
1
2
3
4
5
6
7
8
9
10
<?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.web.service.UserService" scope="singleton" init-method="init" destroy-method="destory"/>

</beans>

测试类

1
2
3
4
5
6
7
8
9
10
11
public class UserServiceTest {

public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("context init...");
UserService userService = (UserService)context.getBean("userService");
System.out.println(userService);

context.close();
}
}

输出结果

1
2
3
4
bean init....
context init...
com.web.service.UserService@6d4b1c02
bean destory....

通过输出结果可以看出,单例的bean对象,在容器创建时,就会调用初始化方法,在容器关闭时调用销毁方法

多例Bean对象

将单例配置改为多例

1
2
3
4
5
6
7
8
9
10
<?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.web.service.UserService" scope="prototype" init-method="init" destroy-method="destory"/>

</beans>

输出结果

1
2
3
context init...
bean init....
com.web.service.UserService@3bfdc050

通过输出结果可以看出,多例Bean对象只有调用时才会进行初始化,而只有当对象长时间不用或没有其他引用时,才会被JVM回收

4.Spring常用注解

4.1 基于注解的IOC配置

Spring中的常用注解,按照功能可以分为如下几类

  • 创建Bean对象

    ​ @Component

    ​ @Controller

    ​ @Service

    ​ @Repository

  • 属性依赖注入

    ​ @Autowired

  • Bean的作用范围

    ​ @Scope

  • Bean的生命周期

    ​ @PostConstruct

    ​ @PreDestroy

@Component

@Component注解相当于xml配置的标签,通过注解的value属性可以配置bean的id,value默认可以不写

,如果不配置value属性,bean的id默认与类名相同,但首字母小写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Component("userService")
public class UserService {

public void init() {
System.out.println("bean init....");
}

public void list() {
System.out.println("userService list...");
}


public void destory() {
System.out.println("bean destory....");
}
}

配置注解扫描器

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

<!-- 配置注解注解扫描器 -->
<context:component-scan base-package="com.web" />

</beans>

编写测试类

1
2
3
4
5
6
7
8
9
10
public class UserServiceTest {

public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService)context.getBean("userService");
System.out.println(userService);

context.close();
}
}

@Autowired

@Autowired注解类似于标签中的,主要是用于属性注入,该注解可以直接标准在属性上,无需setter方法

@Autowired注解默认根据类型进行配置,如果存在多个相同类型,则根据bean的id进行匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class UserService {

@Autowired
private UserDao userDao;

public void init() {
System.out.println("bean init....");
}

public void list() {
userDao.list();
}


public void destory() {
System.out.println("bean destory....");
}
}

如果存在多个相同类型,但bean的id不匹配,则可以配合@Qualifier注解来注入指定id的同类型的bean

注意,@Qualifier不能单独使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Component
public class UserService {

@Qualifier("userDao1")
@Autowired
private UserDao userDao;

public void init() {
System.out.println("bean init....");
}

public void list() {
userDao.list();
}


public void destory() {
System.out.println("bean destory....");
}
}

为了简化@Autowired+@Qualifier的组合使用,我们可以通过@Resource注解进行替代,唯一的不同是需要通过

@Resource注解中的name属性来指定要注入的bean的id

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component
public class UserService {

@Resource(name = "userDao1")
private UserDao userDao;

public void init() {
System.out.println("bean init....");
}

public void list() {
userDao.list();
}


public void destory() {
System.out.println("bean destory....");
}
}

@Scope

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Component
@Scope("singleton")
public class UserService {

@Resource(name = "userDao1")
private UserDao userDao;

public void init() {
System.out.println("bean init....");
}

public void list() {
userDao.list();
}


public void destory() {
System.out.println("bean destory....");
}
}

@PostConstruct与@PreDestroy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Component
@Scope("singleton")
public class UserService {

@Resource(name = "userDao1")
private UserDao userDao;

@PostConstruct
public void init() {
System.out.println("bean init....");
}

public void list() {
userDao.list();
}

@PreDestroy
public void destory() {
System.out.println("bean destory....");
}
}

4.2 Spring中的新注解

前面,我们已经学习了Spring IOC容器的基本配置,但在某些情况下,随便项目模块的不断增多,xml中的配置会越来越多,这可能会造成”xml泛滥

为了解决上述问题,Spring提供了新的注解,通过类的配置方式来替代xml配置方式

常用的新注解如下

  • @Configuration
  • @ComponentScan
  • @Bean
  • @Import
  • @PropertySource

@Configuration

@Configuration注解用于标注一个类是一个配置类,等价与spring的xml配置文件

1
2
3
@Configuration
public class SpringConfiguration {
}

@ComponentScan

该注解等同于xml中的<context:component-scan />标签

1
2
3
4
@Configuration
@ComponentScan(basePackages = "com.web")
public class SpringConfiguration {
}

@Bean

@Bean通常用于标注某个方法,将方法的返回的对象注入到IOC容器中

如下列配置

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


<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/baidu_cloud"/>
<property name="user" value="root" />
<property name="password" value="111111"/>
</bean>

</beans>

@Bean替换xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
@ComponentScan(basePackages = "com.web")
public class SpringConfiguration {

@Bean(name = "dataSource")
public DataSource createDataSource() {
ComboPooledDataSource ds = new ComboPooledDataSource();
try {
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/baidu_cloud");
ds.setUser("root");
ds.setPassword("111111");

return ds;
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
}
}

编写注解测试类

1
2
3
4
5
6
7
8
public class AnnotationTest {

public static void main(String[] args) throws SQLException {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
ComboPooledDataSource dataSource = (ComboPooledDataSource)context.getBean("dataSource");
System.out.println(dataSource.getConnection());
}
}

@Import

该注解用于导入其他标注有@Configuration注解的类

JdbcConfig配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
public class JdbcConfig {

@Bean(name = "dataSource")
public DataSource createDataSource() {
ComboPooledDataSource ds = new ComboPooledDataSource();
try {
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/baidu_cloud");
ds.setUser("root");
ds.setPassword("111111");

return ds;
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
}
}

SpringConfiguration配置类

1
2
3
4
5
@Import(JdbcConfig.class)
@Configuration
@ComponentScan(basePackages = "com.web")
public class SpringConfiguration {
}

@PropertySource

该注解主要用于加载外部properties文件

jdbc.properties

1
2
3
4
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/baidu_cloud
jdbc.user=root
jdbc.password=111111

JdbcConfig

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
@Configuration
public class JdbcConfig {

@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.user}")
private String user;
@Value("${jdbc.password}")
private String password;

@Bean(name = "dataSource")
public DataSource createDataSource() {
ComboPooledDataSource ds = new ComboPooledDataSource();
try {
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(user);
ds.setPassword(password);

return ds;
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
}
}

SpringConfiguration

1
2
3
4
5
6
@Import(JdbcConfig.class)
@Configuration
@ComponentScan(basePackages = "com.web")
@PropertySource("classpath:jdbc.properties")
public class SpringConfiguration {
}

4.3 Spring测试注解

Spring框架中,也设计了Junit测试相关注解,方便在执行测试方法时,自动进行IOC容器的创建

  1. 导入spring测试jar文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.1.7.RELEASE</version>
    </dependency>

    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    </dependency>
  2. 编写测试类

  3. ```java
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {SpringConfiguration.class})
    public class SpringTest {

    @Autowired
    private DataSource dataSource;
    
    @Test
    public void testDataSource() throws SQLException {
        System.out.println(dataSource.getConnection());
    }
    

    }

    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

    # 5.面向切面编程(AOP)

    ## 5.1 AOP概述

    AOP(Aspect Oriented Programming),面向切面编程

    AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容

    AOP就是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术

    AOP通常可以实现日志记录,性能统计,安全控制,事务处理,异常处理等功能

    AOP的实现方式

    1. JDK动态代理
    2. Cglib

    AOP相关概念和术语

    - Join point:连接点,在spring中指的是被拦截的点

    - Pointcut:切入点,指对Join point进行拦截的定义

    - Advice

    ​ 通知,指拦截到Join point后要执行的操作

    ​ 通知类型:前置通知、后置通知、异常通知、最终通知、环绕通知

    ## 5.2 基于xml的AOP配置

    导入相关jar文件

    ```java
    <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.13</version>
    </dependency>

创建Logger类

1
2
3
4
5
6
7
8
9
10
public class Logger {

public void startRecord() {
System.out.println("start record log...");
}

public void endRecord() {
System.out.println("end record log...");
}
}

aop配置

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">

<bean id="userService" class="com.web.service.UserService" />

<bean id="logger" class="com.web.util.Logger" />

<!-- aop配置 -->
<aop:config>
<!-- 切面配置 -->
<aop:aspect ref="logger">
<!-- 切入点配置 -->
<aop:pointcut id="logAdvice" expression="execution(* com.web.service.*.*(..))" />
<!-- 前置通知 -->
<aop:before method="startRecord" pointcut-ref="logAdvice" />
<aop:after method="endRecord" pointcut-ref="logAdvice" />
</aop:aspect>
</aop:config>
</beans>

编写测试类

1
2
3
4
5
6
7
8
9
public class UserServiceTest {

public static void main(String[] args) throws SQLException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService)context.getBean("userService");
userService.list();
context.close();
}
}

输出结果

1
2
3
start record log...
user service list...
end record log...

5.3 基于注解的AOP配置

开启注解扫描与aop注解支持

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

<!-- 注解扫描器 -->
<context:component-scan base-package="com.web" />

<!-- 开启aop注解支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

添加切面类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Aspect
@Component("logger")
public class Logger {

@Pointcut("execution(* com.web.service.*.*(..))")
public void pc(){}

@Before("pc()")
public void startRecord() {
System.out.println("start record log...");
}

@After("pc()")
public void endRecord() {
System.out.println("end record log...");
}
}

编写测试类

1
2
3
4
5
6
7
public class AOPAnnotationTest {

public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService)context.getBean("userService");
userService.list();
}

输出结果

1
2
3
start record log...
user service list...
end record log...

5.4 事务控制

在日常的项目开发中,事务控制是非常只要的一环,也是我们经常接触的一块,但对于事务的开启、提交、回滚却需要重复编写,那么我们可以通过aop的理念,将事务控制进行公共抽离

基于xml的事务控制

添加依赖

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>

xml配置

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">

<bean id="userService" class="com.web.service.UserService"/>

<!-- 数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/baidu_cloud"/>
<property name="user" value="root"/>
<property name="password" value="111111"/>
</bean>

<!-- 事务管理 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 事务通知 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

<!-- 事务aop配置 -->
<aop:config>
<aop:pointcut id="userServicePointCut" expression="execution(* com.web.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="userServicePointCut"/>
</aop:config>

</beans>

事务属性配置

  • isolation:指定事务的隔离级别,默认是DEFAULT,表示使用数据库的默认隔离级别
  • propagation:指定事务的传播性,默认是REQUIRED,表示需要使用事务,查询选择SUPPORTS
  • read-only:指定事务是否只读,只有查询方法才设置为true
  • timeout:指定事务的超时时间
  • rollback-for:指定一个异常,当发生该异常时,则事务回滚
  • no-rollback-for:指定一个异常,当发生该异常时,事务不会滚,其他异常回滚

基于注解的事务控制

xml配置

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">

<!-- 开启注解扫描器 -->
<context:component-scan base-package="com.web" />

<!-- 数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/baidu_cloud"/>
<property name="user" value="root"/>
<property name="password" value="111111"/>
</bean>

<!-- 事务管理 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 开启事务注解支持 -->
<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>

</beans>

类事务配置

1
2
3
4
5
6
7
8
9
@Service
@Transactional(readOnly = true)
public class UserService {

@Transactional
public void list() {
System.out.println("user service list...");
}
}

全注解的事务控制

JdbcConfig

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
public class JdbcConfig {

@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.user}")
private String user;
@Value("${jdbc.password}")
private String password;

@Bean(name = "dataSource")
public DataSource createDataSource() {
ComboPooledDataSource ds = new ComboPooledDataSource();
try {
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(user);
ds.setPassword(password);

return ds;
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
}
}

TransactionConfig

1
2
3
4
5
6
7
public class TransactionConfig {

@Bean(name = "transactionManager")
public PlatformTransactionManager createTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}

SpringConfiguration

1
2
3
4
5
6
7
8
@Configuration
@Import({JdbcConfig.class, TransactionConfig.class})
@ComponentScan(basePackages = "com.web")
@PropertySource("classpath:jdbc.properties")
@EnableTransactionManagement
public class SpringConfiguration {

}

5.Spring JdbcTemplate

5.1 概述

Spring JdbcTemplate是Spring中经典且最受欢迎的Jdbc框架,它是对jdbc底层基本功能的封装,实现对表的CRUD操作

代码演示说明

依赖管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>

编写测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class JdbcTest {

public static void main(String[] args) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/baidu_cloud");
dataSource.setUsername("root");
dataSource.setPassword("111111");

JdbcTemplate jt = new JdbcTemplate(dataSource);
int count = jt.queryForObject("select count(*) from t_file", Integer.class);
System.out.println("count: " + count);
}
}

5.2 JdbcTemplate CRUD

查询

查询总条数

1
int count = jt.queryForObject("select count(*) from t_file", Integer.class);

条件查询

1
int count = jt.queryForObject("select count(*) from t_file where id > ?", Integer.class, 3);
1
String fileName = jt.queryForObject("select file_name from t_file where id=?", String.class, 1);

查询所有

1
2
3
4
5
6
7
8
9
10
11
List<User> list = jt.query("select id, user_account, user_password from t_user", new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int i) throws SQLException {
User user = new User();
user.setId(rs.getInt("id"));
user.setUserAccount(rs.getString("user_account"));
user.setUserPassword(rs.getString("user_password"));

return user;
}
});

新增

1
int count = jt.update("insert into t_user(user_account, user_password, user_email, user_phone) values (?,?,?,?)","admin", "123456", "test@qq.com", "123213211");

更新

1
int count = jt.update("update t_user set user_password=? where id=?", "111111", 1);

删除

1
int count = jt.update("delete from t_user");