动态代理之AOP

    xiaoxiao2022-07-13  179

    引入

    转账案例:不加事务管理,出现异常时,转账错误

    /** * 账户的业务层实现类 */ public class AccountServiceImpl implements IAccountService{ @Autowired private IAccountDao accountDao; @Autowired private TransactionManager txManager; public void setTxManager(TransactionManager txManager) { this.txManager = txManager; } public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } @Override public List<Account> findAllAccount() { return accountDao.findAllAccount(); } @Override public Account findAccountById(Integer accountId) { return accountDao.findAccountById(accountId); } @Override public void saveAccount(Account account) { accountDao.saveAccount(account); } @Override public void updateAccount(Account account) { accountDao.updateAccount(account); } @Override public void deleteAccount(Integer acccountId) { accountDao.deleteAccount(acccountId); } @Override public Account findAccountByName(String accountName) { return accountDao.findAccountByName(accountName); } @Override public void transfer(String sourceName, String targetName, Float money) { //根据名称查询转出账户 Account source = accountDao.findAccountByName(sourceName); //根据名称查询转入账户 Account target = accountDao.findAccountByName(targetName); //转出账户减钱 source.setMoney(source.getMoney()-money); //转入账户加钱 target.setMoney(target.getMoney()+money); //更新转出账户 accountDao.updateAccount(source); //模拟异常 int i = 1/0; //更新转入账户 accountDao.updateAccount(target); } }

    加事务管理,代码过于冗余

    /** * 账户的业务层实现类 * * 事务控制应该都是在业务层 */ public class AccountServiceImpl_OLD implements IAccountService{ private IAccountDao accountDao; private TransactionManager txManager; public void setTxManager(TransactionManager txManager) { this.txManager = txManager; } public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } @Override public List<Account> findAllAccount() { try { //1.开启事务 txManager.beginTransaction(); //2.执行操作 List<Account> accounts = accountDao.findAllAccount(); //3.提交事务 txManager.commit(); //4.返回结果 return accounts; }catch (Exception e){ //5.回滚操作 txManager.rollback(); throw new RuntimeException(e); }finally { //6.释放连接 txManager.release(); } } @Override public Account findAccountById(Integer accountId) { try { //1.开启事务 txManager.beginTransaction(); //2.执行操作 Account account = accountDao.findAccountById(accountId); //3.提交事务 txManager.commit(); //4.返回结果 return account; }catch (Exception e){ //5.回滚操作 txManager.rollback(); throw new RuntimeException(e); }finally { //6.释放连接 txManager.release(); } } @Override public void saveAccount(Account account) { try { //1.开启事务 txManager.beginTransaction(); //2.执行操作 accountDao.saveAccount(account); //3.提交事务 txManager.commit(); }catch (Exception e){ //4.回滚操作 txManager.rollback(); }finally { //5.释放连接 txManager.release(); } } @Override public void updateAccount(Account account) { try { //1.开启事务 txManager.beginTransaction(); //2.执行操作 accountDao.updateAccount(account); //3.提交事务 txManager.commit(); }catch (Exception e){ //4.回滚操作 txManager.rollback(); }finally { //5.释放连接 txManager.release(); } } @Override public void deleteAccount(Integer acccountId) { try { //1.开启事务 txManager.beginTransaction(); //2.执行操作 accountDao.deleteAccount(acccountId); //3.提交事务 txManager.commit(); }catch (Exception e){ //4.回滚操作 txManager.rollback(); }finally { //5.释放连接 txManager.release(); } } @Override public Account findAccountByName(String accountName) { try { //1.开启事务 txManager.beginTransaction(); //2.执行操作 Account account = accountDao.findAccountByName(accountName); //3.提交事务 txManager.commit(); //4.返回结果 return account; }catch (Exception e){ //5.回滚操作 txManager.rollback(); throw new RuntimeException(e); }finally { //6.释放连接 txManager.release(); } } @Override public void transfer(String sourceName, String targetName, Float money) { try { //1.开启事务 txManager.beginTransaction(); //2.执行操作 //根据名称查询转出账户 Account source = accountDao.findAccountByName(sourceName); //根据名称查询转入账户 Account target = accountDao.findAccountByName(targetName); //转出账户减钱 source.setMoney(source.getMoney()-money); //转入账户加钱 target.setMoney(target.getMoney()+money); //更新转出账户 accountDao.updateAccount(source); //异常 int i = 1/0; //更新转入账户 accountDao.updateAccount(target); //3.提交事务 txManager.commit(); }catch (Exception e){ //4.回滚操作 txManager.rollback(); }finally { //5.释放连接 txManager.release(); } } }

    事务管理工具类

    /** * 和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接 */ public class TransactionManager { private ConnectionUtils connectionUtils; public void setConnectionUtils(ConnectionUtils connectionUtils) { this.connectionUtils = connectionUtils; } /** * 开启事务 */ // 前置通知 public void beginTransaction(){ try { connectionUtils.getThreadConnection().setAutoCommit(false);//开启事务 }catch (Exception e){ e.printStackTrace(); } } /** * 回滚事务 */ // 异常通知 public void rollback(){ try { connectionUtils.getThreadConnection().rollback(); }catch (Exception e){ e.printStackTrace(); } } /** * 提交事务 */ // 后置通知 public void commit(){ try { connectionUtils.getThreadConnection().commit();//还回连接池中 }catch (Exception e){ e.printStackTrace(); } } /** * 释放连接 */ // 最终通知 public void release(){ try { connectionUtils.getThreadConnection().close(); // 从当前线程解绑连接对象 connectionUtils.removeConnection(); }catch (Exception e){ e.printStackTrace(); } } }

    基于接口的动态代理回顾

    /** * 模拟一个消费者 */ public class Client { public static void main(String[] args) { final Producer producer = new Producer();//被代理对象 /** * 动态代理: * 特点:字节码随用随创建,随用随加载 * 作用:不修改源码的基础上对方法增强 * 分类: * 基于接口的动态代理 * 基于子类的动态代理 * 基于接口的动态代理: * 涉及的类:Proxy * 提供者:JDK官方 * 如何创建代理对象: * 使用Proxy类中的newProxyInstance方法 * 创建代理对象的要求: * 被代理类最少实现一个接口,如果没有则不能使用 * newProxyInstance方法的参数: * ClassLoader:类加载器 * 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。 * Class[]:字节码数组 * 它是用于让代理对象和被代理对象有相同方法。固定写法。 * InvocationHandler:用于提供增强的代码 * 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。 * 此接口的实现类都是谁用谁写。 */ IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() { /** * 作用:执行被代理对象的任意接口方法 * 接口中的所有方法都会被其拦截并执行 * 方法参数的含义 * @param proxy 代理对象的引用 * @param method 当前执行的方法 * @param args 当前执行方法所需的参数 * @return 和被代理对象方法有相同的返回值 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //提供增强的代码 Object returnValue = null; //1.获取方法执行的参数 Float money = (Float)args[0]; //2.判断当前方法是不是销售 if("saleProduct".equals(method.getName())) { // money*0.8会将我们的数据从float类型转成double类型 returnValue = method.invoke(producer, money*0.8f); } return returnValue; } }); proxyProducer.saleProduct(10000f); //代理对象 执行增强的方法 } } /** * 对生产厂家要求的接口 */ public interface IProducer { /** * 销售 * @param money */ public void saleProduct(float money); /** * 售后 * @param money */ public void afterService(float money); } /** * 一个生产者 */ public class Producer implements IProducer{ /** * 销售 * @param money */ public void saleProduct(float money){ System.out.println("销售产品,并拿到钱:"+money); } /** * 售后 * @param money */ public void afterService(float money){ System.out.println("提供售后服务,并拿到钱:"+money); } }

    使用动态代理实现事务控制

    创建Service的代理对象的工厂

    /** * 用于创建Service的代理对象的工厂 */ public class BeanFactory { private IAccountService accountService; private TransactionManager txManager; public final void setTxManager(TransactionManager txManager) { this.txManager = txManager; } public void setAccountService(IAccountService accountService) { this.accountService = accountService; } /** * 获取Service代理对象 * @return */ public IAccountService getAccountService() { return (IAccountService)Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() { /** * 添加事务的支持 * * @param proxy * @param method * @param args * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //判断是否查询方法,如果是,则不需要事务支持,直接放行即可 if ("findAllAccount".equals(method.getName())) { return method.invoke(accountService, args); } Object rtValue = null; try { //1.开启事务 txManager.beginTransaction(); //2.执行操作 rtValue = method.invoke(accountService, args); //3.提交事务 txManager.commit(); //4.返回结果 return rtValue; } catch (Exception e) { //5.回滚操作 txManager.rollback(); throw new RuntimeException(e); } finally { //6.释放连接 txManager.release(); } } }); } }

    bean.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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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/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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--配置代理的service--> <bean id="proxyAccountService" factory-bean="beanFactory" factory-method="getAccountService"></bean> <!--配置beanfactory--> <bean id="beanFactory" class="com.sz.factory.BeanFactory"> <!-- 注入service --> <property name="accountService" ref="accountService"></property> <!-- 注入事务管理器 --> <property name="txManager" ref="txManager"></property> </bean> <!--配置Service--> <bean id="accountService" class="com.sz.service.impl.AccountServiceImpl"> <!--注入Dao--> <!--set方式注入 会先调用默认构造函数 如果仅仅自定义了有参构造函数将其覆盖 set注入则报错--> <property name="accountDao" ref="accountDao"></property> </bean> <!--配置Dao对象--> <bean id="accountDao" class="com.sz.dao.impl.AccountDaoImpl"> <!-- 注入QueryRunner --> <property name="runner" ref="runner"></property> <!-- 注入ConnectionUtils --> <property name="connectionUtils" ref="connectionUtils"></property> </bean> <!-- 配置Connection的工具类 ConnectionUtils --> <bean id="connectionUtils" class="com.sz.utils.ConnectionUtils"> <!-- 注入数据源--> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置QueryRunner--> <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"> <!--<constructor-arg name="ds" ref="dataSource"></constructor-arg>--> </bean> <!-- 配置数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!--连接数据库的必备信息--> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_account"></property> <property name="user" value="root"></property> <property name="password" value="123"></property> </bean> <!-- 配置事务管理器--> <bean id="txManager" class="com.sz.utils.TransactionManager"> <!-- 注入ConnectionUtils --> <property name="connectionUtils" ref="connectionUtils"></property> </bean> </beans>

    持久层实现类

    /** * 账户的业务层实现类 */ //@Service("accountService") public class AccountServiceImpl implements IAccountService{ @Autowired private IAccountDao accountDao; @Autowired private TransactionManager txManager; public void setTxManager(TransactionManager txManager) { this.txManager = txManager; } public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } @Override public List<Account> findAllAccount() { return accountDao.findAllAccount(); } @Override public Account findAccountById(Integer accountId) { return accountDao.findAccountById(accountId); } @Override public void saveAccount(Account account) { accountDao.saveAccount(account); } @Override public void updateAccount(Account account) { accountDao.updateAccount(account); } @Override public void deleteAccount(Integer acccountId) { accountDao.deleteAccount(acccountId); } @Override public Account findAccountByName(String accountName) { return accountDao.findAccountByName(accountName); } @Override public void transfer(String sourceName, String targetName, Float money) { // try { // //1.开启事务 // txManager.beginTransaction(); // //2.执行操作 // //根据名称查询转出账户 // Account source = accountDao.findAccountByName(sourceName); // //根据名称查询转入账户 // Account target = accountDao.findAccountByName(targetName); // //转出账户减钱 // source.setMoney(source.getMoney()-money); // //转入账户加钱 // target.setMoney(target.getMoney()+money); // //更新转出账户 // accountDao.updateAccount(source); // //异常 // //int i = 1/0; // //更新转入账户 // accountDao.updateAccount(target); // //3.提交事务 // txManager.commit(); // }catch (Exception e){ // //4.回滚操作 // txManager.rollback(); // }finally { // //5.释放连接 // txManager.release(); // } //2.1根据名称查询转出账户 Account source = accountDao.findAccountByName(sourceName); //2.2根据名称查询转入账户 Account target = accountDao.findAccountByName(targetName); //2.3转出账户减钱 source.setMoney(source.getMoney()-money); //2.4转入账户加钱 target.setMoney(target.getMoney()+money); //2.2更新转出账户 accountDao.updateAccount(source); //模拟异常 //int i = 1/0; //2.5更新转入账户 accountDao.updateAccount(target); } }

     

    最新回复(0)