一、AOP概念的引入JDK动态代理为什么需要JDK动态代理在传统的业务开发中我们经常会遇到这样的场景需要在多个业务方法中添加相同逻辑比如事务管理、日志记录、权限校验等。使用JDK动态代理技术将这些横切关注点事务、日志等从业务逻辑中抽取出来。1.创建maven的项目引入开发的坐标dependencies dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version5.0.2.RELEASE/version /dependency dependency groupIdcommons-logging/groupId artifactIdcommons-logging/artifactId version1.2/version /dependency dependency groupIdlog4j/groupId artifactIdlog4j/artifactId version1.2.12/version /dependency !-- 有单元测试的环境Spring5版本Junit4.12版本 -- dependency groupIdjunit/groupId artifactIdjunit/artifactId version4.12/version scopetest/scope /dependency !-- 连接池 -- dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.1.10/version /dependency !-- mysql驱动包 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.6/version /dependency !-- Spring整合Junit测试的jar包 -- dependency groupIdorg.springframework/groupId artifactIdspring-test/artifactId version5.0.2.RELEASE/version scopetest/scope /dependency /dependencies2.QcbyUtils类进行事务管理package com.qcby.Utils; import com.alibaba.druid.pool.DruidDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; /** * 事务的工具类 */ public class QcbyUtils { private static DruidDataSource ds null; // 使用ThreadLocal存储当前线程中的Connection对象 private static ThreadLocalConnection threadLocal new ThreadLocalConnection(); // 在静态代码块中创建数据库连接池 static { try { // 通过代码创建C3P0数据库连接池 ds new DruidDataSource(); ds.setDriverClassName(com.mysql.cj.jdbc.Driver); ds.setUrl(jdbc:mysql:///spring_db); ds.setUsername(root); ds.setPassword(Xuhaoyu666!); } 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: * */ 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.AccountService的接口和实现类package com.qcby.service; import com.qcby.domain.Account; import java.sql.SQLException; public interface AccountService { public void save(Account account1, Account account2) throws SQLException; }package com.qcby.service; import com.qcby.dao.AccountDao; import com.qcby.domain.Account; import java.sql.SQLException; public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao accountDao; } Override public void save(Account account1, Account account2) throws SQLException{ // try{ // 保存1账号 accountDao.save(account1); // 模拟异常 // int a 1 / 0; // 保存2账号 accountDao.save(account2); // } catch (ArithmeticException e) { // e.printStackTrace(); // throw new SQLException(事务执行失败发生除零错误, e); // } } }4.AccountDao的接口和实现类package com.qcby.dao; import com.qcby.domain.Account; public interface AccountDao { public void save(Account account); }package com.qcby.dao; import com.qcby.Utils.QcbyUtils; import com.qcby.domain.Account; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; public class AccountDaoImpl implements AccountDao { public void save(Account account) { try{ Connection conn QcbyUtils.getConnection(); String sql insert into account values(null,?,?); PreparedStatement stmt conn.prepareStatement((sql)); stmt.setString(1,account.getName()); stmt.setDouble(2,account.getMoney()); stmt.executeUpdate(); stmt.close(); } catch (SQLException e){ e.printStackTrace(); } } }5.生成代理对象package com.qcby.JDKProxy; import com.qcby.Utils.QcbyUtils; import com.qcby.service.AccountService; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JdkProxy { public static Object getProxy(final AccountService accountService){ Object proxy Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() { Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result null; try{ QcbyUtils.startTransaction(); result method.invoke(accountService,args); QcbyUtils.commit(); } catch (Exception e){ e.printStackTrace(); QcbyUtils.rollback(); } return result; } }); return proxy; } }6.测试方法import com.qcby.JDKProxy.CglibProxy; import com.qcby.JDKProxy.JdkProxy; import com.qcby.dao.AccountDao; import com.qcby.dao.AccountDaoImpl; import com.qcby.domain.Account; import com.qcby.service.AccountService; import com.qcby.service.AccountServiceImpl; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.sql.SQLException; /** * 达内教育--腾讯课程认证机构 * 史招阳 */ public class DemoTest { Test public void run1() throws SQLException { ApplicationContext ac new ClassPathXmlApplicationContext(applicationContext.xml); // 获取service对象 AccountService accountService (AccountService) ac.getBean(accountService); Account account1 new Account(null,熊大,10000.00); Account account2 new Account(null,美羊羊,11000.00); // accountService.save(account1,account2); Object proxyobj JdkProxy.getProxy(accountService); AccountService proxy (AccountService) proxyobj; proxy.save(account1,account2); } }二、AOP相关的概念1.AOP的概述什么是AOP的技术在软件业AOP为Aspect Oriented Programming的缩写意为面向切面编程AOP是一种编程范式隶属于软工范畴指导开发者如何组织程序结构AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范通过预编译方式或者运行期动态代理实现程序功能的统一维护的一种技术AOP是OOP的延续是软件开发中的一个热点也是Spring框架中的一个重要内容是函数式编程的一种衍生范型利用AOP可以对业务逻辑的各个部分进行隔离从而使得业务逻辑各部分之间的耦合度降低提高程序的可重用性同时提高了开发的效率AOP:面向切面编程(思想,解决OOP遇到的一些问题)AOP采取横向抽取机制取代了传统纵向继承体系重复性代码性能监视、事务管理、安全检查、缓存为什么要学习AOP可以在不修改源代码的前提下对程序进行增强2. AOP的优势运行期间不修改源代码的情况下对已有的方法进行增强AOP优势1. 减少重复代码2. 提高开发效率3. 维护方便3. AOP的底层原理JDK 的动态代理技术1. 为接口创建代理类的字节码文件2. 使用 ClassLoader 将字节码文件加载到 JVM3. 创建代理类实例对象执行对象的目标方法CGLIB 代理技术