Java的动态代理

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

Java的动态代理

阿尔伯特-李古拉-逸凡   2020-03-16 我要评论
# Java的动态代理 动态代理: 特点:字节码随用随创建,随用随加载 作用:不修改源码的基础上对方法增强 分类: 基于接口的动态代理 基于子类的动态代理 # 一、java基于接口的动态代理 - 基于接口的动态代理: - 涉及的类:Proxy - 提供者:JDK官方 - 如何创建代理对象:使用Proxy类中的newProxyInstance方法 - 创建代理对象的要求:被代理类最少实现一个接口,如果没有则不能使用 - newProxyInstance方法的参数: - ClassLoader:类加载器,被代理对象的类加载器 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。 - Class[]:字节码数组,被代理对象的接口的字节码 它是用于让代理对象和被代理对象有相同方法,即实现接口方法。固定写法。 - InvocationHandler:用于提供增强的代码 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。 此接口的实现类都是谁用谁写。 这里用生产厂家和代理商举例说明 生产厂家的接口类:IProducer ```java package club.leyvan.proxy; /** * 对生产厂家要求的接口 */ public interface IProducer { /** * 销售 * @param money */ public void saleProduct(float money); /** * 售后 * @param money */ public void afterService(float money); } ``` 生产厂家的实现类: ```java package club.leyvan.proxy; /** * 一个生产者 */ 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); } } ``` 消费者类:Client ```java package club.leyvan.proxy /** * 模拟一个消费者 */ public class Client { public static void main(String[] args) { Producer producer = new Producer(); 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())) { returnValue = method.invoke(producer, money*0.8f); } return returnValue; } }); proxyProducer.saleProduct(10000f); } } } ``` 这样在不修改Producer类的情况下就可以对该对象进行增强 但如果Producer这个类没有实现接口那么上面的方法就不能够使用,于是我们再介绍第二种动态代理的方式 # 二、java基于子类的动态代理 - 基于子类的动态代理: - 涉及的类:Enhancer - 提供者:第三方cglib库 - 如何创建代理对象: 使用Enhancer类中的create方法 - 创建代理对象的要求:被代理类不能是最终类 - create方法的参数: - Class:字节码 它是用于指定被代理对象的字节码。 - Callback:用于提供增强的代码 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。 - 此接口的实现类都是谁用谁写。 - 我们一般写的都是该接口的子接口实现类:MethodInterceptor 需要第三方jar包的支持: ```xml cglib cglib 2.1_3 ``` Producer类:不实现接口 ```java package club.leyvan.cglib; /** * 一个生产者 */ public class Producer { /** * 销售 * @param money */ public void saleProduct(float money){ System.out.println("销售产品,并拿到钱:"+money); } /** * 售后 * @param money */ public void afterService(float money){ System.out.println("提供售后服务,并拿到钱:"+money); } } ``` Client类: ```java package club.leyvan.cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * 模拟一个消费者 */ public class Client { public static void main(String[] args) { final Producer producer = new Producer(); Producer cglibProducer = (Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() { /** * 执行北地阿里对象的任何方法都会经过该方法 * @param proxy * @param method * @param args * 以上三个参数和基于接口的动态代理中invoke方法的参数是一样的 * @param methodProxy :当前执行方法的代理对象 * @return * @throws Throwable */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //提供增强的代码 Object returnValue = null; //1.获取方法执行的参数 Float money = (Float)args[0]; //2.判断当前方法是不是销售 if("saleProduct".equals(method.getName())) { returnValue = method.invoke(producer, money*0.8f); } return returnValue; } }); cglibProducer.saleProduct(10000f); } } ``` # 三、动态代理的作用 - 可以通过动态代理,增强连接池的close()方法,使close()方法不是关闭连接,而是将连接放入连接池中 - 可以通过动态代理,增强getParameter()等方法,实现全局的乱码问题,当然这里还可以使用装饰者模式 # 四、使用动态代理实现事务控制(代理的代码) 使用工厂类创建代理类:BeanFactory类、最终使用的是从工厂中生产出来的service对象 ```java /** * 用于创建Service的代理对象的工厂 */ public class BeanFactory { private IAccountService accountService; /** * 用于管理事务的工具类,使用了ThreadLocal完成连接与线程的绑定 */ private TransactionManager txManager; public void setTxManager(TransactionManager txManager) { this.txManager = txManager; } public final 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("test".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(); } } }); } } ``` 被代理的service类: ```java /** * 账户的业务层实现类 * * 事务控制应该都是在业务层 */ public class AccountServiceImpl implements IAccountService{ private IAccountDao accountDao; public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } @Override public List 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 void transfer(String sourceName, String targetName, Float money) { System.out.println("transfer...."); //1根据名称查询转出账户 Account source = accountDao.findAccountByName(sourceName); //2根据名称查询转入账户 Account target = accountDao.findAccountByName(targetName); //3转出账户减钱 source.setMoney(source.getMoney()-money); //4转入账户加钱 target.setMoney(target.getMoney()+money); //5更新转出账户 accountDao.updateAccount(source); // int i=1/0; //6更新转入账户 accountDao.updateAccount(target); } } ``` 实现了事务与service层的分离

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们