SpringAOP的引入

目录

一、概念引入

1.引入依赖

2.工具类

3.实体类

4.持久层实现类

5.业务层实现类

6.配置文件

7.测试类

8.运行

查看数据库:

9.现在如果转账过程中出现异常

AccountServiceImpl(模拟异常)

再运行:

查看数据库:

10.现在做事务管理

AccountServiceImpl(事务管理)

运行

查看数据库:

11.生成代理对象

代理对象:

业务层实现类

查看数据库:


一、概念引入

入门案例(概念引入)

1.引入依赖

XML 复制代码
<dependencies>
    <!--spring的核心依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <!--日志-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <!--测试-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!--连接池 alibaba的-->
    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>
    <!--mysql驱动-->
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
    <!--spring-test-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.0.2.RELEASE</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2.工具类

java 复制代码
package com.qcby.utils;

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

import javax.sql.DataSource;

import com.alibaba.druid.pool.DruidDataSource;

/**
 * 事务的工具类
 */
public class TxUtils {
   
   private static DruidDataSource ds = null;

   // 使用ThreadLocal存储当前线程中的Connection对象
   private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();

   // 在静态代码块中创建数据库连接池---static代码块
   static {
      try {
         // 通过代码创建C3P0数据库连接池
         ds = new DruidDataSource();
         ds.setDriverClassName("com.mysql.jdbc.Driver");
         ds.setUrl("jdbc:mysql:///spring_db");
         ds.setUsername("root");
         ds.setPassword("2020");
      } catch (Exception e) {
         throw new ExceptionInInitializerError(e);
      }
   }

   /**
    * @Method: getConnection
    * @Description: 从数据源中获取数据库连接
    * @Anthor:
    * @return Connection
    * @throws SQLException
    */
   public static Connection getConnection() throws SQLException {

      // 从当前线程中获取Connection
      Connection conn = threadLocal.get();

      if (conn == null) {
         // 从数据源中获取数据库连接
         conn = getDataSource().getConnection();
         // 将conn绑定到当前线程
         threadLocal.set(conn);
      }
      return conn;
   }

   /**
    * @Method: startTransaction
    * @Description: 开启事务
    * @Anthor:
    *
    */
   //jdbc开启事务靠链接开启
   public static void startTransaction() {
      try {
         Connection conn = threadLocal.get();
         if (conn == null) {
            conn = getConnection();
            // 把 conn绑定到当前线程上
            threadLocal.set(conn);
         }

         // 开启事务
         conn.setAutoCommit(false);

      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Method: rollback
    * @Description:回滚事务
    * @Anthor:
    */
   public static void rollback() {
      try {
         // 从当前线程中获取Connection
         Connection conn = threadLocal.get();
         if (conn != null) {
            // 回滚事务
            conn.rollback();
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Method: commit
    * @Description:提交事务
    * @Anthor:
    */
   public static void commit() {
      try {
         // 从当前线程中获取Connection
         Connection conn = threadLocal.get();
         if (conn != null) {

            // 提交事务
            conn.commit();

         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Method: close
    * @Description:关闭数据库连接(注意,并不是真的关闭,而是把连接还给数据库连接池)
    * @Anthor:
    *
    */
   public static void close() {
      try {
         // 从当前线程中获取Connection
         Connection conn = threadLocal.get();//从连接池拿到链接
         if (conn != null) {
            conn.close();
            // 解除当前线程上绑定conn
            threadLocal.remove();
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Method: getDataSource
    * @Description: 获取数据源
    * @Anthor:
    * @return DataSource
    */
   public static DataSource getDataSource() {
      // 从数据源中获取数据库连接
      return ds;
   }

}

3.实体类

java 复制代码
package com.qcby.model;

import java.io.Serializable;

public class Account implements Serializable {
    private Integer id;
    private String name;
    private Double money;

    public Account() {
    }

    public Account(Integer id, String name, Double money) {
        this.id = id;
        this.name = name;
        this.money = money;
    }

    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 Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

4.持久层实现类

java 复制代码
package com.qcby.dao.impl;

import com.qcby.dao.AccountDao;
import com.qcby.pojo.Account;
import com.qcby.utils.TxUtils;

import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import com.mysql.jdbc.Driver;

public class AccountDaoImpl implements AccountDao {
    //实现两个账户的转账
    @Override
    public void updateSaveAll(Account account){

        Connection connection=null;
        PreparedStatement stmt=null;
        try{
            //获取连接
            connection = TxUtils.getConnection();
            String sql = "update  account set money = money + ? where name = ?";
            stmt = connection.prepareStatement(sql);
            stmt.setDouble(1, account.getMoney());
            stmt.setString(2, account.getName());
            // 查询
            int result = stmt.executeUpdate();
            System.out.println("修改影响了"+result+"行数据!!");
        }catch(Exception e){
            try {
                stmt.close();
                //connection.close();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
    }
}

5.业务层实现类

java 复制代码
package com.qcby.service.impl;

import com.qcby.dao.AccountDao;
import com.qcby.model.Account;
import com.qcby.service.AccountService;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void updateSaveAll(Account account1, Account account2) {
        //保存账号1
        accountDao.updateSaveAll(account1);
        //保存账号2
        accountDao.updateSaveAll(account2);
    }
}

6.配置文件

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



    <!--配置持久层和业务层-->
    <bean id="accountService" class="com.qcby.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    <bean id="accountDao" class="com.qcby.dao.impl.AccountDaoImpl">
    </bean>

</beans>

7.测试类

java 复制代码
package com.qcby;

import com.qcby.model.Account;
import com.qcby.service.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 demo {

    @Autowired
    private AccountService accountService;

    @Test
    public void run(){
        Account account1=new Account(null,"aaa",500.00);
        Account account2=new Account(null,"bbb",-500.00);
        accountService.updateSaveAll(account1,account2);
    }
}

8.运行

查看数据库:

之前:

现在:

9.现在如果转账过程中出现异常

AccountServiceImpl(模拟异常)

java 复制代码
package com.qcby.service.impl;

import com.qcby.dao.AccountDao;
import com.qcby.model.Account;
import com.qcby.service.AccountService;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void updateSaveAll(Account account1, Account account2) {
        //保存账号1
        accountDao.updateSaveAll(account1);
        //模拟异常
        int a=1/0;
        //保存账号2
        accountDao.updateSaveAll(account2);
    }
}

再运行:

查看数据库:

只有第一条数据变了,出现错误

10.现在做事务管理

AccountServiceImpl(事务管理)

java 复制代码
package com.qcby.service.impl;

import com.qcby.dao.AccountDao;
import com.qcby.model.Account;
import com.qcby.service.AccountService;
import com.qcby.utils.TxUtils;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void updateSaveAll(Account account1, Account account2) {
        //在这里进行事务管理
        try {
            //开启事务
            TxUtils.startTransaction();
            //保存账号1
            accountDao.updateSaveAll(account1);
            //模拟异常
            int a=1/0;
            //保存账号2
            accountDao.updateSaveAll(account2);
            //提交事务
            TxUtils.commit();
        }catch (Exception e){
            e.printStackTrace();
            //回滚事务
            TxUtils.rollback();
        }finally {
            //关闭资源
            TxUtils.close();
        }
    }
}

这里仍然有异常,但是进行了事务管理,

运行

查看数据库:

原来:

现在:

回滚了

11.生成代理对象

代理对象:

java 复制代码
package com.qcby.proxy;

import com.qcby.service.AccountService;
import com.qcby.utils.TxUtils;

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

/*
* 传入目标对象,生成该对象的代理对象,返回。对目标对象的方法进行增强
* */
public class JdkProxy {
    //获取代理对象
    public static Object getProxy(AccountService accountService){
        /*
        * 使用JDK动态代理生成代理对象
        * 第一个参数:类的加载其
        * 第二个参数:当前传入的对象实现了哪些接口要字节码的对象
        * 第三个参数:回调函数
        * */
        Object proxy = Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler(){
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {
                    //开启事务
                    TxUtils.startTransaction();
                    result = method.invoke(accountService,args);
                    //提交事务
                    TxUtils.commit();
                }catch (Exception e){
                    e.printStackTrace();
                    //回滚
                    TxUtils.rollback();
                }finally {
                    TxUtils.close();
                }
                return result;
            }
        });
        return proxy;
    }
}

业务层实现类

(有异常)(之前在这里写的事务就不用写了)

java 复制代码
package com.qcby.service.impl;

import com.qcby.dao.AccountDao;
import com.qcby.pojo.Account;
import com.qcby.service.AccountService;
import com.qcby.utils.TxUtils;

import java.sql.SQLException;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;//因为这里是空指针,所以要有set方法

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void updateSaveAll(Account account1, Account account2){
        try {
            //保存账号1
            accountDao.updateSaveAll(account1);
            //模拟异常
            int a=1/0;
            //保存账号2
            accountDao.updateSaveAll(account2);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

测试类

(多了一个run2())

java 复制代码
package com.qcby.springAopTest;

import com.qcby.pojo.Account;
import com.qcby.proxy.JdkProxy;
import com.qcby.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Autowired
    private AccountService accountService;

    @Test
    public void run1(){
        Account account1=new Account(null,"aaa",500.00);
        Account account2=new Account(null,"bbb",-500.00);
        accountService.updateSaveAll(account1,account2);
    }

    @Test
    public void run2(){
        Account account1=new Account(null,"aaa",500.00);
        Account account2=new Account(null,"bbb",-500.00);
        //生成代理对象
        Object proxyobj= JdkProxy.getProxy(accountService);
        AccountService proxy=(AccountService)proxyobj;
        proxy.updateSaveAll(account1,account2);
    }
}

运行:

查看数据库:

原来:

现在:

相关推荐
一只淡水鱼6625 分钟前
【mybatis】基本操作:详解Spring通过注解和XML的方式来操作mybatis
java·数据库·spring·mybatis
张声录127 分钟前
【ETCD】【实操篇(十六)】基于角色的访问控制:ETCD 安全管理指南
数据库·安全·etcd
warrah33 分钟前
redis——岁月云实战
数据库·redis·缓存
秀儿y33 分钟前
Redis-十大数据类型
数据库·redis·缓存·oracle
凡人的AI工具箱1 小时前
每天40分玩转Django:Django类视图
数据库·人工智能·后端·python·django·sqlite
路在脚下@1 小时前
MySQL的索引失效的原因有那些
数据库·mysql
凡人的AI工具箱1 小时前
每天40分玩转Django:实操图片分享社区
数据库·人工智能·后端·python·django
CT随1 小时前
MongoDB
数据库·mongodb
Fool丶玄浅2 小时前
【数据库系统概论】—— 关系数据库
数据库·数据库系统
DashVector2 小时前
如何通过HTTP API检索Doc
数据库·人工智能·http·阿里云·数据库开发·向量检索