Spring框架入门--SpringAOP的两种实现方式--Spring事务管理--声明式事务

Spring框架学习02

一、springAOP简介

1、AOP概念

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。

2、AOP应用场景

Aop的功能主要是为了拦截或者实现日志安全检查等一些检查的工作,aop也常用于事务管理,防止垃圾数据进入数据库。

3、横向切割和纵向切割

Aop采用的横向切割技术,在不修改源代码的情况下完成添加功能的技术;纵向切割技术,修改源代码情况下完成功能的操作。

4、AOP的五种增强——实现横向切割技术的方式

前置增强,表示在目标方法执行前实施增强

后置增强,表示在目标方法执行后实施增强

环绕增强,表示在目标方法执行前后实施增强

异常增强,表示在目标方法抛出异常后实施增强。

最终增强,表示在目标方法执行后不管有没有异常抛出总是实施增强

二、Spring AOP的应用——基于aspectJ的xml版

1、pom.xml导入相关依赖

<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.0modelVersion>

    <groupId>com.java.Spring_AOPgroupId>
    <artifactId>Spring_AOPartifactId>
    <version>1.0-SNAPSHOTversion>

    <dependencies>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.11version>
        dependency>

        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-beansartifactId>
            <version>4.2.5.RELEASEversion>
        dependency>

        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>4.2.5.RELEASEversion>
        dependency>

        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-coreartifactId>
            <version>4.2.5.RELEASEversion>
        dependency>

        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-testartifactId>
            <version>4.2.5.RELEASEversion>
        dependency>

        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-txartifactId>
            <version>4.3.7.RELEASEversion>
        dependency>

        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-jdbcartifactId>
            <version>4.3.7.RELEASEversion>
        dependency>

        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-aopartifactId>
            <version>4.3.7.RELEASEversion>
        dependency>

        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-aspectsartifactId>
            <version>4.3.7.RELEASEversion>
        dependency>

        
        <dependency>
            <groupId>org.aspectjgroupId>
            <artifactId>aspectjweaverartifactId>
            <version>1.8.9version>
        dependency>
        
         <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.38version>
        dependency>

        <dependency>
            <groupId>c3p0groupId>
            <artifactId>c3p0artifactId>
            <version>0.9.1.2version>
        dependency>

    dependencies>
project>
2、创建一个目标类
package com.java.aop.xml;

/**
 * @author Liushun
 * @date Created in 2018/9/17 20:26
 * @description 目标类,就是在操作过程中手动调用的类
 */
public class Target {

    // 目标方法1:查询余额
    public void selectAccount(){
        System.out.println("模拟查询到用户余额为100");
    }
}
3、 创建一个增强类
package com.java.aop.xml;

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * @author Liushun
 * @date Created in 2018/9/17 20:23
 * @description 增强类,在调用目标类的时候spring利用aop思想,执行预编译的类
 */
public class Handler {

    // 前置增强:模拟用户验证
    public void handlerBefore(){
        System.out.println("前置增强方法--取款操作前的用户校验通过");
    }

    // 后置增强:模拟取款后的信息输出
    public void handlerAfter(){
        System.out.println("后置增强方法--取款后的信息输出");
    }

    // 环绕增强
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕增强——检查前。。。");
        // 调用切点方法
        pjp.proceed();
        System.out.println("环绕增强——检查后。。。");
    }

    // 异常增强:在业务目标方法中出现类异常情况,则会执行异常增强,如果不存在异常,则不执行异常增强
    public void excep(){
        System.out.println("异常增强——哎呀,出错啦!");
    }

    // 最终增强:不管有没有异常出现,均会执行的增强称之为最终增强
    public void finallyHandler(){
        System.out.println("最终增强--关闭资源");
    }
}
4、applicationContext.xml加入相关配置

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

        
        <bean id="target" class="com.java.aop.xml.Target"/>
        <bean id="handler" class="com.java.aop.xml.Handler"/>

        
        <aop:config>
            
            <aop:pointcut id="myPointcut" expression="execution(* com.java.aop.xml.Target.*(..))"/>

            
            <aop:aspect ref="handler">
                
                <aop:before method="handlerBefore" pointcut-ref="myPointcut"/>

                
                <aop:after-returning method="handlerAfter" pointcut-ref="myPointcut"/>

                
                <aop:around method="around" pointcut-ref="myPointcut"/>

                
                <aop:after-throwing method="excep" pointcut-ref="myPointcut"/>

                
                <aop:after method="finallyHandler" pointcut-ref="myPointcut"/>
            aop:aspect>
            
        aop:config>
beans>
5、测试类
package com.java.aop.xml;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author Liushun
 * @date Created in 2018/9/17 20:33
 * @description aop测试类
 */
public class AOPTest {

    // 调用目标方法,spring的aop功能会自动调用增强方法
    @Test
    public void aopTest(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Target target = (Target) context.getBean("target");
        // 查询余额方法
        target.selectAccount();
    }
}

三、Spring AOP的应用——基于注解版

1、applicationContext.xml

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

        
        <context:component-scan base-package="com.java.aop.anno"/>
        
        <aop:aspectj-autoproxy/>
    
beans>
2、增强类
package com.java.aop.anno;

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

/**
 * @author Liushun
 * @date Created in 2018/9/17 20:23
 * @description 增强类,在调用目标类的时候spring利用aop思想,执行预编译的类
 */

// 实例化增强类
@Service
// 开启切面的注解
@Aspect
public class Handler {

    // 前置增强:模拟用户验证
    @Before("execution(* com.java.aop.anno.Target.*(..))")
    public void handlerBefore(){
        System.out.println("前置增强方法--取款操作前的用户校验通过");
    }

    // 后置增强:模拟取款后的信息输出
    @AfterReturning("execution(* com.java.aop.anno.Target.*(..))")
    public void handlerAfter(){
        System.out.println("后置增强方法--取款后的信息输出");
    }

    // 环绕增强
    @Around("execution(* com.java.aop.anno.Target.*(..))")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕增强——检查前。。。");
        // 调用切点方法
        pjp.proceed();
        System.out.println("环绕增强——检查后。。。");
    }

    // 异常增强:在业务目标方法中出现类异常情况,则会执行异常增强,如果不存在异常,则不执行异常增强
    @AfterThrowing("execution(* com.java.aop.anno.Target.*(..))")
    public void excep(){
        System.out.println("异常增强——哎呀,出错啦!");
    }

    // 最终增强:不管有没有异常出现,均会执行的增强称之为最终增强
    @After("execution(* com.java.aop.anno.Target.*(..))")
    public void finallyHandler(){
        System.out.println("最终增强--关闭资源");
    }

}
3、目标类
package com.java.aop.anno;

import org.springframework.stereotype.Service;

/**
 * @author Liushun
 * @date Created in 2018/9/17 20:26
 * @description 目标类,就是在操作过程中手动调用的类
 */

// 实例化目标类
@Service
public class Target {

    // 目标方法1:查询余额
    public void selectAccount(){
        System.out.println("模拟查询到用户余额为100");
    }

}
4、测试类
package com.java.aop.anno;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * @author Liushun
 * @date Created in 2018/9/17 20:33
 * @description aop测试类
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/applicationContext.xml")
public class AOPTest2 {

    @Autowired
    private Target target;

    // 调用目标方法,spring的aop功能会自动调用增强方法
    @Test
    public void aopTest(){
        // 查询余额方法
        target.selectAccount();
    }
}
5、注意事项

目标类要设置@service注解,目的是为了在调用service时候完成实例化和注入操作

增强类要设置@Aspect切面注解,目的是定义当前类是切面,而且也要设置@service注解,目的也是为了在完成实例化和注入操作

注解开发,主要更改的是增强类里的注解配置

四、Spring的事务管理

1、事务的理解

事务管理对于企业应用而言至关重要。它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性。就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失

简单来说:事务是一系列的动作,一旦其中有一个动作出现错误,必须全部回滚,系统将事务中对数据库的所有已完成的操作全部撤消,滚回到事务开始的状态,避免出现由于数据不一致而导致的接下来一系列的错误。事务的出现是为了确保数据的完整性和一致性,在目前企业级应用开发中,事务管理是必不可少的

2、事务的属性
  • 传播行为

    定义了事务应用到方法上的边界。也就是什么时候开始一个新的事务,或者什么时候事务被暂停,或者方法是否要在事务中运行

事务传播行为类型 说明
PROPAGATION_REQUIREO 如果当前没有事务,就创建一个事务;如果已经存在一个事务,就加入到这个事务中。这是最常见的选择
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务就以非事务方式执行
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务就抛出异常
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务则将当前事务挂起
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务则将当前事务挂起
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务则抛出异常
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIREO类似的操作
  • 隔离级别

    用来指定一个事务受其他并发事务活动影响的程度。隔离性是数据的事务的4个特征之一,但是实际上来说,用户使用数据库产品是需要在效率和安全上找到平衡点的,所以需要设置事务的隔离级别

隔离级别 说明
ISOLATION_DEFAULT 使用底层数据库预设的隔离级别
ISOLATION_READ_COMMITTED 允许事务读取其它并行的事务已经送出的数据字段,可以防止脏读取问题
ISOLATION_READ_UNCOMMITTED 允许事务读取其它并行的事务还没送出的数据,会发生脏读取、非重复读、幻读等问题
ISOLATION_REPEATABLE_READ 要求多次读取的数据必须相同,除非事务本身更新数据,可防止脏读取、非重复读问题
ISOLATION_SERIALIZABLE 完整的隔离层次,可防止脏读取、非重复读、幻读等问题,会锁定相应的表格数据,导致使用此级别的应用效率降低
  • 只读提示

    Read-only=true,必须配合传播行为来设置,一般建议设置在查询的方法中

  • 事务超时间隔

    可以让事务在特定的秒数后自动回滚,不必等到它自己结束,它也必须配合传播行为来设置。比如,Timeout=5

  • 回滚规则

    默认情况下在出现运行时异常RuntimeException才会回滚,检查时异常不回滚。当然也可以改变这种规则

五、声明式事务

1、声明式事务简介

声明式事务管理:它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。事务管理作为一种横切关注点,可以通过AOP方法模块化。Spring通过Spring AOP框架支持声明式事务管理。

声明式事务管理有三种方法实现,分别是TransactionProxyFactoryBean的代理方式、基于AspectJ的xml配置方式和基于注解的声明方式,后两种在开发应用中常常出现。

声明式事务管理是基于AOP思想完成的,类似与在给业务层加入切面,对事务操作前后进行一定的事务管理控制。

2、声明式事务应用——基于注解版–转账案例
1、applicationContext.xml

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

        
        <context:component-scan base-package="com.java.tx"/>
        
        <aop:aspectj-autoproxy/>

        
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
                <property name="dataSource" ref="dataSource"/>
        bean>

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

        
        <bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"/>
        bean>

        
        <tx:annotation-driven transaction-manager="transactionManager1"/>

beans>
2、Dao层实现类
package com.java.tx.dao.impl;

import com.java.tx.dao.IAccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

/**
 * @author Liushun
 * @date Created in 2018/9/18 20:04
 * @description DAO层实现类
 */

@Repository
public class AccountDaoImpl implements IAccountDao {

    @Autowired(required = false)
    private JdbcTemplate jdbcTemplate;

    @Override
    public void modifyOutAccount(String outCard, Double money) {
        String sql = "UPDATE account SET money = money - ? WHERE `name` = ?";
        jdbcTemplate.update(sql,money,outCard);
    }

    @Override
    public void modifyInAccount(String inCard, Double money) {
        String sql = "UPDATE account SET money = money + ? WHERE `name` = ?";
        jdbcTemplate.update(sql,money,inCard);
    }
}
3、Service层实现类
package com.java.tx.service.impl;

import com.java.tx.dao.IAccountDao;
import com.java.tx.service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author Liushun
 * @date Created in 2018/9/18 20:10
 * @description	Service层实现类
 */
@Service
// 事务的注解,表示当前类下的所有方法均加入事务
@Transactional
public class AccountServiceImpl implements IAccountService {

    @Autowired(required = false)
    private IAccountDao accountDao;

    @Override
    public void transferAccount(String inCard, String outCard, Double money) {
        // 转出
        accountDao.modifyOutAccount(outCard,money);
        // 异常
        int i = 1/0;
        // 转入
        accountDao.modifyInAccount(inCard,money);
    }
}
4、测试类
package com.java.tx;

import com.java.tx.service.IAccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * @author Liushun
 * @date Created in 2018/9/18 20:39
 * @description 声明式事务测试类
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/applicationContext.xml")
public class TxTest {

    @Autowired
    private IAccountService accountService;

    @Test
    public void test(){
        accountService.transferAccount("张三","李四",50D);
    }

}

你可能感兴趣的:(SSM)