Java零基础——Spring篇

1.Spring框架的介绍

1.1 传统的项目的架构

在这里插入图片描述

在传统的项目中,一般遵循MVC开发模型。

(1) view层与用户进行交互,显示数据或者将数据传输给view层。

(2) 在controller层创建service层对象,调用service层中业务方法。

(3) 在service层创建dao层对象,调用dao层中操作数据的方法。

(4) dao层进行具体的数据库操作

1.2 传统的项目架构缺陷

程序在一定程度上存在耦合性,不利于程序的扩展。在controller中直接创建了service层类的对象。如果service的业务发生了变更,那么就需要修改controller层的代码。
在这里插入图片描述

在进行程序的扩展时,不建议在当前程序的基础上直接修改程序,为了保证之前程序的正常,一般遵循开闭原则进行维护性的修改,对扩展开放,对修改关闭。

例如:用户注册功能。用户注册,从账号、密码、手机号等信息即可。随着行业发展,目前要求进行实名认证。

1.已注册未认证用户登录时进行认证。

2.新用户注册后要求进行认证。

为避免对已有业务的改动,可以新建一个service类,重写注册方法。则在controller层需要创建新的service对象。每个相关的controller层的代码都需要改动,并且每个controller都需要创建对象,存在对象的浪费。

面向过程—>面向对象---->面向接口---->面向切面(组件)

ArrayList aList = new ArrayList();

List aList = new LinkedList()

1.3 解决方案

基于每个controller都要修改service的创建问题,可以为service定义一个统一的创建方式,例如对象工厂模式,使用工厂创建对象,这样以后使用工厂创建对象的对象需要维护时,只需要修改对象工厂即可,且可以结合单例模式,对象工厂返回单例,这样优化了对象重复的浪费问题。
在这里插入图片描述

虽然单例工厂能够解决对象的维护和重复问题。但是,随着service层的扩大,工厂也逐渐臃肿,基本每个service会对应一个factory。基于这种情况,则又需要解决工厂臃肿的问题,为此可以利用反射技术,反射可以创建任意类的对象。但是,工厂为保证单例,只能存储的对象只有一个,而controller层需要使用不同的service层对象,为保证对象的有效,且反射性能相对较低,基于这样的情况,则可以定义一个需要创建的对象的清单和一个存储对象的容器,根据清单创建对象,然后将所有创建service对象进行存储,每个controller只需要去容器中获取对象即可,这样既解决了单例问题,也提高了性能。
在这里插入图片描述

1.3.1 代码示例
在这里插入图片描述

1.3.2 对象清单
在这里插入图片描述
在这里插入图片描述

1.3.3 对象容器工厂

package org.springframework.context;



public interface ApplicationContext {



    /**

     * 获取spring容器创建好的对象

     * @param name

     * @return

     */

    Object getBean(String name);



    /**

     * 获取spring容器创建好的对象

     * @param name

     * @return

     */

    <T> T getBean(String name,Class<T> c);



}



package org.springframework.context.support;



import org.dom4j.Document;

import org.dom4j.Element;

import org.dom4j.io.SAXReader;

import org.springframework.context.ApplicationContext;



import java.io.InputStream;

import java.util.HashMap;

import java.util.List;

import java.util.Map;



/**

 * spring的核心类

 */

public class ClassPathXmlApplicationContext implements ApplicationContext {

    /**

     * 用于存放id或者name与某个类对象的映射关系

     */

    private Map<String,Object> objMap = new HashMap<>();



    public ClassPathXmlApplicationContext(){}



    public ClassPathXmlApplicationContext(String xmlPath){

        try {

            //将spring-context.xml中配置的bean对应的类的对象默认全部创建好

            SAXReader reader = new SAXReader();

            InputStream ins = ClassPathXmlApplicationContext.class.getClassLoader().getResourceAsStream(xmlPath);

            Document doc = reader.read(ins);

            //读取xml的根标签

            Element rootElement = doc.getRootElement();

            //拿到beans根标签下的所有bean子标签

            List<Element> childEleList = rootElement.elements();

            for(Element temp : childEleList){

                //读取某个bean标签的id、name、class的属性值

                String id = temp.attributeValue("id");

                String name = temp.attributeValue("name");

                String cls = temp.attributeValue("class");

                Object obj = Class.forName(cls).newInstance();

                //以id做key,拿到class的全路径创建对象作为value

                //将键值对存储到objMap中

                objMap.put(id,obj);

                //拿到name以,切割   以切割多个字符串做key,拿到class的全路径创建对象作为value

                String[] nameAtt = name.split(",");

                for(String strName: nameAtt){

                    objMap.put(strName,obj);

                }

            }

        } catch (Exception e) {

            e.printStackTrace();

        }

    }



    /**

     * 获取spring容器创建好的对象

     * @param name

     * @return

     */

    @Override

    public Object getBean(String name) {

        return objMap.get(name);

    }



    /**

     * 获取spring容器创建好的对象

     * @param name

     * @return

     */

    @Override

    public <T> T getBean(String name, Class<T> c) {

        return (T)objMap.get(name);

    }

}
 

1.3.4 程序相关类
1.3.4.1 test

package com.powernode.test;



import com.powernode.domain.Dog;

import com.powernode.domain.User;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;



public class SelfSpringTest {



    public static void main(String[] args) {

        //启动spring容器

        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");

        User u1 = context.getBean("u1", User.class);

        u1.sleep();

    }



}
 

2.Spring的介绍

2.1 简介

Spring框架是由于软件开发的复杂性而创建的,初衷是为了让软件开发更加简单。Spring使用的是简单的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

Web Service,有2个显著特点:

1.数据格式是xml格式。

2.配置繁琐,“笨重”,对象关联性大,需在配置文件中各种配置。

基于这些原因,Spring框架提出了:IOC/DI(控制反转/依赖注入),AOP(面向切面编程)。

Spring框架可在任何类型的部署平台上为基于Java的现代企业应用程序提供全面的编程和配置模型。Spring的关键元素是在应用程序级别的基础架构支持:Spring专注于企业应用程序的“管道”,以便团队可以专注于应用程序级别的业务逻辑,而不必与特定的部署环境建立不必要的联系。

2.2 Spring的核心组件

在这里插入图片描述

2.2.1 核心容器
核心容器由 spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring 表达式语言,Spring Expression Language)等模块组成,它们的细节如下:

l spring-core 模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。

l spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。

l context 模块建立在由 core和 beans 模块的基础上建立起来的,它以一种类似于 JNDI 注册的方式访问对象。Context 模块继承自 Bean 模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过 Servelet 容器)等功能。Context 模块也支持 Java EE 的功能,比如 EJB、JMX 和远程调用等。ApplicationContext 接口是 Context 模块的焦点。spring-context-support 提供了对第三方库集成到 Spring 上下文的支持,比如缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。

l spring-expression 模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是 JSP2.1 规范中定义的统一表达式语言的扩展,支持 set 和 get 属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从 Spring IoC 容器检索对象,还支持列表的投影、选择以及聚合等。

依赖关系图如下:
在这里插入图片描述

2.2.2 数据访问/集成
数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:

(注:JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service)

l JDBC 模块提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。

l ORM 模块提供了对流行的对象关系映射 API 的集成,包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 spring的其它功能整合,比如前面提及的事务管理。

l OXM 模块提供了对 OXM 实现的支持,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。

l JMS 模块包含生产(produce)和消费(consume)消息的功能。从 Spring 4.1 开始,集成了 spring-messaging 模块。

l 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写 beginTransaction()、commit()、rollback() 等事务管理方法,声明式事务是通过注解或配置由 spring 自动处理,编程式事务粒度更细)

2.2.3 Web
Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:

l Web 模块提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与 web 相关的部分。

l Web-MVC 模块为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。

l Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。

l Web-Portlet 模块提供了用于 Portlet 环境的 MVC 实现,并反映了 spring-webmvc 模块的功能。

2.2.4 其他
还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:

l AOP 模块提供了面向方面(切面)的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。

l Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。

l Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。

l Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。

l 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

3.Spring的IOC的使用 IOC、DI

IOC:控制反转。将对象的创建、初始化、销毁等一系列的生命周期过程交给spring管理。

结婚:

方式1: 自己找女生--------------->吃饭、逛街、看电影、送回家等--------->结婚

(同学、同事、公交地铁1个月-3个月) 半年-1年半 1天

方式2: 媒婆(1个月)------------------------>结婚(1天)

吃饭:

方式1: 买菜、买米(30min-1h)---->蒸饭、洗菜、切菜、炒菜(1个小时)—>吃(15-30min)

方式2: 定外卖----------------->吃(15-30min)

面向过程----->面向对象----->面向接口----->面向组件(面向切面)–>面向服务—>面向百度

3.1 基本使用

3.1.1 创建项目并导入spring IoC相关jar包
在这里插入图片描述

在pom文件中,引入Spring的IoC核心jar包

<!--依赖-->
<dependencies>
    <!--引入spring的context依赖,可以传递出aop beans core expression-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.4</version>
    </dependency>
</dependencies>

3.1.2 创建User类

package com.bjpowernode.domain;

import java.util.Date;

/**
 * Created on 2021/7/16
 *
 * @author 雷哥
 */
public class User {
    private Integer id;
    private String name;
    private Integer age;
    private String address;
    private Date birth;

    public User() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", birth=" + birth +
                '}';
    }
}
 

3.1.3 创建Spring的核心配置文件spring-context.xml/applicationContext.xml

<?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">
    <!-- spring 核心配置文件 配置IOC容器中需要创建的bean -->
    <bean id="userId"  name="user" class="com.bjpowernode.domain.User" />
</beans>

3.1.4 编写测试程序

public class Test {
    public static void main(String[] args) {
        //根据 spring的配置文件 创建 应用容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        System.out.println("马上获取bean");
        //从容器中获取 对象
        User user = (User) context.getBean("user");
        System.out.println(user);
    }
}

3.2 Bean标签属性介绍

3.2.1 id
是 bean的唯一标识 一个bean,其id 值只能有一个 。整个IOC 容器id 值不允许重复,使用名称作为key。

3.2.2 name
一个bean的名称,可以存在多个,多个之间使用逗号分隔。不论bean有没有定义name属性,默认id都会当做name。

3.2.3 class
bean的具体的类型,包名和类名组成。

3.2.4 scope
bean的作用域:如果不写scope,则默认为单例

prototype :非单例,每次获取都会创建一个新的bean对象。

singleton : 单例,多次获取永远同一个bean, 默认值。

request : 一次请求,基于web项目的bean的作用域。

session : 一次会话,基于web项目的bean的作用域。

3.2.5 lazy-init
延迟初始化(懒加载),默认只要加载了配置文件。bean对象就会被初始化,lazy-init则是获取时才会初始化。只针对单例模式有效,非单例每次获取都会创建,没有延迟初始化的意义

3.2.6 depends-on
初始化时依赖的对象,当前对象初始化前需先初始化depends-on指定的对象

3.2.7 init-method
对象初始化后,调用的方法

3.2.8 destroy-method
对象销毁时,调用的方法

3.2.9 autowire
属性自动装配

byName 根据属性名称装配

byType 根据类型装配

3.2.10 autowire-candidate
是否允许作为自动装配的候选项

true 作为自动装配的候选项

false 不作为自动装配的候选项

3.2.11 primary
优先使用该bean,因为Spring需要支持使用类型查找对象,在一个大类型下,可能存在多个小类型。如果根据大类型装配属性时,不知道使用哪个具体的对象,则可以根据primary设置优先级。

3.2.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- spring 核心配置文件 配置IOC容器中需要创建的bean -->
   <!-- <bean id="userId"  name="user" class="com.bjpowernode.domain.User"  />-->
    <!--
        id : bean的唯一标识  整个IOC容器不能重复。
        name : bean的key,多个name之间使用逗号,
        class : 具体的bean的全路径
        scope : bean的作用域
                singleton 单例  默认
                prototype 非单例
        lazy-init="true" 获取时创建对象
        depends-on="test" 默认自上而下创建  depends-on 会优先创建 depends-on 对应的bean
        init-method : 对象创建后调用的方法
        destroy-method :对象销毁时调用的方法, 容器调用close
        autowire : 属性自动装配
                    byName 根据属性名装配
                    byType 根据属性类型装配

        primary :  当存在多个同样的类型时, primary 为true 则优先使用该bean

    -->
    <bean id="userId2" name="user1,user2" class="com.bjpowernode.domain.User" scope="singleton" depends-on="test" init-method="init" destroy-method="destory" primary="true"  />
    <!--  test类 -->
    <bean name="test" class="com.bjpowernode.domain.Test" />

    <bean name="userService1" class="com.bjpowernode.service.impl.UserServiceImpl1" primary="true" />
   <bean name="userService2" class="com.bjpowernode.service.impl.UserServiceImpl2" />
</beans>



package com.bjpowernode.service;

public interface IUserService {
}



package com.bjpowernode.service.impl;

import com.bjpowernode.service.IUserService;

/**
 * @Description: 接口实现类1
 * @author: Mr.T
 * @date 2020-09-26 14:33
 */
public class UserServiceImpl1 implements IUserService {
}



package com.bjpowernode.service.impl;

import com.bjpowernode.service.IUserService;
public class UserServiceImpl2 implements IUserService {
}



package com.bjpowernode.domain;
public class User {

    private Integer id;

    private String name;

    public User(){
        System.out.println("构造方法执行  user 对象进行创建");
    }

    public  void sleep(){
        System.out.println("早睡早起!!!");
    }

    public void init(){
        System.out.println("对象初始化后调用的方法");
    }
    public  void  destory(){
        System.out.println("对象销毁时调用");
    }
}



package com.bjpowernode.test;

import com.bjpowernode.domain.User;
import com.bjpowernode.service.IUserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        //根据 spring的配置文件 创建 应用容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        System.out.println("马上获取bean");
        //从容器中获取 对象
        // 装备对象 : XX   XXX1  XX2   xx3
        User user = (User) context.getBean("user2");//
        System.out.println("21:"+user);
        System.out.println("22:"+context.getBean("user2"));

        //获取接口的类型
        System.out.println(context.getBean(IUserService.class));
        context.close();//关闭容器  此时会调用销毁的方法
    }
}

3.3 Bean对象创建的4种方式

3.3.1 构造方法创建
使用构造方法创建bean对象,是spring默认的创建方式。

<!-- 使用构造方法创建对象 -->
<bean id="user" class="com.bjpowernode.domian.User" />

3.3.2 静态工厂创建

<!-- 使用静态工厂创建对象 -->
<!--
    id : bean 的唯一标识
    class : 工厂类
    factory-method : 工厂方法
 -->
<bean id="user2" class="com.bjpowernode.factory.UserStaticFactory" factory-method="getObj" />



package com.bjpowernode.factory;

import com.bjpowernode.domian.User;

public class UserStaticFactory {
    /**
     * 静态工厂中用于创建对象的方法
     * @return
     */
    public static User getObj(){
        System.out.println("静态工厂中 创建对象的方法 执行了");
        return  new User();
    }
}
 

3.3.3 非静态工厂创建

<!--
    非静态工厂创建对象
        在非静态工厂中,创建对象的方法是非静态方法。非静态方法的执行,首先需要该类对象
        注意: 使用非静态工厂创建对象,首先需要创建工厂类对象
-->
<!-- 工厂类对象 -->
<bean id="userFactory" class="com.bjpowernode.factory.UserFactory" />
<!-- 使用非静态工厂创建对象 -->
<!--
    factory-bean : 非静态工厂对象
    factory-method : 创建对象的非静态方法
-->
<bean id="user3" factory-bean="userFactory" factory-method="getObj" />



package com.bjpowernode.factory;

import com.bjpowernode.domian.User;

public class UserFactory {
    /**
     * 工厂中用于创建对象的方法
     * @return
     */
    public  User getObj(){
        System.out.println("非静态工厂中创建对象的方法 执行了");
        return  new User();
    }
}
 

3.3.4 注解创建
Spring为简化对象的创建方式,提供了注解。

3.3.4.1 组件注解:
3.3.4.1.1 @Component(“bs”)
表示该类为一个被Spring管理的组件。但是,由于在开发中为了让代码的可读性更高。

Spring基于分层思想,将需要创建的组件分为以下几类:

3.3.4.1.2 @Controller
@Controller注解,标识该类是controller层的类。并且,注意在使用SpringMVC时,所有的Constroller,必须使用@Controller注解。

3.3.4.1.3 @Service
@Service注解,标识该类是业务层的类。

3.3.4.1.4 @Respository
@Respository注解,标识该类是操作数据层的类。

注意:

以上注解是Spring中定义的创建对象的注解,都可以创建对象,如果该类有明确的作用,有自己所属的层,则建议使用相应的注解,如果实在无法区分该类所属层,可以使用@Component注解。

3.3.4.2 注解使用步骤
3.3.4.2.1 开启组件扫描
在spring的核心配置文件中,开启注解扫描,让Spring将被注解修饰的类,创建对相关。

xml头部

xmlns:context=“http://www.springframework.org/schema/context”

http://www.springframework.org/schema/context

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

<!--
    开启组件扫描
 -->
<context:component-scan base-package="com.bjpowernode.*" />
 

3.3.4.2.2 添加注解

package com.bjpowernode.domian;

import org.springframework.stereotype.Component;
@Component
public class Person {

    public Person(){
        System.out.println("Person的构造方法.........");
    }
}

3.3.5 什么时候使用XML配置和注解
能使用注解时,就使用了注解,注解非常方便。但是,在第三方的类中,是无法使用注解的。因为无法在别人提供的源码上加上Spring注解,此时只能使用XML配置的形式,配置第三方类的Bean信息。

3.4 IOC属性注入的3种方式

为对象属性设置值,就是属性注入。

3.4.1 构造方法属性注入:DI(依赖注入,给对象的属性赋值)

<?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 class="com.bjpowernode.domain.User" />
        <!--
           有参数的构造方法
                此时是2个参数的构造方法
                index : 参数下标  从 0开始
                value : 属性的值
         -->
        <bean id="user2" class="com.bjpowernode.domain.User" >
            <constructor-arg index="0" value="1001" />
            <constructor-arg index="1" value="韩梅梅" />
        </bean>
        <!-- 有参数的构造方法
                使用index下标查找 属性 存在问题 都只有一个参数 则默认使用后面的构造方法
                可以使用 type 指定参数的类型
                更推荐 使用name属性 : name表示构造器中参数的名称
         -->
        <bean id="user3" class="com.bjpowernode.domain.User">
            <constructor-arg index="0" value="1001" type="java.lang.Integer"  />
        </bean>
        <bean id="user4" class="com.bjpowernode.domain.User">
                <constructor-arg name="name" value="韩梅梅" />
        </bean>
</beans>



package com.bjpowernode.domain;

public class User {

    /**
     *  id 属性
     */
    private Integer id;
    /**
     *  name 属性
     */
    private String name;


    public User(){
        System.out.println("无参数构造方法");
    }

    public User(Integer id) {
        System.out.println("id参数方法");
        this.id = id;
    }

    public User(String name) {
        System.out.println("name参数构造方法");
        this.name = name;
    }

    public User(Integer id, String name) {
        System.out.println("id,name参数构造方法");
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
 

3.4.2 set方法属性注入

<?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">
         <!--
           使用set方法进行属性注入
            property 表示属性
                name : 表示属性对应的set方法名,去掉set前缀,首字母小写。并不是真正的属性名
         -->
        <bean id="dg" class="com.powernode.pojo.Dog">
    <property name="sonList">
        <list>
            <value>小黑</value>
            <value>小白</value>
            <value>小花</value>
        </list>
    </property>
    <property name="wifeList">
        <set>
            <value>小翠儿</value>
            <value>如花</value>
        </set>
    </property>
    <property name="friendMap">
        <map>
            <entry key="uName1" value="土狗"></entry>
            <entry key="uName2" value="泰迪"></entry>
            <entry key="uName3" value-ref="u1"></entry>
        </map>
    </property>
    <property name="props">
        <props>
            <prop key="strain">土狗</prop>
            <prop key="age">15</prop>
            <prop key="gender"></prop>
        </props>
    </property>
</bean>


</beans>
 

3.4.3 注解属性注入
在spring中,为了简化属性的注入,Spring提供注解:@Autowired,Spring会自动从IOC容器中,为这个属性查找相应类型的值,进行注入。

  1. 开启包的注解扫描
    <context:component-scan base-package=“com.*” />

  2. 使用注解

package com.bjpowernode.domain;

import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;
public class Student {

    public Integer id;

    public String name;

    @Autowired  //使用注解自动注入
    //User 对象
    public User user;
    public void setStudentId(Integer id) {
        System.out.println("set方法被调用了............");
        this.id = id;
    }
 /*   public void setUser(User user) {
        this.user = user;
    }*/
}

注意:

在使用自动注入时,可以在bean标签上,配置autowire,但是此时必须有该属性的set方法,@Autowired注解,是不需要set方法的。

如果是在xml中注入对象,值使用ref属性。value属性,只支持boolean,数字,字符串等。

3.5 常见类型的属性注入

在Spring中,提供了丰富的标签,进行各种属性的注入。常见的类型:

数字、字符串、boolean、数组、set、list、map、properties。

package com.bjpowernode.domain;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class Person {

    private Integer id;

    private String name;

    private boolean sex;// true  男 false 女

    private String[] likes;//爱好

    private Set<String> girlFriends; //女朋友

    private List<Dream> dreams;//梦想

    private Map<String,String> house; //房子

    private Properties properties; //配置文件属性

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean getSex() {
        return sex;
    }

    public void setSex(boolean sex) {
        this.sex = sex;
    }

    public String[] getLikes() {
        return likes;
    }

    public void setLikes(String[] likes) {
        this.likes = likes;
    }

    public Set<String> getGirlFriends() {
        return girlFriends;
    }

    public void setGirlFriends(Set<String> girlFriends) {
        this.girlFriends = girlFriends;
    }

    public List<Dream> getDreams() {
        return dreams;
    }

    public void setDreams(List<Dream> dreams) {
        this.dreams = dreams;
    }

    public Map<String, String> getHouse() {
        return house;
    }

    public void setHouse(Map<String, String> house) {
        this.house = house;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

package com.bjpowernode.domain;

public class Dream {

    private String title;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}



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



    <!-- 简单的属性注入 : 基本数据类型 + string -->
    <bean id="person1" class="com.bjpowernode.domain.Person" >
        <!-- Integer 类型的属性注入 -->
        <property name="id" value="1001" />
        <!-- String 类型的属性注入 -->
        <property name="name" value="佚名" />
        <!-- boolean 属性注入 -->
        <property name="sex"  value="true" />
    </bean>
    <!-- 数组类型 -->
    <bean id="person2" class="com.bjpowernode.domain.Person" >
        <property name="likes" >
            <array>
                <value>足球</value>
                <value>篮球</value>
                <value>羽毛球</value>
            </array>
        </property>
    </bean>
    <!--  set 类型注入 -->
    <bean id="person3" class="com.bjpowernode.domain.Person" >
        <property name="girlFriends" >
           <set>
                <value>韩梅梅</value>
                <value>Lucy</value>
                <value>Lucy</value>
                <value>Rose</value>
           </set>
        </property>
    </bean>
    <bean id="dream1" class="com.bjpowernode.domain.Dream">
        <property name="title" value="数钱数到手抽筋" />
    </bean>
    <!-- list 类型 -->
    <bean id="person4" class="com.bjpowernode.domain.Person" >
        <property name="dreams" >
            <list>
                <bean class="com.bjpowernode.domain.Dream">
                    <property name="title" value="解放全人类" />
                </bean>
                <bean class="com.bjpowernode.domain.Dream">
                    <property name="title" value="世界和平" />
                </bean>
                <ref bean="dream1"/>
            </list>
        </property>
    </bean>

    <!-- map结构   -->
    <bean id="person5" class="com.bjpowernode.domain.Person" >
        <property name="house" >
            <map>
                <entry key="wh" value="江滩" />
                <entry key="bj" value="后海" />
                <entry key="hz" value="西湖" />
            </map>
        </property>
    </bean>

    <!-- properties  -->
    <bean id="person6" class="com.bjpowernode.domain.Person" >
        <property name="properties" >
           <props>
               <prop key="driver">驱动</prop>
               <prop key="url">url</prop>
           </props>
        </property>
    </bean>
</beans>



package com.bjpowernode.test;

import com.bjpowernode.domain.Dream;
import com.bjpowernode.domain.Person;
import com.bjpowernode.domain.Student;
import com.bjpowernode.domain.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;
import java.util.List;
import java.util.Properties;

public class Test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        Person person1 = (Person) context.getBean("person1");
        System.out.println(person1.getId() +"  "+ person1.getName() + " "+ person1.getSex() );
        Person person2 = (Person) context.getBean("person2");
        String[] likes = person2.getLikes();
        System.out.println(Arrays.asList(likes));
        Person person3= (Person) context.getBean("person3");
        System.out.println(person3.getGirlFriends());

        Person person4 = (Person) context.getBean("person4");
        List<Dream> dreams = person4.getDreams();
        System.out.println(dreams.get(0).getTitle());
        System.out.println(dreams.get(1).getTitle());
        System.out.println(dreams.get(2).getTitle());

        Person person5 = (Person) context.getBean("person5");
        System.out.println(person5.getHouse());

        Person person6 = (Person) context.getBean("person6");
        Properties properties = person6.getProperties();
        System.out.println(properties.getProperty("driver"));
        System.out.println(properties.getProperty("url"));
    }
}

3.6 使用IOC容器,改造传统项目

3.6.1 xml配置版
3.6.1.1 创建项目并加入依赖
在这里插入图片描述

<!--依赖-->
<dependencies>
    <!--引入spring的context依赖,可以传递出aop beans core expression-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.4</version>
    </dependency>
</dependencies>

3.6.1.2 项目结构
在这里插入图片描述

3.6.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">
    <!-- 声明  com.bjpowernode.dao 对象 -->
    <bean id="userDao" class="com.bjpowernode.dao.UserDao" />
    <!-- 声明service 对象 -->
    <bean id="userService" class="com.bjpowernode.service.impl.UserServiceImpl" autowire="byType">
        <!-- 使用自动装配 则不需要 声明属性注入 但是要有set方法 -->
        <!--<property name="userDao" ref="userDao" />-->
    </bean>

    <!-- 声明controller -->
    <bean id="userController" class="com.bjpowernode.controller.UserController" autowire="byType">
        <!-- 使用自动装配 则不需要 声明属性注入 但是要有set方法-->
        <!--<property name="userService" ref="userService"/>-->
    </bean>
</beans>
 

3.6.1.4 controller

package com.bjpowernode.controller;

import com.bjpowernode.service.IUserService;

public class UserController {
    private IUserService userService;
    public void register(){
        System.out.println("控制层的   register  方法");
        userService.register();
    }
    public void setUserService(IUserService userService) {
        this.userService = userService;
    }
}
 

3.6.1.5 dao

package com.bjpowernode.dao;
public class UserDao {
    public void add(){
        System.out.println("进行数据库数据新增操作");
    }
}
 

3.6.1.6 service

package com.bjpowernode.service;

public interface IUserService {
    /**
     * 注册接口
     */
    public void register();
}



package com.bjpowernode.service.impl;

import com.bjpowernode.dao.UserDao;
import com.bjpowernode.service.IUserService;

public class UserServiceImpl implements IUserService {
    /**
     * com.bjpowernode.dao 层 属性
     */
    private UserDao userDao;

    @Override
    public void register() {
        System.out.println("com.bjpowernode.service 的 register ");
        userDao.add();
    }
    /**
     *  使用set方法 是为了自动装配 或者进行set 属性设置
     * @param userDao
     */
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}
 

3.6.1.7 test

package com.bjpowernode;
import com.bjpowernode.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        UserController bean = context.getBean(UserController.class);
        bean.register();
    }
}

3.6.2 注解版
3.6.2.1 配置文件

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

    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.*" />
</beans>
 

3.6.2.2 controller

package com.bjpowernode.controller;

import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {

    @Autowired
    private IUserService userService;

    public void register(){
        System.out.println("控制层的   register  方法");
        userService.register();
    }
}
 

3.6.2.3 dao

package com.bjpowernode.dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {

    public void add(){
        System.out.println("进行数据库数据新增操作");
    }
}
 

3.6.2.4 service

package com.bjpowernode.service;

public interface IUserService {
    /**
     * 注册接口
     */
    public void register();
}



package com.bjpowernode.service.impl;

import com.bjpowernode.dao.UserDao;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements IUserService {
    /**
     * com.bjpowernode.dao 层 属性
     */
    @Autowired
    private UserDao userDao;

    @Override
    public void register() {
        System.out.println("com.bjpowernode.service 的 register ");
        userDao.add();
    }
}
 

3.6.2.5 test

package com.bjpowernode.test;


import com.bjpowernode.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        //UserController bean = context.getBean(UserController.class);
        //bean.register();
        //程序员自己创建的对象  不在IOC 自己容器中
        //new UserController().register();
    }
}

4.AOP

com.powernode.aadenglu

Login: login():登录方法

com.powernode.anquan

Security: isSecurity():检测操作环境是否安全

com.powernode.bmapper

CBCBankMapper(核心类): selectMoney() updateMoney() updateInvest() update2Tel()

com.powernode.crizhi

Logger: log():记录用户操作细节

com.powernode.dqinli

Clean :cleanResource():清理缓存

Expt: handExpt()

4.1 AOP简介:面向切面(面向组件)

DefaultAopProxyFactory

代理

静态代理

静态代理,每个被代理类都需要创建对应的代理类。随着程序的扩展,代理类也会增多,臃肿,维护量变多,为了解决这个问题,Java中,提供了动态代理技术,开发者不需要自己定义代理类,代理类由JDK动态的创建,开发只需要指定被代理的类即可。

切面(aspect):除了核心类以外的其他类称之为切面

通知(advisor):切面中的方法称之为通知

核心类:一个项目中不能省略的模块类

核心方法:核心类中的方法称之为核心方法

连接点:核心类中的某一个方法

切入点(pointcut):某个包下的某个类下的某一批方法

代理(proxy):将多个切面与核心类组合在一起,形成一个新的类,这个类称之为代理类

织入(weaver):书写代理类的过程称之为织入

4.2 动态代理

4.2.1 JDK动态代理
4.2.1.1 Proxy
该类提供了方法创建代理类和代理类的对象的方法

创建一个代理类并返回代理类对象

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

loader : 类加载器,指定类加载器,是为了精确的定位类

interfaces : 接口Class类,使用JDK的反射,必须要有接口

h :InvocationHandler ,代理的处理器,每个代理类都有一个关联的处理器

4.2.1.2 InvocationHandler
是每个代理类对应的处理器

Object 方法调用的返回值,可以作为被代理的方法调用的返回值

proxy : 代理类对象

method : 目标类中被代理的方法

args : 目标类中被代理的方法的运行参数

Object invoke(Object proxy,Method method,Object[] args)

4.2.1.3 代码示例
4.2.1.3.1 目标类接口

package com.bjpowernode.proxy.demo02;

/**
 * @Description: 目标类接口
 * @author: Mr.T
 * @date 2020-09-27 10:38
 */
public interface ITargetClass {

    /**
     * 房子出租
     * @param m
     */
    void rent(int m);
}

4.2.1.3.2 目标类

package com.bjpowernode.proxy.demo02;

/**
 * @Description: 目标类
 * @author: Mr.T
 * @date 2020-09-27 10:39
 */
public class TargetClass implements ITargetClass {

    @Override
    public void rent(int m) {
        System.out.println("出租的金额为:" + m);
    }
}

4.2.1.3.3 代理类处理器

package com.bjpowernode.proxy.demo02;

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

/**
 * @Description: 代理的处理器
 *              处理器会被绑定一个代理
 *              帮助代理调用目标方法
 * @author: Mr.T
 * @date 2020-09-27 10:40
 */
public class ProxyHanlder implements InvocationHandler {
    /**
     *  目标方法类的对象
     */
    private Object targetObj;


    public ProxyHanlder(Object targetObj){
        this.targetObj = targetObj;
    }

    /**
     *
     * @param proxy  生成的代理类的对象
     * @param method  目标类中被代理的方法
     * @param args    目标类中被代理的方法实际参数
     * @return      可以当做目标方法的返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //使用反射调用 目标类中的方法
        Object obj = method.invoke(targetObj, args);
        return obj;
    }
}

4.2.1.3.4 测试类

package com.bjpowernode.proxy.demo02;

import java.lang.reflect.Proxy;

/**
 * @Description: TODO
 * @author: Mr.T
 * @date 2020-09-27 10:45
 */
public class Test {

    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        //创建了目标类对象
        ITargetClass targetClass = new TargetClass();
        //创建处理器
        ProxyHanlder proxyHanlder = new ProxyHanlder(targetClass);
        //创建具体的代理类和对象 具体产生的代理类  会实现 接口 所以能够转化为 接口类型
        ITargetClass proxy = (ITargetClass) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{ITargetClass.class}, proxyHanlder);
        // 调用代理类中  rent方法 $proxy0
        proxy.rent(100);

    }
}
 

4.2.1.3.5 生成代理类源码

package com.bjpowernode.proxy.demo02;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.UndeclaredThrowableException;

/**
 * @Description: 动态代理生成的代理类
 *      Proxy : JDK中所有生成的代理的父类
 *      ITargetClass : 指定被代理类的接口
 *
 * @author: Mr.T
 * @date 2020-09-27 10:59
 */
public final class $Proxy0 extends Proxy implements ITargetClass
{
    private static Method m0; //hashCode 方法
    private static Method m1; // equals
    private static Method m2; //toString
    private static Method m3; // rent 方法  被代理的方法


    static {
        try {
            $Proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);
            $Proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            $Proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);
            $Proxy0.m3 = Class.forName("com.bjpowernode.proxy.demo02.ITargetClass").getMethod("rent", Integer.TYPE);
        }
        catch (NoSuchMethodException ex) {
            throw new NoSuchMethodError(ex.getMessage());
        }
        catch (ClassNotFoundException ex2) {
            throw new NoClassDefFoundError(ex2.getMessage());
        }
    }

    /**
     *  invocationHandler 就是定义的 invocationHandler
     * @param invocationHandler
     */
    public $Proxy0(final InvocationHandler invocationHandler) {
        super(invocationHandler); //Proxy(InvocationHandler invocationHandler) --> 为父类中 InvocationHandler 赋值
        //当前类中 InvocationHandler 对象  且有值
        /*
       Proxy(InvocationHandler h) {
            Objects.requireNonNull(h);
            this.h = h;
        }
        * */
    }

    public final boolean equals(final Object o) {
        try {
            return (boolean)super.h.invoke(this, $Proxy0.m1, new Object[] { o });
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    public final String toString() {
        try {
            return (String)super.h.invoke(this, $Proxy0.m2, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    public final void rent(final int n) {
        try {
            //super.h   this.h   ---> 自定义的  ProxyHanlder
            //调用自定义的ProxyHanlder 中的invoke方法   : $Proxy0 对象
            //$Proxy0.m3  rent 方法
            //new Object[] { n } 传入的参数
            super.h.invoke(this, $Proxy0.m3, new Object[] { n });
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }

    public final int hashCode() {
        try {
            return (int)super.h.invoke(this, $Proxy0.m0, null);
        }
        catch (Error | RuntimeException error) {
            throw;
        }
        catch (Throwable t) {
            throw new UndeclaredThrowableException(t);
        }
    }
}

4.2.1.3.6 JDK动态代理的不足
在JDK中使用动态代理,必须有类的接口。因为生成的代理需要实现这个接口,这样我们生成的代理类对象,才能转化为代理目标的接口对象,然后根据接口中的方法,调用处理器中invoke方法。
在这里插入图片描述

4.2.2 Cglib动态代理
为了弥补JDK动态代理的不足,第三方组织封装一套工具包,cglib的工具包,这套包不基于接口,基于父子继承,通过重写的形式扩展方法,但是这个子类工具自动生成的。

早期,Cglib动态代理,性能相于JDK的动态代理高一些。JDK进行一些列优化,目前Spring默认使用的动态代理JDK,也支持Cglib。

4.2.2.1 Cglib动态代理的使用
4.2.2.1.1 MethodInterceptor
cglib中,提供的对方法执行拦截的接口。其中intercept是对具体方法进行拦截处理的方法。

public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,

                           MethodProxy proxy)

Object : 方法执行返回的结果

obj :增强类的对象

method :目标方法

proxy :用于回调的方法的对象

4.2.2.1.2 代码示例
4.2.2.1.2.1 导入jar包

<!-- 引入cglib 的jar 包-->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

4.2.2.1.2.2 创建被代理目标类

package com.bjpowernode.proxy.demo03;

/**
 * @Description: 被代理的目标类
 * @author: Mr.T
 * @date 2020-09-27 14:13
 */
public class TargetClass {

    public  void rent(){
        System.out.println("目标类中的出租方法");
    }
}
 

4.2.2.1.2.3 方法拦截器

package com.bjpowernode.proxy.demo03;

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

import java.lang.reflect.Method;

/**
 * @Description: 方法执行的拦截器
 * @author: Mr.T
 * @date 2020-09-27 14:20
 */
public class MyMethodInteceptor implements MethodInterceptor {
    /**
     *  进行具体的拦截的方法
     * @param obj     被代理类的对象
     * @param method  被代理的目标方法
     * @param args  实际运行的参数
     * @param proxy 代理类对象
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("前置增强");
        //代理 调用父类中的方法
        Object o = proxy.invokeSuper(obj, args);
        System.out.println("intercept  执行了");//执行了
        System.out.println("后置增强");
        return o ;
    }
}
 

4.2.2.1.2.4 测试类

package com.bjpowernode.proxy.demo03;

import net.sf.cglib.proxy.Enhancer;

/**
 * @Description: TODO
 * @author: Mr.T
 * @date 2020-09-27 14:21
 */
public class Test {

    public static void main(String[] args) {
        //增强类工具  可以创建代理类对象
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(TargetClass.class);
        //设置调用时 回调
        enhancer.setCallback(new MyMethodInteceptor());
        //创建代理类对象
        TargetClass proxy = (TargetClass) enhancer.create();
        proxy.rent();
    }
}
 

4.2.2.2 动态代理的不足
不论是JDK的动态代理,还是第三方cglib动态代理,都需要开发者编写代码处理程序。程序结构基本上大同小异,重复造轮子。基于这样的情况,在Spring中,提供了2种方式:xml配置形式和注解形式,使用动态代理。这种模式就是Spring Aop技术。其底层依然是动态代理。

4.3 Spring的AOP配置

在Spring中,AOP的配置主要分为2类:xml配置和注解配置

XML配置也分为两种,一种Spring的原生支持,一种是Spring的aspects这个相关的框架。

4.3.1 AOP的相关概念
连接点(JoinPoint):所谓连接点是指那些被拦截的点,而spring中这些点就是指方法,因为spring只支持方法类型的连接点。

切入点(PointCut):所谓切入点就是指我们要对那些JoinPoint进行拦截的定义,指的是具体的拦截的位置

增强/通知(Advice) : 增强就是对具体的连接点进行扩展的功能。由于一般对方法进行增强,分为在方法前执行或者方法后,或者发生异常执行等等,所以增强被分为:前置增强(前置通知)、后置增强(后置通知)、环绕通知(环绕增强)、异常增强(异常通知)

引介(Introduction):引介是一种特殊的Advice,在不修改代码的前提下,引介可以在运行期为类动态的添加一些方法或Field.

目标(Target) :被代理的类(需要增强类)

织入(Weaving) :把Advice应用到Target的过程

代理(Proxy):使用AOP配置后产生的代理类

切面(Aspect):切点和增强整合形成了切面
在这里插入图片描述

4.3.2 Spring自身AOP具体配置
4.3.2.1 引入aop相关jar包

<?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>org.example</groupId>
    <artifactId>02-spring-aop01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.2.0.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>

    </dependencies>


</project>
 

4.3.2.2 定义增强类
4.3.2.2.1 前置增强-MethodBeforeAdvice

package com.bjpowernode.advice;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
 * @Description: spring 规定的增强方法接口
 * @author: Mr.T
 * @date 2020-09-27 15:42
 */
public class MyBeforeAdvice implements MethodBeforeAdvice {

    /**
     *
     * @param method  目标方法
     * @param args   实际运行的参数
     * @param target  目标类对象
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置增强的方法");
    }
}

4.3.2.2.2 后置增强-AfterReturningAdvice

package com.bjpowernode.advice;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

/**
 * @Description: 后置增强接口
 * @author: Mr.T
 * @date 2020-09-27 15:55
 */
public class MyAfterAdvice implements AfterReturningAdvice {

    /**
     *
     * @param returnValue 被增强的方法运行后返回的数据
     * @param method     被增强的方法
     * @param args      方法运行的参数
     * @param target       目标类对象
     * @throws Throwable
     */
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("后置增强方法");
    }
}

4.3.2.2.3 环绕增强-MethodInterceptor

package com.bjpowernode.advice;


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

/**
 * @Description: 环绕增强
 * @author: Mr.T
 * @date 2020-09-27 16:04
 */
public class MyAroundAdvice implements MethodInterceptor {


    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("前置增强");
        Object rs = invocation.proceed();//调用 目标方法
        System.out.println("后置增强");
        return rs;
    }
}
 

4.3.2.2.4 异常增强-ThrowsAdvice
异常增强中的增强方法必须叫:afterThrowing,并且必须定义参数接收发生的异常信息。

package com.bjpowernode.advice;

import org.springframework.aop.ThrowsAdvice;

/**
 * @Description: 异常增强类
 * @author: Mr.T
 * @date 2020-09-27 16:12
 */
public class MyExceptionAdvice implements ThrowsAdvice {

    public void afterThrowing(Exception ex){
        System.out.println("异常增强的方法!!!!!!");
    }
}
 

4.3.2.3 目标类

package com.bjpowernode;

public interface ITargetClass {
    /**
     * 待增强的目标方法
     */
    void targetMethod();

    /**
     * 待增强的方法
     * @param msg
     * @return
     */
    String afterTargetMethod(String msg);

    /**
     * 环绕增强的方法
     */
    void aroundTargetMethod();

    /**
     *  执行会发生异常
     */
    void runException();
}



package com.bjpowernode.impl;

import com.bjpowernode.ITargetClass;

/**
 * @Description: 目标类
 * @author: Mr.T
 * @date 2020-09-27 15:38
 */
public class TargetClassImpl implements ITargetClass {
    @Override
    public void targetMethod() {
        System.out.println("待增强的目标方法");
    }

    @Override
    public String afterTargetMethod(String msg) {
        System.out.println("待增强的目标方法 --- afterTargetMethod");
        return "被增强的方法的返回值";
    }


    public void aroundTargetMethod() {
        System.out.println("待增强的目标方法 --- aroundTargetMethod");
    }

    /**
     * 发生异常
     */
    public void runException() {
        System.out.println("待增强的目标方法 --- runException");
        int m = 0;
        int n = 100/m;
    }


}
 

4.3.2.4 aop配置

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

    <!-- 定义目标类对象 -->
    <bean id="targetClass" class="com.bjpowernode.impl.TargetClassImpl" />
    <!-- 定义增强类对象 前置增强类 -->
    <bean id="myBeforeAdvice" class="com.bjpowernode.advice.MyBeforeAdvice" />
    <!-- 定义增强类对象  后置增强 -->
    <bean id="myAfterAdvice" class="com.bjpowernode.advice.MyAfterAdvice" />
    <!-- 定义增强类 环绕增强 -->
    <bean id="myAroundAdvice" class="com.bjpowernode.advice.MyAroundAdvice" />
    <!-- 定义增强类  异常增强类 -->
    <bean id="myExceptionAdvice" class="com.bjpowernode.advice.MyExceptionAdvice" />
    <!-- 进行织入 -->
    <aop:config>
        <!--
            id : 连接点的唯一标识
            expression : 连接点的表达式
                execution(* 包名.类名.方法名(..))
                * 指任意字符
                .. 表示参数可以是任意个
        -->
        <aop:pointcut id="beforePoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.targetMethod(..))"/>
        <!-- 后置增强的切点 -->
        <aop:pointcut id="afterPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.afterTargetMethod(..))"/>
        <!-- 环绕增强的切点 -->
        <aop:pointcut id="aroundPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.aroundTargetMethod(..))"/>
        <!-- 异常增强的切点 -->
        <aop:pointcut id="exceptionPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.runException(..))"/>
        <!--
            织入
            将增强和连接点 结合
        -->
        <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="beforePoint" />

        <!-- 织入
            后置增强的织入
         -->
        <aop:advisor advice-ref="myAfterAdvice" pointcut-ref="afterPoint" />

        <!--
            织入
            环绕增强的织入
        -->
        <aop:advisor advice-ref="myAroundAdvice"  pointcut-ref="aroundPoint" />

        <!--
          织入
          异常增强的织入
      -->
        <aop:advisor advice-ref="myExceptionAdvice"  pointcut-ref="exceptionPoint" />
    </aop:config>

</beans>

4.3.2.5 测试类

package com.bjpowernode;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        ITargetClass targetClass = context.getBean(ITargetClass.class);
        targetClass.runException();
    }
}
 

4.3.3 AspectJ框架AOP配置
在原生的spring中,每种增强都需要单独定义一个类实现相应的接口。增强类本身就更庞大,而且方法的名称是固定的。基于这种情况,AspectJ提供了相对更加灵活的方式。

在AspectJ中,只需要定义一个增强类即可,并且方法的名称可以任意定义。

4.3.3.1 引入相关jar

<?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>org.example</groupId>
    <artifactId>02-spring-aop02</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.2.0.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>

    </dependencies>
</project>
 

 

4.3.3.2 编写增强类

package com.bjpowernode.advice;

import org.aopalliance.intercept.Invocation;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAdvice {

    public void beforAdvice(){
        System.out.println("前置增强的方法");
    }

    public void afterAdvice(String name,String rs){
        System.out.println("后置增强的方法");
    }

    public void aroundAdvice(ProceedingJoinPoint joinPoint){
        System.out.println("前置增强");
        try {
            joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("后置增强");
    }

    /**
     * 异常增强
     * @param exception
     */
    public  void exceptionAdvice(Exception exception){
        System.out.println("异常增强!");
    }
}
 

4.3.3.3 编写目标类

package com.bjpowernode;

public interface ITargetClass {

    /**
     * 前置增强的方法
     */
    void  beforeMethod();

    /**
     * 后置增强的方法
     */
    String afterMethod(String name1);

    /**
     * 环绕增强的方法
     */
    void aroundMethod();

    /**
     * 异常增的方法
     */
    void runExceptionMethod();
}



package com.bjpowernode.impl;

import com.bjpowernode.ITargetClass;

public class TargetClassImpl  implements ITargetClass {

    @Override
    public void beforeMethod() {
        System.out.println("待前置增强--------beforeMethod");
    }

    @Override
    public String afterMethod(String name) {
        System.out.println("待后置增强--------afterMethod");
        return  "韩梅梅";
    }

    @Override
    public void aroundMethod() {
        System.out.println("待环绕增强--------aroundMethod");
    }

    @Override
    public void runExceptionMethod() {
        System.out.println("待异常增强--------runExceptionMethod");
        int m = 0;
        int n = 100/m;
    }
}
 

4.3.3.4 配置AspectJ的增强配置

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

    <!-- 定义增强的目标类对象 -->
    <bean id="targetClass" class="com.bjpowernode.impl.TargetClassImpl" />
    <!-- 定义增强类的对象 -->
    <bean id="myAdvice" class="com.bjpowernode.advice.MyAdvice" />

    <!-- 进行AOP配置 -->
    <aop:config>
        <!-- 前置切点 -->
        <!--
              aop:before : aspectJ中 前置增强的配置
               method : 当前增强类中前置增强的方法  方法名
               pointcut-ref : 增强连接点
           -->
        <aop:pointcut id="beforPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.beforeMethod(..)) " />
        <!-- 后置切点 -->
        <!-- args 配置被增强的方法的参数名称 -->
        <aop:pointcut id="afterPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.afterMethod(..)) and args(name)"   />
        <!-- 环绕切点 -->
        <aop:pointcut id="aroundPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.aroundMethod(..))"  />
        <!-- 异常切点 -->
        <aop:pointcut id="exceptionPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.runExceptionMethod(..))" />

        <aop:aspect ref="myAdvice">
          <!--  <aop:before method="beforAdvice" pointcut-ref="beforPoint" />-->
            <!--
                arg-names :后置增强中增强的方法的参数名称
                    注意: name 也是被增强的方法的参数名称 参数名称要一致
                returning :返回结果的参数名称
            -->
           <aop:after-returning method="afterAdvice" pointcut-ref="afterPoint" arg-names="name,rs"   returning="rs" />

            <!--<aop:around method="aroundAdvice" pointcut-ref="aroundPoint"  />-->
             <!--
                 throwing : 接收异常参数的名称
             -->
           <aop:after-throwing method="exceptionAdvice" pointcut-ref="exceptionPoint" throwing="exception"  />
        </aop:aspect>
    </aop:config>

</beans>
 

4.3.3.5 进行测试

package com.bjpowernode;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        ITargetClass bean = context.getBean(ITargetClass.class);
        bean.runExceptionMethod();

    }
}

4.3.4 AspectJ的AOP注解方式
4.3.4.1 引入相关jar包

<?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>org.example</groupId>
    <artifactId>02-spring-aop3</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.2.0.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>

    </dependencies>
</project>

4.3.4.2 定义增强类

package com.bjpowernode.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAdvice {

    @Before(value = "execution(* com.bjpowernode.impl.TargetClassImpl.beforeMethod(..))")
    public void beforAdvice(){
        System.out.println("前置增强的方法");
    }
    /*
    *args 被增强的方法的参数名称
    * argNames  增强方法的参数名称
    *  参数名称必须一致
    * returning 参数名称
    * */
    @AfterReturning(value="execution(* com.bjpowernode.impl.TargetClassImpl.afterMethod(..)) && args(name)",argNames = "name,rs" ,returning = "rs" )
    public void afterAdvice(String name,String rs){
        System.out.println("后置增强的方法");
    }

    @Around(value="execution(* com.bjpowernode.impl.TargetClassImpl.aroundMethod(..))")
    public void aroundAdvice(ProceedingJoinPoint joinPoint){
        System.out.println("前置增强");
        try {
            joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("后置增强");
    }

    /**
     * 异常增强
     * @param exception
     */
    @AfterThrowing(value="execution(* com.bjpowernode.impl.TargetClassImpl.runExceptionMethod(..))",throwing = "exception" )
    public  void exceptionAdvice(Exception exception){
        System.out.println("异常增强!");
    }
}
 

4.3.4.3 目标类

package com.bjpowernode;

public interface ITargetClass {

    /**
     * 前置增强的方法
     */
    void  beforeMethod();

    /**
     * 后置增强的方法
     */
    String afterMethod(String name);

    /**
     * 环绕增强的方法
     */
    void aroundMethod();

    /**
     * 异常增的方法
     */
    void runExceptionMethod();
}



package com.bjpowernode.impl;

import com.bjpowernode.ITargetClass;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
public class TargetClassImpl  implements ITargetClass {

    @Override
    public void beforeMethod() {
        System.out.println("待前置增强--------beforeMethod");
    }

    @Override
    public String afterMethod(String name) {
        System.out.println("待后置增强--------afterMethod");
        return  "韩梅梅";
    }

    @Override
    public void aroundMethod() {
        System.out.println("待环绕增强--------aroundMethod");
    }

    @Override
    public void runExceptionMethod() {
        System.out.println("待异常增强--------runExceptionMethod");
        int m = 0;
        int n = 100/m;
    }
}
 

4.3.4.4 开启相关注解

<?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"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.*" />
    <!-- 开启aspectj 的相关注解 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

4.3.4.5 测试类

package com.bjpowernode;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        ITargetClass bean = context.getBean(ITargetClass.class);
        bean.runExceptionMethod();
    }
}

5.Spring整合Mybatis

Spring整合Mybatis就是将Mybatis交给Spring进行管理,将Mybatis的SqlSession对象,放入IOC容器中,并且可以利用自动装配功能,为每个数据库操作层,注入SqlSession。并且Spring内置可以有代理的,可以根据SqlSession对象及数据操作接口,创建Mapper接口的代理对象,此时Mapper的代理在IOC容器中,那么可以将Mapper接口的对象注入到Service中。

5.1 多XML版

使用配置文件版本,Mybatis配置文件和Spring配置文件是单独的。

5.1.1 引入相关jar包
5.1.1.1 spring相关jar包

<!-- spring相关jar包  开始 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!-- spring相关jar包  结束 -->

5.1.1.2 mybatis相关jar包

<!-- mybatis核心包  开始-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>
<!-- mybatis核心包  结束-->

5.1.1.3 数据库相关jar包

<!-- mysql jdbc 数据库包 开始 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>
<!-- mysql jdbc 数据库包 结束 -->

5.1.1.4 日志相关jar包

<!-- 日志相关jar包  开始 -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.13.3</version>
</dependency>
<!-- 日志相关jar包  结束 -->

5.1.1.5 spring和mybatis整合包

<!-- spring和 mybatis 整合包 开始   -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.4</version>
</dependency>
<!-- spring和 mybatis 整合包  结束-->

5.1.1.6 mybatis分页插件包

<!-- mybatis分页插件包   开始-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.0</version>
</dependency>
<!-- mybatis分页插件包   结束-->

5.1.2 相关类

5.1.2.1 domain

package com.bjpowernode.domain;

public class User {

    private Integer id;

    private  String username;

    private String password;

    private String realname;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRealname() {
        return realname;
    }

    public void setRealname(String realname) {
        this.realname = realname;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", realname='" + realname + '\'' +
                '}';
    }
}

5.1.2.2 mapper

package com.bjpowernode.mapper;

import com.bjpowernode.domain.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface UserMapper {
    /**
     * 根据ID 查询用户
     * @param id
     * @return
     */
    User selectById(@Param("id") Integer id);

    /**
     * 查询所有
     * @return
     */
    List<User> selectAll();
}
 

5.1.2.3 service

package com.bjpowernode.service;

import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;

public interface IUserService {
    User queryUser(Integer id);
    PageInfo<User> queryPage(Integer page,Integer limit);
}



package com.bjpowernode.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.mapper.UserMapper;
import com.bjpowernode.service.IUserService;

public class UserServiceImpl implements IUserService {
    private UserMapper  userMapper;
    @Override
    public User queryUser(Integer id) {
        return userMapper.selectById(id);
    }
    @Override
    public PageInfo<User> queryPage(Integer page,Integer limit) {
        Page<User> users = PageHelper.startPage(page, limit);
        userMapper.selectAll();
        return users.toPageInfo();
    }
    /**
     * 使用xml形式注入 mapper
     * @param userMapper
     */
    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
}
 

5.1.2.4 测试类

package com.bjpowernode;

import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.service.IUserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");

        IUserService bean = context.getBean(IUserService.class);
        PageInfo<User> pageInfo = bean.queryPage(2, 1);
        List<User> list = pageInfo.getList();
        for (User user : list) {
            System.out.println(user);
        }
    }
}
 

5.1.3 相关配置文件
5.1.3.1 jdbc配置文件
#数据库连接信息
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&useSSL=false&characterEncoding=UTF8&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456
5.1.3.2 日志配置文件

# 全局日志配置
log4j.rootLogger=DEBUG, stdout
# MyBatis 日志配置
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

5.1.3.3 mybatis核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 引入数据库配置文件 -->
    <!--<properties resource="jdbc.properties" />-->
    <!-- 全局设置 -->
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    <!-- 配置类别名 -->
    <typeAliases>
        <package name="com.bjpowernode.domain"/>
    </typeAliases>
    <!-- 配置分页插件 -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor" />
    </plugins>
    <!-- 数据源环境 -->
<!--    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>-->
    <!-- 映射文件 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>
</configuration>

5.1.3.4 mybatis映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.mapper.UserMapper">

    <select id="selectById" resultType="com.bjpowernode.domain.User">
        select * from user where id = #{id}
    </select>

    <select id="selectAll" resultType="com.bjpowernode.domain.User">
        select * from user
    </select>
</mapper>

5.1.3.5 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"
       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 https://www.springframework.org/schema/context/spring-context.xsd">
    <!--
        终极目标 为 每个service 注入一个Mapper 对象
        1. Mapper 对象
        2. SqlSession 获取
        3. SqlSession 要根据 SqlSessionFactory 获取
        4. SqlSessionFactory 要 根据 SqlSessionFactoryBuilder获取
        5. SqlSessionFactoryBuilder 可以直接创建 此时需要使用IOC容器
        6. 配置数据源
    -->
    <!--1. 引入jdbc的配置文件 使用配置文件 不是使用系统属性-->
    <context:property-placeholder location="jdbc.properties" system-properties-mode="FALLBACK" />
    <!--2. 配置数据源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <!--3. 配置SqlSessionFactoryBean 对象-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--  mybatis 核心配置文件 -->
        <property name="configLocation" value="mybatis.xml" />
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 4.扫描所有的Mapper接口 自动创建Mapper的代理对象  -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 待扫描的mapper 接口的包名 多个之间使用逗号分隔 -->
        <property name="basePackage" value="com.bjpowernode.mapper" />
        <!--注入SqlSessionFactoryBean 用于创建SqlSession -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" />
    </bean>

    <!-- 配置Service 层对象 -->
    <bean id="userService" class="com.bjpowernode.service.impl.UserServiceImpl" autowire="byType" />

</beans>

5.2 Spring配置文件版

使用Spring的配置文件,取代mybatis的核心配置文件。

导入的jar包和相关类完全一致,jdbc配置文件和日志配置文件也相同。只是将mybatis的核心配置文件中的配置,移入到spring的核心配置文件中。

5.2.1 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"
       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 https://www.springframework.org/schema/context/spring-context.xsd">
    <!--
        终极目标 为 每个service 注入一个Mapper 对象
        1. Mapper 对象
        2. SqlSession 获取
        3. SqlSession 要根据 SqlSessionFactory 获取
        4. SqlSessionFactory 要 根据 SqlSessionFactoryBuilder获取
        5. SqlSessionFactoryBuilder 可以直接创建 此时需要使用IOC容器
        6. 配置数据源
    -->
    <!--1. 引入jdbc的配置文件 使用配置文件 不是使用系统属性-->
    <context:property-placeholder location="jdbc.properties" system-properties-mode="FALLBACK" />
    <!--2. 配置数据源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <!--3. 配置SqlSessionFactoryBean 对象-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--  配置数据源 -->
        <property name="dataSource" ref="dataSource" />
        <!-- 配置包下类别名 多个包之间使用 逗号分隔 -->
        <property name="typeAliasesPackage" value="com.bjpowernode.domain" />
        <!-- 配置插件 -->
        <property name="plugins">
            <array>
                <bean id="pageInterceptor" class="com.github.pagehelper.PageInterceptor" />
            </array>
        </property>
        <!-- 配置映射文件 -->
        <property name="mapperLocations" value="mapper/**/*Mapper.xml"></property>
    </bean>
    <!-- 4.扫描所有的Mapper接口 自动创建Mapper的代理对象  -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 待扫描的mapper 接口的包名 多个之间使用逗号分隔 -->
        <property name="basePackage" value="com.bjpowernode.mapper" />
        <!--注入SqlSessionFactoryBean 用于创建SqlSession -->
        <!--
            SqlSessionFactoryBean 是可以自动装配的 但是 如果存在多个数据源时,可以指定SqlSessionFactoryBean
            区分数据源
        -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" />
    </bean>
    <!-- 配置Service 层对象 -->
    <bean id="userService" class="com.bjpowernode.service.impl.UserServiceImpl" autowire="byType" />

</beans>
 

5.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"
       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 https://www.springframework.org/schema/context/spring-context.xsd">
    <!--
        终极目标 为 每个service 注入一个Mapper 对象
        1. Mapper 对象
        2. SqlSession 获取
        3. SqlSession 要根据 SqlSessionFactory 获取
        4. SqlSessionFactory 要 根据 SqlSessionFactoryBuilder获取
        5. SqlSessionFactoryBuilder 可以直接创建 此时需要使用IOC容器
        6. 配置数据源
    -->
    <!--1. 引入jdbc的配置文件 使用配置文件 不是使用系统属性-->
    <context:property-placeholder location="jdbc.properties" system-properties-mode="FALLBACK" />
    <!--2. 配置数据源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>



    <!-- 配置 Configuration-->
    <bean  id="configuration" class="org.apache.ibatis.session.Configuration">
        <!-- 指定日志工具 -->
        <property name="logImpl"  value="org.apache.ibatis.logging.log4j.Log4jImpl" />
        <!-- 配置缓存 -->
        <property name="cacheEnabled" value="true" />
    </bean>
    <!--3. 配置SqlSessionFactoryBean 对象-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--  配置数据源 -->
        <property name="dataSource" ref="dataSource" />
        <!-- 配置包下类别名 多个包之间使用 逗号分隔 -->
        <property name="typeAliasesPackage" value="com.bjpowernode.domain" />
        <!-- 配置插件 -->
        <property name="plugins">
            <array>
                <bean id="pageInterceptor" class="com.github.pagehelper.PageInterceptor" />
            </array>
        </property>
        <!-- 注入configuration -->
        <property name="configuration"  ref="configuration" />
        <!-- 配置映射文件 -->
        <property name="mapperLocations" value="mapper/**/*Mapper.xml"></property>
    </bean>
    <!-- 4.扫描所有的Mapper接口 自动创建Mapper的代理对象  -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 待扫描的mapper 接口的包名 多个之间使用逗号分隔 -->
        <property name="basePackage" value="com.bjpowernode.mapper" />
        <!--注入SqlSessionFactoryBean 用于创建SqlSession -->
        <!--
            SqlSessionFactoryBean 是可以自动装配的 但是 如果存在多个数据源时,可以指定SqlSessionFactoryBean
            区分数据源
        -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" />
    </bean>

    <!-- 配置Service 层对象 -->
    <bean id="userService" class="com.bjpowernode.service.impl.UserServiceImpl" autowire="byType" />

</beans>
 

6.声明式事务

在spring中,spring可以管理数据源,管理连接,spring也可以管理事务,并且spring单独对事务分了一个模块进行管理。并且,Spring简化了事务开发,只需要通过配置的方式,Spring即可对事务进行统一完善的管理,Spring的事务管理基于Spring的AOP技术。

Spring的声明式事务,有两种方式:xml配置、注解

6.1 XML配置方式

<?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" xmlns:tx="http://www.springframework.org/schema/tx"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--
        终极目标 为 每个service 注入一个Mapper 对象
        1. Mapper 对象
        2. SqlSession 获取
        3. SqlSession 要根据 SqlSessionFactory 获取
        4. SqlSessionFactory 要 根据 SqlSessionFactoryBuilder获取
        5. SqlSessionFactoryBuilder 可以直接创建 此时需要使用IOC容器
        6. 配置数据源
    -->
    <!--1. 引入jdbc的配置文件 使用配置文件 不是使用系统属性-->
    <context:property-placeholder location="jdbc.properties" system-properties-mode="FALLBACK" />
    <!--2. 配置数据源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <!-- 配置 Configuration-->
    <bean  id="configuration" class="org.apache.ibatis.session.Configuration">
        <!-- 指定日志工具 -->
        <property name="logImpl"  value="org.apache.ibatis.logging.log4j.Log4jImpl" />
        <!-- 配置缓存 -->
        <property name="cacheEnabled" value="true" />
    </bean>
    <!--3. 配置SqlSessionFactoryBean 对象-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--  配置数据源 -->
        <property name="dataSource" ref="dataSource" />
        <!-- 配置包下类别名 多个包之间使用 逗号分隔 -->
        <property name="typeAliasesPackage" value="com.bjpowernode.domain" />
        <!-- 配置插件 -->
        <property name="plugins">
            <array>
                <bean id="pageInterceptor" class="com.github.pagehelper.PageInterceptor" />
            </array>
        </property>
        <!-- 注入configuration -->
        <property name="configuration"  ref="configuration" />
        <!-- 配置映射文件 -->
        <property name="mapperLocations" value="mapper/**/*Mapper.xml"></property>
    </bean>
    <!-- 4.扫描所有的Mapper接口 自动创建Mapper的代理对象  -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 待扫描的mapper 接口的包名 多个之间使用逗号分隔 -->
        <property name="basePackage" value="com.bjpowernode.mapper" />
        <!--注入SqlSessionFactoryBean 用于创建SqlSession -->
        <!--
            SqlSessionFactoryBean 是可以自动装配的 但是 如果存在多个数据源时,可以指定SqlSessionFactoryBean
            区分数据源
        -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" />
    </bean>
    <!-- 配置Service 层对象 -->
    <bean id="userService" class="com.bjpowernode.service.impl.UserServiceImpl" autowire="byType" />
    <!-- 事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 配置数据源  指定要管理那个数据源的事务 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 配置事务增强 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 配置增强规则 -->
        <tx:attributes>
            <!--
                name : 进行数据库操作方法的名称  add* 表示 add开头的方法  * 指代任意字符
                propagation : 事务传播性  面试重点
                read-only : 只读事务  默认 false
                rollback-for : 指定回滚的异常  默认是 RunTimeException 下的异常会自动回滚
                no-rollback-for : 不回滚的异常
                timeout : 事务的超时时间
                isolation : 事务隔离级别  面试重点
                    | 1. 读未提交
                    | 2. 读已提交
                    | 3. 可重复读
                    | 4. 串行化
            -->
            <tx:method name="add*" read-only=”false” rollback-for="Exception"/>
            <tx:method name="insert*" rollback-for="Exception" />
            <tx:method name="update*" rollback-for="Exception" />
            <tx:method name="delete*" rollback-for="Exception" />
            <tx:method name="*" read-only="true" />
        </tx:attributes>
    </tx:advice>
    <!-- 配置切面 -->
    <aop:config>
        <!-- 注意一般切点在 service -->
        <aop:pointcut id="mypoint" expression="execution(* com.bjpowernode.service.impl.*.*(..))"/>
        <!-- 织入增强 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint" />
    </aop:config>
</beans>

6.2 注解版声明式事务

在Spring中,为简化事务开发,提供了注解:@Transactional,该注解可以指定在类上,在类上,该类中的所有方法都会使用事务,该注解也可以指定方法上,该方法会使用事务。使用非常简单,只需:

  1. 配置事务管理器

  2. 开启注解事务

  3. 在需要使用事务的地方使用@Transactional

6.2.1 配置类

<?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" xmlns:tx="http://www.springframework.org/schema/tx"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--
        终极目标 为 每个service 注入一个Mapper 对象
        1. Mapper 对象
        2. SqlSession 获取
        3. SqlSession 要根据 SqlSessionFactory 获取
        4. SqlSessionFactory 要 根据 SqlSessionFactoryBuilder获取
        5. SqlSessionFactoryBuilder 可以直接创建 此时需要使用IOC容器
        6. 配置数据源
    -->
    <!--1. 引入jdbc的配置文件 使用配置文件 不是使用系统属性-->
    <context:property-placeholder location="jdbc.properties" system-properties-mode="FALLBACK" />
    <!--2. 配置数据源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <!-- 配置 Configuration-->
    <bean  id="configuration" class="org.apache.ibatis.session.Configuration">
        <!-- 指定日志工具 -->
        <property name="logImpl"  value="org.apache.ibatis.logging.log4j.Log4jImpl" />
        <!-- 配置缓存 -->
        <property name="cacheEnabled" value="true" />
    </bean>
    <!--3. 配置SqlSessionFactoryBean 对象-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--  配置数据源 -->
        <property name="dataSource" ref="dataSource" />
        <!-- 配置包下类别名 多个包之间使用 逗号分隔 -->
        <property name="typeAliasesPackage" value="com.bjpowernode.domain" />
        <!-- 配置插件 -->
        <property name="plugins">
            <array>
                <bean id="pageInterceptor" class="com.github.pagehelper.PageInterceptor" />
            </array>
        </property>
        <!-- 注入configuration -->
        <property name="configuration"  ref="configuration" />
        <!-- 配置映射文件 -->
        <property name="mapperLocations" value="mapper/**/*Mapper.xml"></property>
    </bean>
    <!-- 4.扫描所有的Mapper接口 自动创建Mapper的代理对象  -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 待扫描的mapper 接口的包名 多个之间使用逗号分隔 -->
        <property name="basePackage" value="com.bjpowernode.mapper" />
        <!--注入SqlSessionFactoryBean 用于创建SqlSession -->
        <!--
            SqlSessionFactoryBean 是可以自动装配的 但是 如果存在多个数据源时,可以指定SqlSessionFactoryBean
            区分数据源
        -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" />
    </bean>
    <!-- 事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 配置数据源  指定要管理那个数据源的事务 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
   <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.*" />
    <!-- 开启事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"  />
</beans>
 

6.2.2 service代码

package com.bjpowernode.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.mapper.UserMapper;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper  userMapper;
    @Override
    public User queryUser(Integer id) {
        return userMapper.selectById(id);
    }
    @Override
    public PageInfo<User> queryPage(Integer page,Integer limit) {
        Page<User> users = PageHelper.startPage(page, limit);
        userMapper.selectAll();
        return users.toPageInfo();
    }
    /**
     *  在spring中 不要在事务相关方法中 使用catch 处理
     *  如果处理了  异常不会被spring aop 增强的方法 捕获到  不会回滚
     *  事务配置就失效了  所以如果有异常 :
     *  1. 直接抛
     *  2. 在catch继续抛出异常
     * @param user
     * @return
     */
    @Override
    //@Transactional(rollbackFor = Exception.class)
    public Integer addUser(User user) {
        int m = userMapper.insert(user);
        int n = 0;
        try {
            m = m/n;//出现异常
        } catch (Exception exception) {
            exception.printStackTrace();
            throw new RuntimeException("发生 请求回滚!!!");
        }
        return m;
    }
}

7
在这里插入图片描述

注意:

事务的传播行为,是指事务会发生传递。例如:A方法存在事务,A调用B方法,那么B方法也会在事务中执行,这种就是事务的传播行为。

package com.bjpowernode.controller;

import com.bjpowernode.domain.User;
import com.bjpowernode.mapper.UserMapper;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;

@Controller
public class UserController {

    @Autowired
    private IUserService  userService;
    @Autowired
    private UserMapper userMapper;

    @Transactional
    public void add(User user){
        User user1 = new User();
        user1.setUsername("韩梅梅");
        user1.setPassword("123");
        user1.setRealname("韩梅梅");
        userMapper.insert(user1);//在父事务中添加数据  自己的程序 更新数据状态
        try {
            //其他的业务操作
            userService.addUser(user);//子事务  子事务发生异常
        }catch (Exception e){
            e.printStackTrace();
        }
        int n = 0;
        //n = 100/n;//出现异常
    }
}



package com.bjpowernode.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.mapper.UserMapper;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper  userMapper;


    @Override
    public User queryUser(Integer id) {
        return userMapper.selectById(id);
    }

    @Override
    public PageInfo<User> queryPage(Integer page,Integer limit) {
        Page<User> users = PageHelper.startPage(page, limit);
        userMapper.selectAll();
        return users.toPageInfo();
    }

    /**
     *  在spring中 不要在事务相关方法中 使用catch 处理
     *  如果处理了  异常不会被spring aop 增强的方法 捕获到  不会回滚
     *  事务配置就失效了  所以如果有异常 :
     *  1. 直接抛
     *  2. 在catch继续抛出异常
     * @param user
     * @return
     */
    @Override
    //@Transactional(propagation = Propagation.SUPPORTS) //有就在事务中执行  没有就不在事务中执行
    //@Transactional(propagation = Propagation.MANDATORY) //必须要有事务
    //@Transactional(propagation = Propagation.NEVER) // 不在事务中执行  当前存在事务就报错
    @Transactional(propagation = Propagation.NESTED) // 当前存在一个事务 就 创建一个子事务 嵌套在当前事务中
    //外层事务出现异常会回滚子事务   子事务出现异常 不会回滚外层事务
    public Integer addUser(User user) {
        int m = userMapper.insert(user);
        int n = 0;
        m = m/n;//出现异常
        return m;
    }
} 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值