AOP开发案例--优化转账

1. AOP优化转账案例

依然使用前面的转账案例,将两个代理工厂对象直接删除!改为springaop思想来实现。

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


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


    <!--引入properties-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>


    <!--配置DataSource-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>


    <!--配置queryRunner-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>


    <!--开启AOP的自动代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    <!--AOP配置-->
  <aop:config>
        <!--1.切点表达式-->
        <aop:pointcut id="myPointcut" expression="execution(* com.lagou.servlet.impl.AccountServiceImpl.*(..))"/>

        <!--2.切面配置-->
        <aop:aspect ref="transactionManager">
            <aop:before method="beginTransaction" pointcut-ref="myPointcut"/>
            <aop:after-returning method="commit"  pointcut-ref="myPointcut"/>
            <aop:after-throwing method="rollback" pointcut-ref="myPointcut"/>
            <aop:after method="release" pointcut-ref="myPointcut"/>
        </aop:aspect>
    </aop:config>


</beans>

1.3 事务管理器的编写

package com.lagou.utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.SQLException;

/*
    事务管理器工具类:包含:开启事务、提交事务、回滚事务、释放资源
     通知类
 */
@Component("transactionManager")
@Aspect //表明该类为切面类
public class TransactionManager {

    @Autowired
    private ConnectionUtils connectionUtils;


    @Around("execution(* com.lagou.servlet.impl.AccountServiceImpl.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws SQLException {

        Object proceed = null;
        try {
            // 开启手动事务
            connectionUtils.getThreadConnection().setAutoCommit(false);
            // 切入点方法执行
            proceed = pjp.proceed();

            // 手动提交事务
            connectionUtils.getThreadConnection().commit();

        } catch (Throwable throwable) {
            throwable.printStackTrace();
            // 手动回滚事务
            connectionUtils.getThreadConnection().rollback();

        } finally {
            // 将手动事务恢复成自动事务
            connectionUtils.getThreadConnection().setAutoCommit(true);
            // 将连接归还到连接池
            connectionUtils.getThreadConnection().close();
            // 解除线程绑定
            connectionUtils.removeThreadConnection();

        }


        return  proceed;
    }


    /*
        开启事务
     */
    public void beginTransaction(){

         // 获取connection对象
        Connection connection = connectionUtils.getThreadConnection();
        try {
            // 开启了一个手动事务
            connection.setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }


    /*
        提交事务
     */
    public void commit(){
        Connection connection = connectionUtils.getThreadConnection();
        try {
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }


    /*
        回滚事务
     */
    public void rollback(){
        Connection connection = connectionUtils.getThreadConnection();
        try {
            connection.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    /*
        释放资源
     */
    public void release(){

        // 将手动事务改回成自动提交事务
        Connection connection = connectionUtils.getThreadConnection();
        try {
            connection.setAutoCommit(true);
            // 将连接归还到连接池
         connectionUtils.getThreadConnection().close();
            // 解除线程绑定
         connectionUtils.removeThreadConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }




    }


}

1.3 数据库连接工具类

package com.lagou.utils;

/*
    连接工具类:从数据源中获取一个连接,并且将获取到的连接与线程进行绑定
       ThreadLocal : 线程内部的存储类,可以在指定的线程内存储数据 key:threadLocal(当前线程)   value:任意类型的值 Connection

 */

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

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@Component
public class ConnectionUtils {

    @Autowired
    private DataSource dataSource;

    private ThreadLocal<Connection> threadLocal = new ThreadLocal<>();


    /*
        获取当前线程上绑定连接:如果获取到的连接为空,那么就要从数据源中获取连接,并且放到ThreadLocal中(绑定到当前线程)
     */
    public  Connection getThreadConnection(){

        // 1. 先从ThreadLocal上获取连接
        Connection connection = threadLocal.get();

        // 2. 判断当前线程中是否是有Connection
        if(connection == null){
            // 3. 从数据源中获取一个连接,并且存入ThreadLocal中
            try {
                // 不为null
                connection = dataSource.getConnection();

                threadLocal.set(connection);

            } catch (SQLException e) {
                e.printStackTrace();
            }

        }

        return  connection;
    }


    /*
        解除当前线程的连接绑定
     */
    public void  removeThreadConnection(){
        threadLocal.remove();

    }





}

1.4 service的编写

package com.lagou.servlet.impl;

import com.lagou.dao.AccountDao;
import com.lagou.servlet.AccountService;
import com.lagou.utils.TransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("accountService")
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;
    @Autowired
    private TransactionManager transactionManager;




    /*
        转账方法  切入点   添加上事务控制的效果
     */
    public void transfer(String outUser, String inUser, Double money) {

        //手动开启事务:调用事务管理器中的开启事务方法
        //transactionManager.beginTransaction();
        // 编写了事务相关代码
        // 调用了减钱方法
        try {
            accountDao.out(outUser,money);

            //int i= 1/0;

            // 调用了加钱方法
            accountDao.in(inUser,money);

            //手动提交事务
            //transactionManager.commit();
        } catch (Exception e) {
            e.printStackTrace();
            //手动回滚事务
            //transactionManager.rollback();
        } finally {
            //资源释放
            //transactionManager.release();
        }




    }

    @Override
    public void save() {
        // 编写了事务相关代码
        System.out.println("save方法");
    }

    @Override
    public void update() {
        System.out.println("update方法");
    }

    @Override
    public void delete() {
        System.out.println("delete方法");
    }


}

1.5 测试类的编写

package com.lagou.test;

import com.lagou.proxy.CglibProxyFactory;
import com.lagou.proxy.JDKProxyFactory;
import com.lagou.servlet.AccountService;
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;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:applicationContext.xml"})
public class AccountServiceImplTest {

    @Autowired
    private AccountService accountService;

    @Autowired
    private JDKProxyFactory proxyFactory;


    @Test
    public void testTransfer(){

        accountService.transfer("tom","jerry",100d);
    }








    /*
        测试JDK动态代理优化转账案例
     */
    @Test
    public void testTransferProxyJDK(){

        // 当前返回的实际上是AccountService的代理对象proxy
        AccountService accountSericeJDKProxy = proxyFactory.createAccountSericeJDKProxy();
        // 代理对象proxy调用接口中的任意方法时,都会执行底层的invoke方法
        //accountSericeJDKProxy.transfer("tom","jerry",100d);
        accountSericeJDKProxy.save();


    }

    @Autowired
    private CglibProxyFactory cglibProxyFactory;

    /*
       测试Cglib动态代理优化转账案例
    */
    @Test
    public void testTransferProxyCglib(){

        // accountServiceCglibProxy: proxy
        AccountService accountServiceCglibProxy = cglibProxyFactory.createAccountServiceCglibProxy();
        accountServiceCglibProxy.transfer("tom","jerry",100d);

    }


}

 

节选自拉钩教育JAVA系列课程

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值