主要内容
Spring 简介
SpringIOC 容器
DI 依赖注入
Spring 整合持久层技术
代理模式
AOP 编程
Spring 事务管理
Spring 基于注解装配 Bean 对象
Junit 的使用
Spring 整合 Junit
Spring 整合 Servlet
Spring 知识点梳理

一、 Spring 简介

在这里插入图片描述

1 Spring介绍

Spring是一个开源框架,最早由Rod Johnson 发起。Spring 为简化企业级开发而生,使 用 Spring 开发可以将 Bean 对象交给 Spring 容器来管理,这样使得很多复杂的代码在 Spring 中开发会变得非常的优雅和简洁,有效的降低代码的耦合度,极大的方便项目的后期维护、 升级和扩展。

2 Spring的时钟关键策略

  • 基于POJO的轻量级和最小侵入性编程;
  • 通过依赖注入和面向接口实现松耦合;
  • 基于切面和惯例进行上了个名师编程;
  • 通过切面和模板减少样板式代码;

3 Spring特点

  • 非侵入式:基于Spring开发的应用中对象可以不依赖Spring的API。
  • 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期。
  • 控制反转:IOC (Inversion of Control),指的是将对象的创建权交给 Spring 去创建。 使用 Spring 之前,对象的创建都是由我们自己在代码中 new 创建。而使用 Spring 之后。对象的创建都是由给了 Spring 框架。
  • 依赖注入:DI (Dependency Injection),是指依赖的对象不需要手动调用 setXX 方法 去设置,而是通过配置赋值。
  • 面向切面编程:Aspect Oriented Programming——AOP。
  • 组件化:Spring 实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中 可以使用 XML 和 Java 注解组合这些对象。
  • 一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三 方类库。
    在这里插入图片描述
    Spring 官网地址: https://spring.io/

4 Spring 体系结构

Spring 框架采用分层架构,根据不同的功能被划分成了多个模块,这些模块可根据作 用分为 Data Access/Integration、Web、AOP、Aspects、Messaging、Instrumentation、Core Container 和 Test。
在这里插入图片描述
Spring 框架的这些模块可以满足一切企业级应用开发的需求,在开发过程中可以根据 需求有选择性地使用所需要的模块。

4.1Data Access/Integration(数据访问/集成)

数据访问/集成层包括 JDBC、ORM、OXM、JMS 和 Transactions 模块,具体介绍如下。

  • JDBC 模块:提供了一个 JDBC 的抽象层,大幅度减少了在开发过程中对数据库操 作的编码。
  • ORM 模块:对流行的对象关系映射 API,包括 JPA、JDO、Hibernate 和 MyBatis 提 供了的集成。
  • OXM 模块:提供了一个支持对象/XML 映射的抽象层实现。
  • JMS 模块:指 Java 消息服务,包含的消息生产和消费的处理。
  • Transactions 事务模块:支持编程和声明式事务处理。

4.2Web

Spring 的 Web 层由 spring-web、spring-webmvc、spring-websocket 和 spring-webflux 组成,具体介绍如下。

  • Spring-web 模块:提供了基本的 Web 开发集成特性,例如多文件上传功能、使用 的 Servlet 监听器的 IoC 容器初始化以及 Web 应用上下文。
  • Spring-webmvc模块:也称为Web-Servlet模块,包含用于web应用程序的Spring MVC 和 REST Web Services 实现。Spring MVC 框架提供了领域模型代码和 Web 表单之间 的清晰分离,并与 Spring Framework 的所有其他功能集成。
  • Spring-websocket 模块:Spring4.0 以后新增的模块,它提供了 WebSocket 和 SocketJS 的实现。
  • Spring-webflux 模块:是一个新的非堵塞函数式 Reactive Web 框架, 可以用来建 立异步的, 非阻塞,事件驱动的服务, 并且扩展性非常好。

4.3Core Container(核心容器)

Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上 下文模块和 Expression Language 表达式语言模块组成,具体介绍如下。

  • Beans 模块:提供了 BeanFactory,是工厂模式的经典实现,Spring 将管理对象称 为 Bean。
  • Core 核心模块:提供了 Spring 框架的基本组成部分,包括 IoC 和 DI 功能。
  • Context 上下文模块:建立在核心和 Beans 模块的基础之上,它是访问定义和配 置任何对象的媒介。ApplicationContext 接口是上下文模块的焦点。
  • Expression Language 模块:是运行时查询和操作对象图的强大的表达式语言。是对 JSP2.1 规范中规定的统一表达式语言(Unified EL)的扩展。

4.4其他模块

Spring 的其他模块还有 AOP、Aspects、Instrumentation 以及 Test 模块,具体介绍如下。

  • AOP 模块:提供了面向切面编程实现,允许定义方法拦截器和切入点,将代码按 照功能进行分离,以降低耦合性。
  • Aspects 模块:提供与 AspectJ 的集成,是一个功能强大且成熟的面向切面编程 (AOP)框架。
  • Instrumentation 模块:提供了类工具的支持和类加载器的实现,可以在特定的应 用服务器中使用。
  • Test 模块:支持 Spring 组件,使用 JUnit 或 TestNG 框架的测试。

5 Spring 的 jar 包下载与介绍

5.1下载地址:

https://repo.spring.io/simple/libs-release-local/org/springframew ork/spring/
-dist后缀表示该文件夹下存放的是 jar 包,文档和 xsd 文件;
-docs 后缀表示该文件夹下存放相关文档,开发指南和 API;
-schema 里存放了 Spring 所用的 xsd 文件。

libs 目录文件说明:
.RELEASE.jar: 开发时需要引用的 jar
.RELEASE-javadoc.jar: 文档
.RELEASE-sources.jar: 源码

5.2jar 包介绍

在这里插入图片描述
在这里插入图片描述

二、 Spring IOC 容器

1 Spring IOC 容器介绍

1.1 IOC 思想

IOC (Inversion of Control) 是指在程序开发中,对象实例的创建不再由调用者管理,而是 由 Spring 容器创建。Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制, 因此,控制权由程序代码转移到了 Spring 容器中,控制权发生了反转,这就是 Spring 的IOC 思想。

1.2 IOC 容器概念

IOC 容器就是具有依赖注入功能的容器,IOC 容器负责实例化、定位、配置应用程序中 的对象及建立这些对象间的依赖。应用程序无需直接在代码中 new 相关的对象,应用程序 由 IOC 容器进行组装。在 Spring 中 BeanFactory 是 IOC 容器的实际代表者。

1.3Bean 的概念

在 Spring 中,被 Spring 容器所管理的对象称之为”Bean”对象。一个 Spring 的 Bean 对象 可以是任何形式的 POJO。

2 Spring IOC 容器类型

Spring 提供了两种 IoC 容器,分别为 BeanFactory 和 ApplicationContext。

2.1BeanFactory

BeanFactory 是基础类型的 IoC 容器。
它由 org.springframework.beans.facytory.BeanFactory接口定义,并提供了完整的 IoC 服务支持。简单来说,BeanFactory 就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。

2.2ApplicationContext

ApplicationContext 是 BeanFactory 的子接口,也被称为应用上下文。该接口的全路径 为org.springframework.context.ApplicationContext,它不仅提供了 BeanFactory 的所有功能, 还添加了对国际化、资源访问、事件传播等方面的良好支持。

ApplicationContext 接口有两个常用的实现类:

2.2.1 ClassPathXmlApplicationContext

该 类 从 类 路 径 ClassPath 中 寻 找 指 定 的 XML 配 置 文 件 , 找 到 并 装 载 完 成 ApplicationContext 的实例化工作。

ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);

FileconfigLocation 参数用于指定 Spring 配置文件的名称和位置。

2.2.2 SystemXmlApplicationContext

该类从指定的文件系统路径中寻找指定的 XML 配置文件,找到并装载完成 ApplicationContext 的实例化工作。

ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation)

它与 ClassPathXmlApplicationContext的区别是:在读取 Spring 的配置文件时, FileSystemXmlApplicationContext不再从类路径中读取配置文件,而是通过参数指定配置文 件的位置,它可以获取类路径之外的资源,如“F:/workspaces/applicationContext.xml”;

3 Spring IOC 容器的使用

3.1搭建环境

3.1.1 创建项目

在这里插入图片描述

3.1.2 添加 jar 包

在这里插入图片描述

3.1.3 添加 Spring 配置文件
<?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">

</beans>

3.2通过 IOC 容器管理 Bean 对象

3.2.1 创建 UsersService 接口与实现类
package com.bjsxt.service;

public interface UsersService {
    void addUsers();
}
public class UsersServiceImpl implements UsersService {
	 @Override 
	 public void addUsers() { 
	 	System.out.println("UsersService addUsers ......"); 
	 } 
 }
3.2.2 修改配置文件
<?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">
	<bean id="usersService" class="com.bjsxt.service.impl.UsersServiceImpl"/>
</beans>
3.2.3 获取 IOC 容器中的对象
package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UsersServiceTest {
    public static void main(String[] args) {
       /* UsersService usersService = new UsersServiceImpl();
        usersService.addUsers();*/
       //启动Spring IOC容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从IOC容器中获取
       UsersService usersService = (UsersService) applicationContext.getBean("usersService");
        usersService.addUsers();
    
}

3.3Spring IOC 容器创建 Bean 对象的三种方式

3.3.1 通过构造方法创建 Bean 对象
public class UsersServiceImpl implements UsersService {

	public UsersServiceImpl(){ 
		System.out.println("Init......."); 
	}
	 @Override 
	 public void addUsers() { 
	 	System.out.println("UsersService addUsers ......"); 
	 } 
 }
3.3.2 通过静态工厂方法创建对象
3.3.2.1 创建静态工厂方法
package com.bjsxt.factory;

import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;

public class ObjectFactory {
    public static UsersService getInstance(){
        return  new UsersServiceImpl();
    }
}
3.3.2.2 修改配置文件
<?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">
	<bean id="usersService" class="com.bjsxt.service.impl.UsersServiceImpl"/>
	<!--通过静态工厂方法实例化对象--> 
	<bean id="usersService2" class="com.bjsxt.factory.ObjectFactory" factory-method="getInstance"/>
</beans>
3.3.2.3 创建测试类
package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ObjectFactoryTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService) applicationContext.getBean("usersService2");
        usersService.addUsers();
    }
}
3.3.3 通过动态工厂方法创建对象
3.3.3.1 创建动态工厂方法
package com.bjsxt.factory;

import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;

public class DynamicObjectFactory {

    public UsersService getInstance(){
        return new UsersServiceImpl();
    }
}
3.3.3.2 修改配置文件
<!--通过动态工厂方法实例化对象--> 
<bean id="dynamicObjectFactory" class="com.bjsxt.factory.DynamicObjectFactory"/> 
<bean id="usersService3" factory-bean="dynamicObjectFactory" factory-method="getInstance"/>
3.3.3.3 创建测试类
package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DynamicFactoryTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService) applicationContext.getBean("usersService3");
        usersService.addUsers();
    }
}

3.4在 Spring IOC 容器中获取 Bean 对象的方式

3.4.1 通过 id 或 name 获取 Bean 对象
applicationContext.getBean(id|name);
3.4.1.1 配置文件
<bean id="usersService" name="name1,name2,name3"  class="com.bjsxt.service.impl.UsersServiceImpl" >
3.4.1.2 获取 bean 对象
 //启动Spring IOC容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从IOC容器中获取
        UsersService usersService = (UsersService) applicationContext.getBean("name2");
        usersService.addUsers();
3.4.2 通过类型获取 Bean 对象

通过类型来或取 Bean 时,要求类型必须是唯一的。

applicationContext.getBean(Class clazz);
3.4.2.1 获取 Bean 对象

在这里插入图片描述

//通过类型获取 Bean 对象 
UsersService usersService = applicationContext.getBean(UsersServiceImpl.class); 
usersService.addUsers();
3.4.3 通过 id 或 name 与类型获取 Bean 对象

在 SpringIOC 容器中,通过类型获取对象时,如果同一类型存在多个对象,我们可以使 用 id 或 name 来识别需要获取的对象。

3.4.3.1 方式一
  //根据id或name区别获取指定的对象方式一
       UsersService usersService = applicationContext.getBean("name1",UsersServiceImpl.class);
        usersService.addUsers();
3.4.3.2 方式二

在这里插入图片描述

 /*方式二*/
        //获取Spring IOC容器中所有的Bean对象的ID
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for(String name: beanDefinitionNames){
            System.out.println(name);
        }
        UsersService usersService = applicationContext.getBean(beanDefinitionNames[0],UsersServiceImpl.class);
        usersService.addUsers();

3.5Spring IOC 容器创建对象的策略

3.5.1 实例化对象策略

Spring IOC 容器在启动时默认的会将在配置文件中所配置的所有 Bean 对象立即进行实 例化,并保存在 IOC 容器中。我们可以通过<bean>标签 lazy-init属性的实现延迟实例化对象。 注意:lazy-init="false"只对 scope 属性为 singleton 才有效,如果 scope 属性为 pototype, 无论 lazy-init的属性值是什么,都只在通过getbean 时进行实例化。

3.5.1.1 立即创建

lazy-init="false"(默认)
在 Spring IOC 容器启动时会实例化配置文件中的所有 Bean 对象。

3.5.1.2 延迟创建

lazy-init="true"
当调用 getBean 方法时创建对象。

3.5.2 Bean 对象的作用域

作用域:作用域限定了 Spring Bean 的作用范围,在 Spring 配置文件定义 Bean 时,通过 声明 scope 配置项,可以灵活定义 Bean 的作用范围。

scope 属性的值:

  • singleton
  • prototype
3.5.2.1 singleton(单例)

singleton 为 scope 属性的默认值。当 scope 属性的值为 singleton 时,Spring IOC 容器启 动时会立即实例化一次 Bean 对象,并一直被 Spring IOC 容器所缓存,所以生命周期较长。

singleton 特点:

  • Spring IOC 容器启动时会创建 Bean 对象
  • 每次调用 getBean 都返回 spring 容器中的唯一一个对象
package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopeTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService) applicationContext.getBean("usersService");
        UsersService usersService1 = (UsersService)applicationContext.getBean("usersService");
        System.out.println(usersService);
        System.out.println(usersService1);
    }
}

在这里插入图片描述

3.5.2.2 prototype(多例)

当 scope 属性的值为 prototype 时,每次调用调用 getBean 方法时都会返回一个新的 Bean 对象,Spring IOC 容器并不会缓存该对象,所以就不再负责管理它的生命周期。

prototype 特点:

  • Spring IOC 容器启动时不会创建 Bean 对象。
  • 每次调用 getBean 都会创建一个新 Bean 对象。
package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopeTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("------------------------");
        UsersService usersService = (UsersService) applicationContext.getBean("usersService");
        UsersService usersService1 = (UsersService)applicationContext.getBean("usersService");
        System.out.println(usersService);
        System.out.println(usersService1);
    }
}

在这里插入图片描述

三、 DI 依赖注入

对于 Spring IOC 容器而言我们更多的是使用它的依赖注入。 Spring 创建对象的过程叫 做 IOC,创建对象时给对象属性赋值叫做 DI,所以我们可以认为 IOC 和 DI 是同一个事情。

1 什么是依赖注入

DI (Dependency Injection):依赖注入是指在Spring IOC容器创建对象的过程中,将所依赖的对象通过配置进行注入。我们可以 通过依赖注入的方式来降低对象间的耦合度。
在软件工程中,对象之间的耦合度就是对象之间的依赖性。对象之间的耦合越高,维护成本越高,因此对象的设计应使对象之间的耦合越小越好。

1.1类的关系

继承 实现 依赖 关联 聚合 组合

1.1.1 依赖关系(Dependency)

【依赖关系】:是一种使用的关系,即一个类的实现需要另一个类的协助,所以要尽量不使用双向的相互依赖。
【代码表现】:局部变量、方法的参数或者对静态方法的调用
【剪头及指向】:带箭头的虚线,指向被使用者

1.1.2 聚合(Aggregation)

【聚合关系】:是整体与部分的关系.如车和轮胎是整体和部分的关系. 聚合关系是关联关系的一种,是强的关联关系;关联和聚合在语法上无法区分,必须考察具体的逻辑关系。
【代码体现】:成员变量
【箭头及指向】:带空心菱形的实心线,菱形指向整体

1.2关系强度

继承 = 实现 > 组合 > 聚合 > 关联 > 依赖

2 为什么使用依赖注入

2.1开闭原则

2.1.1 定义

OCP (Open Close Principle): 软件本身应该是可扩展的,而不可修改的。也就是,对扩 展开放,对修改封闭的。

2.1.2 开闭原则优点

易扩展。开闭原则的定义就要求对扩展开放。

易维护。软件开发中,对现有代码的修改是一件很有风险的事情,符合开闭原则的设计 在扩展时无需修改现有代码,规避了这个风险,大大提交了可维护性。

2.2高内聚,低耦合

高内聚是指相关度比较高的部分尽可能的集中,不要分散。

低耦合就是说两个相关的模块尽可以能把依赖的部分降低到最小,不要产生强依赖。

3 依赖注入的方式

在使用依赖注入时,如果注入的是 Bean 对象,那么要求注入的 Bean 对象与被注入的 Bean 对象都需要 Spring IOC 容器来实例化。

3.1通过 Set 方法注入

需要为注入的成员变量提供 Set 方法。

3.1.1 配置文件

添加持久层

package com.bjsxt.dao;

public interface UsersDao {
    void insertUsers();
}
package com.bjsxt.dao.impl;

import com.bjsxt.dao.UsersDao;

public class UsersDaoImpl implements UsersDao {
    @Override
    public void insertUsers() {
        System.out.println("JDBC:....insert into ....");
    }
}

修改配置文件

<bean id="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/>
<bean id="usersService" name="name1,name2,name3" class="com.bjsxt.service.impl.UsersServiceImpl"> 
	<property name="usersDao"> 
		<ref bean="usersDao"/> 
	</property> 
	<!--简写-->
	<!--<property name="usersDao" ref="usersDaoMybatis"/>-->
</bean>
3.1.2 Bean 对象

public class UsersServiceImpl implements UsersService {
    private UsersDao usersDao;
    
    public UsersDao getUsersDao() { 
    	return usersDao; 
    }
     public void setUsersDao(UsersDao usersDao) {
        this.usersDao = usersDao;
    }
    
      public UsersServiceImpl(){
        System.out.println("Init.......");
    }
       @Override
    public void addUsers() {
        usersDao.insertUsers();
        //System.out.println("UsersService addUsers ......");
    }
}

添加测试类

package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DITest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService= (UsersService) applicationContext.getBean("usersService");
        usersService.addUsers();
    }
}

在这里插入图片描述
修改dao

package com.bjsxt.dao.impl;

import com.bjsxt.dao.UsersDao;

public class UsersDaoMybatisImpl implements UsersDao {
    @Override
    public void insertUsers() {
        System.out.println("Mybatis.....insert into.....");
    }
}

修改配置文件

<bean id="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl"/>
<bean id="usersDaoMybatis" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/>
<bean id="usersService" name="name1,name2,name3" class="com.bjsxt.service.impl.UsersServiceImpl"> 
	<property name="usersDao"> 
		<ref bean="usersDaoMybatis"/> 
	</property> 
</bean>

面向接口,不需要修改代码。
在这里插入图片描述

3.2通过构造方法注入

Bean 对象中需要提供有参的构造方法

3.2.1 配置文件
<bean id="usersService" name="name1,name2,name3" class="com.bjsxt.service.impl.UsersServiceImpl"> 
	<!-- 
		name:根据参数名称识别参数 
		index:根据参数的位置来识别参数 
		type:根据参数的类型识别参数 
	--> 
	<constructor-arg name="usersDao"> 
		<ref bean="usersDaoMybatis"/> 
	</constructor-arg> 
	<!--<constructor-arg name="usersDao" ref="usersDaoMybatis"/>--> 
</bean>
3.2.2 Bean 对象
public class UsersServiceImpl implements UsersService {
	private UsersDao usersDao; 
	
	public UsersServiceImpl(UsersDao usersDao){ 
		this.usersDao = usersDao; 
	}
	

	public UsersDao getUsersDao() { 
    	return usersDao; 
    }
     public void setUsersDao(UsersDao usersDao) {
        this.usersDao = usersDao;
    }
    
      public UsersServiceImpl(){
        System.out.println("Init.......");
    }
       @Override
    public void addUsers() {
        usersDao.insertUsers();
     }
}

3.3自动注入

自动注入的方式有两种,一种是全局配置自动注入,另一种是局部配置自动注入。
无论全局配置或局部单独配置,都有 5 个值可以选择:

no:当 autowire 设置为 no 的时候,Spring 就不会进行自动注入。

byName:在 Spring 容器中查找 id 与属性名相同的 bean,并进行注入。需要提供 set 方 法。

byType:在 Spring 容器中查找类型与属性名的类型相同的 bean,并进行注入。需要提供 set 方法。

constructor:仍旧是使用 byName 方式,只不过注入的时候,使用构造方式进行注入。

default:全局配置的 default 相当于 no,局部的 default 表示使用全局配置设置。

3.3.1 局部自动注入

通过 bean 标签中的 autowier 属性配置自动注入。

有效范围:仅针对当前 bean 标签生效。

<bean id="usersDaoMybatis" class="com.bjsxt.dao.impl.UsersDaoMybatisImpl"/> 
<bean id="usersService" name="name1,name2,name3" class="com.bjsxt.service.impl.UsersServiceImpl" autowire="byType"> 
</bean>
3.3.2 全局自动注入

通过 beans 标签中的 default-autowire 属性配置自动注入。

有效范围:配置文件中的所有 bean 标签都生效。

<?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" 
	default-autowire="byName">

4 依赖注入的数据类型

4.1注入 Bean 对象

方式一

<property name="FieldName"> 
	<ref bean="BeanID"/>
</property>	

方式二

<property name="FieldName" ref="BeanID"/>

4.2注入基本数据类型和字符串

方式一

<property name="FieldName"> 
	<value>content</value> 
</property>

方式二

<property name="FieldName" value="Content"/>

4.3注入 List

<property name="FieldName" > 
	<list> 
		<value/>或者<bean/>或者<ref/>...... 
	</list> 
</property>
 <property name="list">
            <list>
                <value>bjsxt</value>
                <value>itbz</value>
            </list>
        </property>
        <property name="users">
            <list>
                <bean class="com.bjsxt.pojo.Users">
                    <property name="username" value="Oldlu"/>
                    <property name="userage" value="30"/>
                </bean>
                <bean class="com.bjsxt.pojo.Users">
                    <property name="username" value="admin"/>
                    <property name="userage" value="20"/>
                </bean>
            </list>
        </property>

4.4注入 Set

<property name="FieldName" > 
	<set>
		<value/>或者<bean/>或者<ref/>...... 
	</set> 
</property>

4.5注入 Map

方式一

<property name="FieldName" > 
	<map>
		<entry key="KeyName" value="Content"/> 
	</map> 
</property>

方式二

<bean id="users1" class="......"> 
<bean id="users1" class="......"> 

<property name="FieldName"> 
	<map>
		<entry key="key1" value-ref="users1"/> 
		<entry key="key2" value-ref="users2"/> 
	</map> 
</property>

4.6注入 Properties

<property name="FieldName" > 
	<props> 
		<prop key="KeyName">Content</prop> 
	</props> 
</property>

四、 Spring 整合持久层技术

1 Spring 整合 JDBC

Spring为了提供对JDBC的支持,在JDBC API的基础上封装了一套实现用于简化JDBC操作的模板。
JDBC模板的设计目的是为了不同类型的JDBC操作提供模板方法,每个模板方法都能控制整个过程,通过这种方式,可以在尽可能保留灵活性的情况下,将数据库存取的工作量降到最低。

1.1搭建环境

1.1.1 创建项目

在这里插入图片描述

1.1.2 添加 jar 包

在这里插入图片描述

1.1.3 创建配置文件
<?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"> 
	
</beans>
1.1.4 创建实体类
package com.bjsxt.pojo;

public class Users {
    private int userid;
    private String username;
    private String usersex;

    public int getUserid() {
        return userid;
    }

    public void setUserid(int userid) {
        this.userid = userid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUsersex() {
        return usersex;
    }

    public void setUsersex(String usersex) {
        this.usersex = usersex;
    }

    @Override
    public String toString() {
        return "Users{" +
                "userid=" + userid +
                ", username='" + username + '\'' +
                ", usersex='" + usersex + '\'' +
                '}';
    }
}
1.1.5 创建持久层
package com.bjsxt.dao;

public interface UsersDao {
    
}
public class UsersDaoImpl implements UsersDao {

}
1.1.6 创建业务层
package com.bjsxt.service;

public interface UsersService {
  
}
package com.bjsxt.service.impl;

public class UsersServiceImpl implements UsersService {
     private UsersDao usersDao;

    public UsersDao getUsersDao() {
        return usersDao;
    }

    public void setUsersDao(UsersDao usersDao) {
        this.usersDao = usersDao;
    }

}

1.2配置 Spring

1.2.1 配置解析 properties 文件
1.2.1.1 添加 db.properties 文件
jdbc.driver=com.mysql.jdbc.Driver 
jdbc.url=jdbc:mysql://localhost:3306/bjsxt 
jdbc.username=root 
jdbc.password=root
1.2.1.2 修改 Spring 配置文件

添加命名空间

xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd

添加<context:property-placeholder/>

<?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 
	http://www.springframework.org/schema/beans/spring-beans.xsd 
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context.xsd" > 
	
	<!--配置解析 properties 配置文件的工具类--> 
	<context:property-placeholder location="db.properties"/> 
</beans>
1.2.2 配置数据源
1.2.2.1 什么是数据源

JDBC2.0 提供了 javax.sql.DataSource 接口,在接口中定义获取 Connection 对象的标准。 数据源的作用是负责建立与数据库的连接,当在应用程序中访问数据库时不必编写数据库连 接代码,直接引用 DataSource 获取操作数据库的 Connection 对象即可。

1.2.2.2 添加数据源配置
<!--配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
1.2.3 配置 JdbcTemplate(Spring提供的一个基于JDBC方式来操作数据库的模板对象)
  <!--配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
1.2.4 配置其他 Bean 对象的依赖注入
1.2.4.1 配置持久层依赖注入
1.2.4.1.1 修改接口实现类
public class UsersDaoImpl implements UsersDao {
    private JdbcTemplate jdbcTemplate;

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
 }
1.2.4.1.2 修改 Spring 配置文件
   <!--配置UsersDao-->
    <bean id="usersDao" class="com.bjsxt.dao.impl.UsersDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>
1.2.4.2 配置业务层依赖注入
   <!-- 配置UsersService-->
    <bean id="usersService" class="com.bjsxt.service.impl.UsersServiceImpl">
        <property name="usersDao" ref="usersDaoSupport"/>
    </bean>

1.3JdbcTemplate 的使用

1.3.1 执行单条 DML 语句

单条的 insert、delete、update。

1.3.1.1 修改持久层
public interface UsersDao {
    int insertUsers(Users users);
 }
    /**
     * 添加用户
     * @param users
     * @return
     */
    @Override
    public int insertUsers(Users users) {
         String sql ="insert into users values(default,?,?)";
         Object[] params = new Object[]{users.getUsername(),users.getUsersex()};
        return this.jdbcTemplate.update(sql,params);
    }
1.3.1.2 修改业务层
public interface UsersService {
    int addUsers(Users users);
 }
    /**
     * 添加用户
     * @param users
     * @return
     */
    @Override
    public int addUsers(Users users) {
        return this.usersDao.insertUsers(users);
    }
1.3.1.3 创建测试类
package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AddUsersTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService)applicationContext.getBean("usersService");
        Users users = new Users();
        users.setUsername("suibian");
        users.setUsersex("male");
        int i = usersService.addUsers(users);
        System.out.println(i);
    }
}
1.3.2 批量执行 DML 语句
1.3.2.1 修改持久层
int[] batchInsertUsers(List<Users> users);
   /**
     * 批量添加用户
     * @param users
     * @return
     */
    @Override
    public int[] batchInsertUsers(List<Users> users) {
        String sql ="insert into users values(default,?,?)";
        BatchPreparedStatementSetter setter = new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
                    Users temp = users.get(i);
                    preparedStatement.setString(1,temp.getUsername());
                    preparedStatement.setString(2,temp.getUsersex());
            }

            @Override
            public int getBatchSize() {
                return users.size();
            }
        };
        return this.jdbcTemplate.batchUpdate(sql,setter);
    }
1.3.2.2 修改业务层
int[] addUsers(List<Users> users);
    /**
     * 批量添加用户
     * @param users
     * @return
     */
    @Override
    public int[] addUsers(List<Users> users) {
        return this.usersDao.batchInsertUsers(users);
    }
1.3.2.3 创建测试类
package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.ArrayList;
import java.util.List;

public class BachAddUsersTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService)applicationContext.getBean("usersService");
        Users users = new Users();
        users.setUsername("suibian1");
        users.setUsersex("male1");
        Users users1 = new Users();
        users1.setUsername("suibian2");
        users1.setUsersex("male2");
        List<Users> list = new ArrayList<>();
        list.add(users);
        list.add(users1);
        usersService.addUsers(list);
    }
}
1.3.3 查询返回单条数据
1.3.3.1 修改持久层
Users selectUsersById(int userid);
  /**
     * 根据ID查询用户
     * @param userid
     * @return
     */
    @Override
    public Users selectUsersById(int userid) {
        String sql = "select * from users where userid = ?";
        Object[] params = new Object[]{userid};
        Users users = new Users();
        this.jdbcTemplate.query(sql, params, new RowCallbackHandler() {
            @Override
            public void processRow(ResultSet resultSet) throws SQLException {
                 users.setUserid(resultSet.getInt("userid"));
                 users.setUsername(resultSet.getString("username"));
                 users.setUsersex(resultSet.getString("usersex"));
            }
        });
        return users;
    }
1.3.3.2 修改业务层
Users findUsersById(int userid);
 @Override
    public Users findUsersById(int userid) {
        return this.usersDao.selectUsersById(userid);
    }
1.3.3.3 创建测试类
package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FindUsersByIdTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService)applicationContext.getBean("usersService");
        Users users = usersService.findUsersById(34);
        System.out.println(users);
    }
}
1.3.4 查询返回多条数据
1.3.4.1 修改持久层
List<Users> selectUsersByName(String username);
  /**
     * 查询用户返回多条数据
     * @param username
     * @return
     */
    @Override
    public List<Users> selectUsersByName(String username) {
        String sql = "select * from users where username = ?";
        Object[] param = new Object[]{username};
        return this.jdbcTemplate.query(sql, param, new RowMapper<Users>() {
            @Override
            public Users mapRow(ResultSet resultSet, int i) throws SQLException {
                Users users = new Users();
                users.setUserid(resultSet.getInt("userid"));
                users.setUsername(resultSet.getString("username"));
                users.setUsersex(resultSet.getString("usersex"));
                return users;
            }
        });
    }
1.3.4.2 修改业务层
List<Users> findUsersByName(String username);
  @Override
    public List<Users> findUsersByName(String username) {
        return this.usersDao.selectUsersByName(username);
    }
1.3.4.3 创建测试类
package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class FindUsersByNameTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService)applicationContext.getBean("usersService");
        List<Users> list = usersService.findUsersByName("itbz-sxt4");
        list.forEach(System.out::println);
    }
}
1.3.5 查询多条数据简化版

通过 BeanPropertyRowMapper 完成对象的映射处理

1.3.5.1 修改持久层
List<Users> selectUsersByName2(String username);
  @Override
    public List<Users> selectUsersByName2(String username) {
        String sql = "select * from users where username = ?";
        Object[] param = new Object[]{username};
        return this.jdbcTemplate.query(sql,param,new BeanPropertyRowMapper<>(Users.class));
    }
}
1.3.5.2 修改业务层
List<Users> findUsersByName2(String username);
    @Override
    public List<Users> findUsersByName2(String username) {
        return this.usersDao.selectUsersByName2(username);
    }
1.3.5.3 创建测试类
package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class FindUsersByName2Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService)applicationContext.getBean("usersService");
        List<Users> list = usersService.findUsersByName2("itbz-sxt4");
        list.forEach(System.out::println);
    }
}

1.4JdbcDaoSupport 的使用

1.4.1 创建持久层
public class UsersDaoImplSupport extends JdbcDaoSupport implements UsersDao {
 
    @Override
    public List<Users> selectUsersByName2(String username) {
        String sql = "select * from users where username = ?";
        Object[] param = new Object[]{username};
        return this.getJdbcTemplate().query(sql,param,new BeanPropertyRowMapper<>(Users.class));
    }
}
1.4.2 修改配置文件
<bean id="usersDaoSupport" class="com.bjsxt.dao.impl.UsersDaoImplSupport"> 
	<property name="dataSource" ref="dataSource"/> 
</bean>

2 Spring 整合 Mybatis

2.1jar 包介绍

2.1.1 Mybatis 的 jar 包:

mybatis-3.5.5.jar
asm-7.1.jar
cglib-3.3.0.jar
commons-logging-1.2.jar
javassist-3.27.0-GA.jar
log4j-1.2.17.jar
log4j-api-2.13.3.jar
log4j-core-2.13.3.jar
ognl-3.2.14.jar
slf4j-api-1.7.30.jar
slf4j-log4j12-1.7.30.jar

2.1.2 Mybatis 整合 Spring 的 jar 包:

mybatis-spring-2.0.4.jar

2.1.3 Spring 的 jar 包:

spring-beans-5.2.7.RELEASE.jar
spring-context-5.2.7.RELEASE.jar
spring-core-5.2.7.RELEASE.jar
spring-expression-5.2.7.RELEASE.jar
spring-jdbc-5.2.7.RELEASE.jar
spring-tx-5.2.7.RELEASE.jar
spring-aop-5.2.7.RELEASE.jar

2.1.4 数据库驱动 jar 包:

mysql-connector-java-5.1.48.jar

2.2搭建环境

2.2.1 创建项目

在这里插入图片描述

2.2.2 添加 jar 包

在这里插入图片描述

2.2.3 创建配置文件
<?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"> 

</beans>
2.2.4 添加 log4j 配置文件
log4j.rootLogger=debug,console

### appender.console输出到控制台 ###
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=<%d> %5p (%F:%L) [%t] (%c) - %m%n
log4j.appender.console.Target=System.out

### appender.logfile输出到日志文件 ###
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
log4j.appender.logfile.File=SysLog.log
log4j.appender.logfile.MaxFileSize=500KB
log4j.appender.logfile.MaxBackupIndex=7
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=<%d> %p (%F:%L) [%t] %c - %m%n
2.2.5 创建映射配置文件与接口

在这里插入图片描述

2.2.6 创建实体类

在这里插入图片描述

2.2.7 创建业务层
public interface UsersService { 
}
public class UsersServiceImpl implements UsersService { 
}

2.3配置 Spring 与 Mybatis 整合

2.3.1 配置解析 properties 文件
2.3.1.1 添加 db.properties 文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bjsxt
jdbc.username=root
jdbc.password=root
2.3.1.2 修改 Spring 配置文件

添加命名空间

xmlns:context="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd

添加<context:property-placeholder/>

<?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 
	http://www.springframework.org/schema/beans/spring-beans.xsd 
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context.xsd" >
	
	<!--配置解析 Properties 工具类--> 
	<context:property-placeholder location="db.properties"/> 
</beans>
2.3.2 配置数据源
 <!--配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
    </bean>
2.3.3 配置 SqlSessionFactoryBean

SqlSessionFactoryBean 是初始化 Mybatis 框架的 Bean 对象。它是生产 SqlSessionFactory 的一种工厂 Bean。在 Spring 整合 Mybatis 中,我们可以不需要 Mybatis 的配置文件,在该 Bean 对象中可以完成对 Mybatis 框架的配置。 如果需要在 Mybatis 的配置文件中配置 Mybatis 框架时,仍然可以使用 Mybatis 的配置文件,但是需要在 SqlSessionFactoryBean 对象 的 configLocation 属性中指定 Mybatis 的配置文件的路径和名称。

 <!--配置SqlSessionFactoryBean-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.bjsxt.pojo"/>
        <property name="mapperLocations" value="com/bjsxt/mapper/*.xml"/>
    </bean>
2.3.4 配置 SqlSessionTemplate
    <!--配置SqlSessionTemplate-->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"/>
    </bean>
2.3.5 配置业务层依赖
2.3.5.1 接口实现类
public class UsersServiceImpl implements UsersService {
    private SqlSessionTemplate sqlSessionTemplate;

    public SqlSessionTemplate getSqlSessionTemplate() {
        return sqlSessionTemplate;
    }

    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }
 }
2.3.5.2 配置文件
 <!--配置业务层-->
    <bean id="usersService" class="com.bjsxt.service.impl.UsersServiceImpl">
        <property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
    </bean>

2.4SqlSessionTemplate 对象的使用

2.4.1 添加用户业务
2.4.1.1 修改业务层
public interface UsersService { 
	void addUsers(Users users); 
}
    /**
     * 添加用户
     * @param users
     */
    @Override
    public void addUsers(Users users) {
        UsersMapper usersMapper =this.sqlSessionTemplate.getMapper(UsersMapper.class);
        usersMapper.insertSelective(users);
    }
2.4.1.2 创建测试类
package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AddUsersTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService) applicationContext.getBean("usersService");
        Users users = new Users();
        users.setUsersex("male");
        users.setUsername("suibian33");
        usersService.addUsers(users);
    }
}
2.4.2 查询用户业务
2.4.2.1 修改业务
List<Users> findUsersAll();
    /**
     * 查询所有用户
     * @return
     */
    @Override
    public List<Users> findUsersAll() {
        UsersMapper usersMapper = this.sqlSessionTemplate.getMapper(UsersMapper.class);
        UsersExample usersExample = new UsersExample();
        return usersMapper.selectByExample(usersExample);
    }
2.4.2.2 创建测试类
package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class FindUsersAllTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService)applicationContext.getBean("usersService");
        List<Users> list = usersService.findUsersAll();
        list.forEach(System.out::println);
    }
}

2.5 SqlSessionDaoSupport 的使用

2.5.1 创建业务层
package com.bjsxt.service.impl;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.pojo.UsersExample;
import com.bjsxt.service.UsersService;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UsersServiceImpl2 extends SqlSessionDaoSupport implements UsersService {

    @Override
    public void addUsers(Users users) {

    }

    @Override
    public List<Users> findUsersAll() {
        UsersMapper usersMapper = this.getSqlSessionTemplate().getMapper(UsersMapper.class);
        UsersExample usersExample = new UsersExample();
        return usersMapper.selectByExample(usersExample);
    }
}
2.5.2 修改配置文件
<bean id="usersService2" class="com.bjsxt.service.impl.UsersServiceImpl2"> 
	<property name="sqlSessionFactory" ref="sqlSessionFactoryBean"/> 
</bean>
2.5.3 创建测试类
package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class FindUsersAll2Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService)applicationContext.getBean("usersService2");
        List<Users> list = usersService.findUsersAll();
        list.forEach(System.out::println);
    }
}

2.6 MapperScannerConfigurer 对象的使用

用于以自动扫描形式来配置 MyBatis 中映射器对象,可以通过配置包路径来自动扫描包接口生成映射器对象。

2.6.1 创建业务层
package com.bjsxt.service.impl;

import com.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.pojo.UsersExample;
import com.bjsxt.service.UsersService;

import java.util.List;

public class UsersServiceImpl3 implements UsersService {
    private UsersMapper usersMapper;

    public UsersMapper getUsersMapper() {
        return usersMapper;
    }

    public void setUsersMapper(UsersMapper usersMapper) {
        this.usersMapper = usersMapper;
    }

    @Override
    public void addUsers(Users users) {

    }

    @Override
    public List<Users> findUsersAll() {
        UsersExample usersExample = new UsersExample();
        return this.usersMapper.selectByExample(usersExample);
    }
}
2.6.2 创建配置文件
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置解析Properties工具类-->
    <context:property-placeholder location="db.properties"/>

    <!--配置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
    </bean>

    <!--配置SqlSessionFactoryBean-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.bjsxt.pojo"/>
      <!--  如果接口与映射配置文件在同一个包中,那么mapperLocations属性则不需要配置。-->
        <!--<property name="mapperLocations" value="com/bjsxt/mapper/*.xml"/>-->
    </bean>

    <!--配置MapperScannerConfigurer-->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.bjsxt.mapper"/>
    </bean>

    <bean id="usersService3" class="com.bjsxt.service.impl.UsersServiceImpl3">
        <property name="usersMapper" ref="usersMapper"/>
    </bean>
</beans>
2.6.3 创建测试类
package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class MapperScannerConfigurerTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext2.xml");
       /* String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for(String str:beanDefinitionNames){
            System.out.println(str);
        }*/
        UsersService usersService = (UsersService) applicationContext.getBean("usersService3");
        List<Users> list = usersService.findUsersAll();
        list.forEach(System.out::println);
    }
}

五、 代理模式

1 什么是代理模式

代理模式(Proxy Pattern):代理模式是 Java 常见的设计模式之一。所谓代理模式是指客 户端并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象。通俗的 来讲代理模式就是我们生活中常见的中介。
在这里插入图片描述

2 为什么使用代理模式

隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类 对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。

开闭原则:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额 外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合 代码设计的开闭原则。

代理模式的优点:

  • 代理模式能将代理对象与真实对象被调用的目标对象分离。
  • 一定程度上降低了系统的耦合度,扩展性好。
  • 保护目标对象。
  • 增强目标对象。

代理模式的缺点:

  • 代理模式会造成系统设计中类的数目的增加。
  • 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
  • 增加了系统的复杂度。

3 代理模式的实现

代理模式可以分为两种:静态代理、动态代理。

3.1静态代理 静态代理模式由三个部分构成:

  • 一个公共的接口
  • 一个被代理角色
  • 一个代理角色
3.1.1 创建公共的接口
package com.bjsxt.staticproxy;

public interface Rent {
    void renting();
}
3.1.2 创建被代理角色
package com.bjsxt.staticproxy;

public class Oldlu implements Rent {
    @Override
    public void renting() {
        System.out.println("Oldlu 有房出租");
    }
}
3.1.3 创建代理角色
package com.bjsxt.staticproxy;

public class StaticProxyRent implements Rent {
    private Rent rent;
    public StaticProxyRent(Rent rent){
        this.rent = rent;
    }
    @Override
    public void renting() {
        System.out.println("向房客出租房屋");
        this.rent.renting();
        System.out.println("完成售后服务");
    }
}
3.1.4 创建测试类
package com.bjsxt.staticproxy;

public class StaticProxyTest {
    public static void main(String[] args) {
        Rent rent = new Oldlu();
        StaticProxyRent staticProxyRent = new StaticProxyRent(rent);
        staticProxyRent.renting();
    }
}

3.2动态代理的实现

在动态代理中分为两种实现方式:

  • 使用 JDK 的 Proxy 类实现动态代理
  • 使用 CGLIB 实现动态代理
3.2.1 使用 JDK 的 Proxy 类实现动态代理
3.2.1.1 创建业务接口
package com.bjsxt.dynamicproxy.jdkproxy;

public interface JdkProxyRent {
    void renting();
}
3.2.1.2 创建接口实现类
package com.bjsxt.dynamicproxy.jdkproxy;

public class JdkProxyOldlu implements JdkProxyRent {
    @Override
    public void renting() {
        System.out.println("Oldlu 有房出租");
    }
}
3.2.1.3 创建生成代理对象的工厂
package com.bjsxt.dynamicproxy.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxyFactory {

    /**
     * 动态生成代理对象
     */
    public static Object getProxyBean(Object target){
        Class clazz = target.getClass();
        MyAspect myAspect = new MyAspect();
        //在JDK中动态生成代理对象的方法
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
            /**
             * 动态生成代理对象中的方法。
             * @param proxy 动态生成的代理对象
             * @param method 目标方法的方法对象
             * @param args 传递到目标方法中的参数列表
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                myAspect.before();
               Object obj =  method.invoke(target,args);
                myAspect.after();
                return obj;
            }
        });
    }
}
3.2.1.4 创建切面对象
package com.bjsxt.dynamicproxy.jdkproxy;

public class MyAspect {
    public void before(){
        System.out.println("带领房客看房。。。签租房协议");
    }
    public void  after(){
        System.out.println("售后服务。");
    }
}
3.2.1.5 创建测试类
package com.bjsxt.dynamicproxy.jdkproxy;

public class JdkProxyTest {
    public static void main(String[] args) {
        JdkProxyRent jdkProxyRent = new JdkProxyOldlu();
        JdkProxyRent jdkProxyRent1 = (JdkProxyRent) JdkProxyFactory.getProxyBean(jdkProxyRent);
        jdkProxyRent1.renting();
    }
}
3.2.2 使用 CGLIB 实现动态代理

CGLIB(Code Generation Library)是一个高性能开源的代码生成包,它被许多框架所使 用,其底层是通过使用一个小而快的字节码处理框架 ASM(Java 字节码操控框架)转换字 节码并生成新的类。因此 CGLIB 要依赖于 ASM 的包。

JDK 的动态代理机制只能代理实现了接口的类,而对于没有实现接口的类就不能使用 JDK 的 Proxy 类生成代理对象,cglib 是针对类来实现代理的,他的原理是对指定的目标类生 成一个子类并通过回调的方式来实现增强,但因为采用的是继承,所以不能对 final 修饰的 类进行代理。

3.2.2.1 添加 jar 包

cglib.jar
asm.jar

3.2.2.2 创建业务接口
package com.bjsxt.dynamicproxy.cglibproxy;

public interface CglibProxyRent {
    void renting();
}
3.2.2.3 创建接口实现类
package com.bjsxt.dynamicproxy.cglibproxy;

public class CglibProxyOldlu implements CglibProxyRent {
    @Override
    public void renting() {
        System.out.println("Oldlu 有房出租");
    }

}
3.2.2.4 创建生成代理对象的工厂
package com.bjsxt.dynamicproxy.cglibproxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxyBeanFactory {
    public static Object getProxyBean(CglibProxyRent rent){
        CglibMyAspect myAspect = new CglibMyAspect();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(rent.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            /**
             *
             * @param o 代理对象的引用
             * @param method 目标对象的方法对象
             * @param objects 目标方法的参数列表
             * @param methodProxy 目标方法的方法对象的代理对象
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                myAspect.before();
                Object obj = method.invoke(rent,objects);
                myAspect.after();
                return obj;
            }
        });
        return enhancer.create();
    }
}
3.2.2.5 创建切面
package com.bjsxt.dynamicproxy.cglibproxy;

public class CglibMyAspect {
    public void before(){
        System.out.println("带领客户看房,签订租房协议");
    }

    public void after(){
        System.out.println("售后服务");
    }
}
3.2.2.6 创建测试类
package com.bjsxt.dynamicproxy.cglibproxy;

public class Test {
    public static void main(String[] args) {
        CglibProxyRent rent = new CglibProxyOldlu();
        CglibProxyRent rent1 = (CglibProxyRent) CglibProxyBeanFactory.getProxyBean(rent);
        rent1.renting();
    }
}

六、 AOP 编程

1 AOP 简介

1.1什么是 AOP

AOP 的全称是 Aspect Oriented Programming,即面向切面编程,它将业务逻辑的各个部 分进行隔离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率。

AOP 采取横向抽取机制,取代了传统纵向继承体系的重复性代码,其应用主要体现在 事务处理、日志管理、权限控制、异常处理等方面。

目前最流行的 AOP 技术有两个,分别为 Spring 框架的 AOP 和 AspectJ 框架。

1.2 什么是面向切面编程

把一个个的横切关注点放到某个模块中去,称之为切面。每个切面影响业务的一种功能, 切面的目的就是为了功能增强,将需要增强的方法做成切面,实现对业务的增强,就是面向 切面编程。

面向切面编程的目的:将与业务本身无关,却被业务模块所共同调用的功能代码封装成 切面,以减少系统的重复代码,降低耦合,提高可扩展性。

面向切面编程的优势:把多个方法前/后的共同代码抽离出来,使用动态代理机制来控 制,先执行抽离出来的代码,再执行每一个真实方法。
在这里插入图片描述

2 AOP 术语

为了更好地理解 AOP,就需要对 AOP 的相关术语有一些了解,这些专业术语主要包含 Joinpoint、Pointcut、Advice、Target、Weaving、Proxy 和 Aspect,它们的含义如下表所示。
在这里插入图片描述
在这里插入图片描述

3 Spring AOP 模块

3.1Spring AOP 模块中的通知类型

在这里插入图片描述

3.2Spring AOP 模块的使用

在使用 Spring 框架的 AOP 模块开发 AOP 时,需要添加核心容器的 jar 包以及 aop 的 jar 包。
在这里插入图片描述
注意:ThrowsAdvice 接口是一个标识接口没有任何抽象方法。如果通知类型定义为异常 通知,那么除了要实现 ThrowsAdvice 以外,还需要在切面中添加下面 4 个方法中的一个,并在该方法中实现具体的增强处理。

 public void afterThrowing(Exception ex) 
 public void afterThrowing(RemoteException) 
 public void afterThrowing(Method method, Object[] args, Object target, Exception ex) 
 public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
3.2.1 创建切面
package com.bjsxt.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;

import java.lang.reflect.Method;

public class MyAspect implements MethodBeforeAdvice, AfterReturningAdvice, MethodInterceptor, ThrowsAdvice {

    /**
     * 前置通知
     * @param method 目标方法对象
     * @param objects 目标方法的参数列表
     * @param o 目标对象
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("Before...."+method.getName());
    }

    /**
     * 后置通知
     * @param o 目标方法的返回值
     * @param method 目标方法对象
     * @param objects 目标方法的参数列表
     * @param o1 目标对象
     * @throws Throwable
     */
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("After...."+method.getName());
    }

    /**
     * 环绕通知
     * @param methodInvocation 目标方法对象
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("Around .....Before"+methodInvocation.getMethod().getName());
       //执行目标方法
       Object obj =  methodInvocation.proceed();
        System.out.println("Around.....After"+methodInvocation.getMethod().getName());
        return obj;
    }

    /**
     * 异常通知
     * @param ex
     */
    public void afterThrowing(Exception ex){
        System.out.println(ex+" Exception");
    }
}
3.2.2 配置切面

Spring 的 AOP 模块实现 AOP 编程的方式:
使用 org.springframework.aop.framework.ProxyFactoryBean工厂对象创建代理对象。

3.2.2.1 创建目标对象
package com.bjsxt.service;

public interface UsersService {
    void addUsers();
}
package com.bjsxt.service.impl;

import com.bjsxt.service.UsersService;

public class UsersServiceImpl implements UsersService {
    @Override
    public void addUsers() {
        String str = null;
        str.length();
        System.out.println("addUsers.....");
    }
}
3.2.2.2 修改 Spring 配置文件
<?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">

    <!--配置目标对象-->
    <bean id="usersService" class="com.bjsxt.service.impl.UsersServiceImpl"/>

    <!--配置切面对象-->
    <bean id="myAspect" class="com.bjsxt.aop.MyAspect"/>
    <!--配置切面-->
    <bean id="usersServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
      <!--  配置目标对象所实现的接口-->
        <property name="proxyInterfaces" value="com.bjsxt.service.UsersService"/>
       <!-- 配置目标对象-->
        <property name="target" ref="usersService"/>
        <!--配置切面对象-->
        <property name="interceptorNames">
            <list>
                <value>myAspect</value>      
            </list>
        </property>
        <!--如何生成代理对象 true:使用CGLIB,false使用JDK的Proxy-->
        <property name="proxyTargetClass" value="true"/>
    </bean>
</beans>
3.2.2.3 创建测试类
package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService = (UsersService) applicationContext.getBean("usersServiceProxy");
        usersService.addUsers();
    }
}
3.2.3 Spring AOP 模块的使用案例

需求:要求在业务层的 updateUsers 方法执行之前,将 UserName 参数转换大写。

3.2.3.1 修改业务层
void updateUsers(String username);
  @Override
    public void updateUsers(String username) {
        System.out.println("UpdateUsers "+username);
    }
3.2.3.2 创建切面
package com.bjsxt.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class ToUppercaseAspect implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        //将username转换大写
        Object[] args = methodInvocation.getArguments();
        args[0] = ((String)args[0]).toUpperCase();
        Object obj =  methodInvocation.proceed();
        return obj;
    }
}
3.2.3.3 配置切面
<?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">

    <!--配置目标对象-->
    <bean id="usersService" class="com.bjsxt.service.impl.UsersServiceImpl"/>

    <!--配置切面对象-->
    <bean id="myAspect" class="com.bjsxt.aop.MyAspect"/>

    <bean id="toUppercaseAspect" class="com.bjsxt.aop.ToUppercaseAspect"/>
    <!--配置切面-->
    <bean id="usersServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
      <!--  配置目标对象所实现的接口-->
        <property name="proxyInterfaces" value="com.bjsxt.service.UsersService"/>
       <!-- 配置目标对象-->
        <property name="target" ref="usersService"/>
        <!--配置切面对象-->
        <property name="interceptorNames">
            <list>
                <value>myAspect</value>
                <value>toUppercaseAspect</value>
            </list>
        </property>
        <!--如何生成代理对象 true:使用CGLIB,false使用JDK的Proxy-->
        <property name="proxyTargetClass" value="true"/>
    </bean>
</beans>

4 AspectJ 框架

4.1AspectJ 框架简介

AspectJ 是一个基于 Java 语言的 AOP 框架。在 Spring 2.0 以后,新增了对 AspectJ 框 架的支持。在 Spring 框架中建议使用 AspectJ 框架开发 AOP。

4.1.1 AspectJ 框架中的通知类型

在这里插入图片描述

4.1.2 Spring 整合 AspectJ 框架所依赖的 Jar 包
4.1.2.1 AspectJ 框架 jar 包

aspectjweaver-1.9.5.jar

4.1.2.2 Spring 框架 jar 包

spring-beans-5.2.7.RELEASE.jar
spring-context-5.2.7.RELEASE.jar
spring-core-5.2.7.RELEASE.jar
spring-expression-5.2.7.RELEASE.jar
spring-aop-5.2.7.RELEASE.jar
spring-aspects-5.2.7.RELEASE.jar
commons-logging-1.2.jar

4.1.3 AspectJ 框架配置 AOP 方式

通过 XML 文件配置 AOP

  • 通过 AspectJ 配置方式
  • 通过 Spring 的 Schema_based 方式

通过注解配置 AOP

4.2AspectJ 框架的使用

在 AspectJ 框架中使用 xml 文件中配置 AOP 的方式:

  • AspectJ 配置方式
  • Schema-based 配置方式
4.2.1 AspectJ 配置方式

AspectJ 配置方式是指使用 AspectJ 框架的配置方式来配置切面。在使用 AspectJ 配置切 面时,切面不需要实现一些特定的接口。

4.2.1.1 创建切面
package com.bjsxt.aspectj.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect {

    /**
     * 前置通知
     * @param joinPoint 对目标对象的封装
     */
    public void myBefore(JoinPoint joinPoint){
        //joinPoint.getTarget(); 获取目标对象
        //joinPoint.getSignature().getName(); 获取目标方法名
        //joinPoint.getArgs(); 获取目标方法参数列表
        //joinPoint.getThis(); 获取代理对象
        System.out.println("Before "+joinPoint.getSignature().getName());
    }

    /**
     * 后置通知
     * @param joinPoint
     */
    public void myAfterReturning(JoinPoint joinPoint){
        System.out.println("After "+joinPoint.getSignature().getName());
    }

    /**
     * 环绕通知
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        System.out.println("Around Before "+proceedingJoinPoint.getSignature().getName());
        Object  obj = proceedingJoinPoint.proceed();
        System.out.println("Around After "+proceedingJoinPoint.getSignature().getName());
        return  obj;
    }

    /**
     * 异常通知类型
     * @param e
     */
    public void myAfterThrowing(Exception e){
        System.out.println("Exception "+e);
    }

    public void myAfter(){
        System.out.println("最终通知");
    }
}
4.2.1.2 Execution 表达式

Execution 是 AspectJ 框架中的一种表达式,用于配置切点。
基本语法格式为:
execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
其中<修饰符模式>与<异常模式>为可选。
execution(public * com.bjsxt.service..*.*(..))
说明:
在这里插入图片描述
在这里插入图片描述
示例 1:
execution(public * com.bjsxt.service.impl.Student.test())
切点是 com.bjsxt.service.impl包中 Student 类中所有 public 修饰的无参数的 test 方法。

示例 2:
execution(* com.bjsxt.service.impl.Student.test(String,int))
切点是com.bjsxt.service.impl包中 Student 类中参数类型是 String,int 类型的 test 方法。

示例 3:
execution(* com.bjsxt.service.impl.Student.test(..))
切点是 com.bjsxt.service.impl 包中 Student 类中任意参数的 test 方法。

示例 4
execution(* com.bjsxt.service.*.*(..))
切点是 com.bjsxt.service 包中所有接口中任意参数的所有方法。

4.2.1.3 使用 AspectJ 方式配置切面
4.2.1.3.1 创建目标对象
package com.bjsxt.aspectj.service;

public interface UsersService {
    void addUsers(String username);
}
package com.bjsxt.aspectj.service.impl;

import com.bjsxt.aspectj.service.UsersService;

public class UsersServiceImpl implements UsersService {
    @Override
    public void addUsers(String username) {
        System.out.println("AddUsers "+username);
    }
}
4.2.1.3.2 开启 aop 命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop.xsd
4.2.1.3.3 配置切面
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置目标对象-->
    <bean id="usersService" class="com.bjsxt.aspectj.service.impl.UsersServiceImpl"/>
    
    <!--配置切面对象-->
    <bean id="myAspect" class="com.bjsxt.aspectj.aop.MyAspect"/>
    <!-- 配置切面-->
    <aop:config>
        <aop:aspect id="my1" ref="myAspect" order="1">
           <!-- 配置切点-->
            <aop:pointcut id="myPointcut" expression="execution(* com.bjsxt.aspectj.service.*.*(..))"/>
            <!--前置通知-->
            <aop:before method="myBefore" pointcut-ref="myPointcut"/>
            <!--后置通知-->
            <aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut"/>
            <!--环绕通知-->
            <aop:around method="myAround" pointcut-ref="myPointcut"/>
            <!--配置异常通知-->
            <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointcut" throwing="e"/>
            <!--最终通知-->
            <aop:after method="myAfter" pointcut-ref="myPointcut"/>
        </aop:aspect>
    </aop:config>
</beans>
4.2.1.3.4 创建测试类
package com.bjsxt.aspectj.test;

import com.bjsxt.aspectj.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContextAspectj.xml");
       UsersService usersService = (UsersService) applicationContext.getBean("usersService");
        usersService.addUsers("oldlu");
    }
}
4.2.1.4 多切面以及切面执行顺序的配置

在 AspectJ 配置方式中,可以添加多个<aop:aspect>标签实现多切面配置。在<aop:aspect> 标签中包含 order 属性用于配置执行切面的执行顺序。

4.2.1.4.1 创建切面
package com.bjsxt.aspectj.aop;

import org.aspectj.lang.JoinPoint;

public class MyAspect2 {
    public void myAspectBefore(JoinPoint joinPoint){
        System.out.println("MyAspect2 Before "+joinPoint.getSignature().getName());
    }
}
4.2.1.4.2 配置多切面
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置目标对象-->
    <bean id="usersService" class="com.bjsxt.aspectj.service.impl.UsersServiceImpl"/>
    
    <!--配置切面对象-->
    <bean id="myAspect" class="com.bjsxt.aspectj.aop.MyAspect"/>
    <!--配置切面对象-->
    <bean id="myAspect2" class="com.bjsxt.aspectj.aop.MyAspect2"/>
    <!-- 配置切面-->
    <aop:config>
        <aop:aspect id="my1" ref="myAspect" order="1">
           <!-- 配置切点-->
            <aop:pointcut id="myPointcut" expression="execution(* com.bjsxt.aspectj.service.*.*(..))"/>
            <!--前置通知-->
            <aop:before method="myBefore" pointcut-ref="myPointcut"/>
            <!--后置通知-->
            <aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut"/>
            <!--环绕通知-->
            <aop:around method="myAround" pointcut-ref="myPointcut"/>
            <!--配置异常通知-->
            <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointcut" throwing="e"/>
            <!--最终通知-->
            <aop:after method="myAfter" pointcut-ref="myPointcut"/>
        </aop:aspect>
        <!--配置切面-->
        <aop:aspect id="my2" ref="myAspect2" order="2">
            <aop:pointcut id="myPointcut2" expression="execution(* com.bjsxt.aspectj.service.*.*(..))"/>
            <aop:before method="myAspectBefore" pointcut-ref="myPointcut2"/>
        </aop:aspect>
    </aop:config>
</beans>
4.2.2 Schema_based 配置方式

Schema_based(基础模式)配置方式是指使用 Spring AOP 模块来定义切面并在 AspectJ 框架中对该切面进行配置。要求切面在定义通知类型时,需要实现特定接口。

4.2.2.1 创建切面
package com.bjsxt.schema_based.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;

import java.lang.reflect.Method;

public class BasedMyAspect implements MethodBeforeAdvice, AfterReturningAdvice, MethodInterceptor, ThrowsAdvice {
    /**
     * 环绕通知
     * @param methodInvocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("Around Before");
       Object obj =  methodInvocation.proceed();
        System.out.println("Around After");
        return obj;
    }

    /**
     * 后置通知
     * @param o
     * @param method
     * @param objects
     * @param o1
     * @throws Throwable
     */
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("After.");
    }

    /**
     * 前置通知
     * @param method
     * @param objects
     * @param o
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("Before");
    }

    /**
     * 异常通知
     * @param ex
     */
    public void afterThrowing(Exception ex){
        System.out.println("Exception: "+ex);
    }
}
4.2.2.2 使用 Schema_based 配置方式配置切面
4.2.2.2.1 创建目标对象
package com.bjsxt.schema_based.service;

public interface BasedUsersService {
    void addUsers(String username);
}
package com.bjsxt.schema_based.service.impl;

import com.bjsxt.schema_based.service.BasedUsersService;

public class BasedUsersServiceImpl implements BasedUsersService {
    @Override
    public void addUsers(String username) {
        System.out.println("AddUsers.."+username);
    }
}
4.2.2.2.2 开启 aop 命名空间
xmlns:aop="http://www.springframework.org/schema/aop" 
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop.xsd
4.2.2.2.3 配置切面
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置目标对象-->
    <bean id="basedUsersService" class="com.bjsxt.schema_based.service.impl.BasedUsersServiceImpl"/>

    <!--配置切面对象-->
    <bean id="basedMyAspect" class="com.bjsxt.schema_based.aop.BasedMyAspect"/>

    <!--配置切面对象-->
    <bean id="basedMyAspect" class="com.bjsxt.schema_based.aop.BasedMyAspect"/>
    <!--配置切面-->
    <aop:config>
       <!-- 配置切点-->
       <aop:pointcut id="basedMyPointcut" expression="execution(* com.bjsxt.schema_based.service.*.*(..))"/>
        <!--配置切面-->
        <aop:advisor id="my1" advice-ref="basedMyAspect" pointcut-ref="basedMyPointcut"/>
    </aop:config>
</beans>
4.2.2.2.4 创建测试类
package com.bjsxt.schema_based.test;

import com.bjsxt.schema_based.service.BasedUsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContextBased.xml");
        BasedUsersService basedUsersService = (BasedUsersService) applicationContext.getBean("basedUsersService");
        basedUsersService.addUsers("oldlu");
    }
}
4.2.2.3 多切面以及切面执行顺序的配置

在 Schema_based 配置方式中,可以添加多个<aop:advisor>标签实现多切面配置。在 <aop:advisor>标签中包含 order 属性用于配置执行切面的执行顺序。

4.2.2.3.1 创建切面
package com.bjsxt.schema_based.aop;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class BasedMyAspect2 implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("BasedMyAspect2...Before");
    }
}
4.2.2.3.2 配置多切面
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置目标对象-->
    <bean id="basedUsersService" class="com.bjsxt.schema_based.service.impl.BasedUsersServiceImpl"/>

    <!--配置切面对象-->
    <bean id="basedMyAspect" class="com.bjsxt.schema_based.aop.BasedMyAspect"/>

    <!--配置切面对象-->
    <bean id="basedMyAspect2" class="com.bjsxt.schema_based.aop.BasedMyAspect2"/>
    <!--配置切面-->
    <aop:config>
       <!-- 配置切点-->
       <aop:pointcut id="basedMyPointcut" expression="execution(* com.bjsxt.schema_based.service.*.*(..))"/>
        <!--配置切面-->
        <aop:advisor id="my1" advice-ref="basedMyAspect" pointcut-ref="basedMyPointcut" order="1"/>
        <aop:advisor id="my2" advice-ref="basedMyAspect2" pointcut-ref="basedMyPointcut" order="2"/>
    </aop:config>
</beans>
4.2.3 注解配置方式

AspectJ 框架允许使用注解定义切面、切入点和增强处理,而 Spring 框架则可以识别并 根据这些注解生成 AOP 代理。

4.2.3.1 常用注解

在这里插入图片描述
在这里插入图片描述

4.2.3.2 创建切面
package com.bjsxt.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;

@Aspect //指定当前对象为切面对象
@Order(2)
public class MyAspect {

    /**
     * 配置切点
     */
    @Pointcut("execution(* com.bjsxt.service.*.*(..))")
    public void myPointcut(){

    }

    /**
     * 前置通知
     * @param joinPoint
     */
    //@Before("execution(* com.bjsxt.service.*.*(..))")
    @Before("myPointcut()")
    public void myBefore(JoinPoint joinPoint){
        System.out.println("Before...."+joinPoint.getSignature().getName());
    }

    /**
     * 后置通知
     * @param joinPoint
     */
    //@AfterReturning("execution(* com.bjsxt.service.*.*(..))")
    @AfterReturning("myPointcut()")
    public void myAfterRetuning(JoinPoint joinPoint){
        System.out.println("AfterRetuning "+joinPoint.getSignature().getName());
    }

    /**
     * 环绕通知
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    //@Around("execution(* com.bjsxt.service.*.*(..))")
    @Around("myPointcut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        System.out.println("Around Before ");
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("Around After");
        return proceed;
    }

    /**
     * 最终通知
     */
   // @After("execution(* com.bjsxt.service.*.*(..))")
    @After("myPointcut()")
    public void myAfter(){
        System.out.println("最终通知");
    }

    /**
     * 异常通知
     * @param e
     */
    //@AfterThrowing(value = "execution(* com.bjsxt.service.*.*(..))",throwing = "e")
    @AfterThrowing(value = "myPointcut()",throwing = "e")
    public void myAfterThrowing(Exception e){
        System.out.println("Exception: "+e);
    }
}
4.2.3.3 配置注解切面
4.2.3.3.1 创建目标对象
package com.bjsxt.service;

public interface UsersService {
    void addUsers(String username);
}
package com.bjsxt.service.impl;

import com.bjsxt.service.UsersService;

public class UsersServiceImpl implements UsersService {
    @Override
    public void addUsers(String username) {
        System.out.println("AddUsers "+username);
    }
}
4.2.3.3.2 开启 aop 命名空间
xmlns:aop="http://www.springframework.org/schema/aop" 
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop.xsd
4.2.3.3.3 配置切面
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

   <!-- 配置目标对象-->
    <bean id="usersService" class="com.bjsxt.service.impl.UsersServiceImpl"/>

    <!--配置切面对象-->
    <bean id="myAspect" class="com.bjsxt.aop.MyAspect"/>
    <!--在AspectJ框架中开启注解处理。声明自动为IOC容器的那些配置了@AspectJ的切面的bean对象创建代理,织入切面。-->
    <!--默认为false:false:使用JDK的Proxy对象创建代理对象。true:使用CGLIB创建代理对象。如果目标对象实现了接口会使用Proxy,如果目标
    对象没有实现接口则自动使用CGLIB创建代理对象。-->
    <aop:aspectj-autoproxy proxy-target-class="false"/>
</beans>
4.2.3.3.4 创建测试类
package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UsersService usersService= (UsersService) applicationContext.getBean("usersService");
        usersService.addUsers("Oldlu");
    }
}
4.2.3.4 多切面以及切面执行顺序的配置
4.2.3.4.1 创建切面
package com.bjsxt.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;

@Aspect //指定当前对象为切面对象
@Order(1)
public class MyAspect2 {

    /**
     * 配置切点
     */
    @Pointcut("execution(* com.bjsxt.service.*.*(..))")
    public void myPointcut(){

    }

    /**
     * 前置通知
     * @param joinPoint
     */
    //@Before("execution(* com.bjsxt.service.*.*(..))")
    @Before("myPointcut()")
    public void myBefore(JoinPoint joinPoint){
        System.out.println("Before2...."+joinPoint.getSignature().getName());
    }

    /**
     * 后置通知
     * @param joinPoint
     */
    //@AfterReturning("execution(* com.bjsxt.service.*.*(..))")
    @AfterReturning("myPointcut()")
    public void myAfterRetuning(JoinPoint joinPoint){
        System.out.println("AfterRetuning2 "+joinPoint.getSignature().getName());
    }

    /**
     * 环绕通知
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    //@Around("execution(* com.bjsxt.service.*.*(..))")
    @Around("myPointcut()")
    public Object myAround(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        System.out.println("Around Before2 ");
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("Around After2");
        return proceed;
    }

    /**
     * 最终通知
     */
   // @After("execution(* com.bjsxt.service.*.*(..))")
    @After("myPointcut()")
    public void myAfter(){
        System.out.println("最终通知2");
    }

    /**
     * 异常通知
     * @param e
     */
    //@AfterThrowing(value = "execution(* com.bjsxt.service.*.*(..))",throwing = "e")
    @AfterThrowing(value = "myPointcut()",throwing = "e")
    public void myAfterThrowing(Exception e){
        System.out.println("Exception: 2"+e);
    }
}
4.2.3.4.2 配置多切面
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

   <!-- 配置目标对象-->
    <bean id="usersService" class="com.bjsxt.service.impl.UsersServiceImpl"/>

    <!--配置切面对象-->
    <bean id="myAspect" class="com.bjsxt.aop.MyAspect"/>
    <bean id="myAspect2" class="com.bjsxt.aop.MyAspect2"/>
    <!--在AspectJ框架中开启注解处理。声明自动为IOC容器的那些配置了@AspectJ的切面的bean对象创建代理,织入切面。-->
    <!--默认为false:false:使用JDK的Proxy对象创建代理对象。true:使用CGLIB创建代理对象。如果目标对象实现了接口会使用Proxy,如果目标
    对象没有实现接口则自动使用CGLIB创建代理对象。-->
    <aop:aspectj-autoproxy proxy-target-class="false"/>
</beans>

Spring实战【下】

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐