动态代理模式

tech2023-02-02  110

动态代理常用的有两种方式

基于接口的动态代理 提供者:JDK官方的Proxy类 要求:被代理类最少实现一个接口基于子类的动态代理 提供者:第三方的CGLib 要求:被代理类不能用final修饰的类(最终类)。 如何获取代理对象?(对本来的类的方法进行增强 也就是拦截) 1、首先定义一个功能接口 2、定义一个类,这个类至少实现了一个接口 3、适用JDK官方的Proxy类来创建 刚才我们创建的类 的代理对象 创建的方式: Proxy.newProxyInstance(三个参数) 参数的含义: 1、ClassLoader: 和被代理对象使用相同的类加载器 类加载器时通过类对象.getClassLoader()方法获得。 2、Interfaces: 和被代理对象具有相同的行为,实现相同的接口 自己创建的类实现的接口时通过类对象.getInterfaces()方法获得。 3、InvocationHandler:如何代理。 执行被代理对象的任何方法,都会经过该方法。 参数: 1、Proxy:代理对象的引用。不一定每次都用得到 2、method:当前执行的方法对象 3、args:执行方法所需的参数。 返回值: 当前执行方法的返回值

1、基于基于接口的动态代理

功能接口

public interface IActor { /** * 基本演出 * @param money */ public void basicAct(float money); /** * 危险演出 * @param money */ public void dangerAct(float money); }

实现接口的类

public class Actor implements IActor{ public void basicAct(float money){ System.out.println("拿到钱,开始基本的表演:"+money); } public void dangerAct(float money){ System.out.println("拿到钱,开始危险的表演:"+money); } }

基于接口创建代理对象

IActor proxyActor = (IActor) Proxy.newProxyInstance( actor.getClass().getClassLoader(), actor.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); Float money = (Float) args[0]; Object rtValue = null; //每个经纪公司对不同演出收费不一样,此处开始判断 if("basicAct".equals(name)){ if(money > 2000){ rtValue = method.invoke(actor, money/2); } } if("dangerAct".equals(name)){ if(money > 5000){ rtValue = method.invoke(actor, money/2); } } return rtValue; } } }); proxyActor.basicAct(8000f); proxyActor.dangerAct(50000f); } )

2、使用CGLib的Enhancer类创建代理对象

刚才的Actor一个类不实现接口 public class Actor{//没有实现任何接口 public void basicAct(float money){ System.out.println("拿到钱,开始基本的表演:"+money); } public void dangerAct(float money){ System.out.println("拿到钱,开始危险的表演:"+money); } } 基于子类的动态代理 要求:被代理对象不能时最终类 用到的类为 Enhancer 用到的方法:create(Class,Callback) 方法的参数: 1、Class:被代理对象的字节码 2、Callback:如何代理 Callback时当前执行方法 Actor cglibActor = (Actor) Enhancer.create(actor.getClass(), new MethodInterceptor() { @Override public Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable { String name = method.getName(); Float money = (Float) args[0]; Object rtValue = null; if("basicAct".equals(name)){ if(money > 2000){ rtValue = method.invoke(actor, money/2); } } if("dangerAct".equals(name)){ if(money > 5000){ rtValue = method.invoke(actor, money/2); } } return rtValue; } }); cglibActor.basicAct(10000); cglibActor.dangerAct(100000);

代理模式的用处举例

我们业务层实现类实现业务层接口 ,调用业务层的方法时,总是要开启事务,确保事务能够完整的执行 但是每一个业务层的方法加上事务的代码是很繁琐的,于是我们可以对业务层实现类进行方法的增强(本质就是对方法进行拦截处理)

public class BeanFactory { public static IAccountService getAccountService() { final IAccountService accountService = new AccountServiceImpl(); IAccountService proxyAccountService = (IAccountService) Proxy.newProxyInstance( accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method,Object[] args) throws Throwable { Object rtValue = null; try { //开启事务 TransactionManager.beginTransaction(); //执行业务层方法 rtValue = method.invoke(accountService, args); //提交事务 TransactionManager.commit(); }catch(Exception e) { //回滚事务 TransactionManager.rollback(); e.printStackTrace(); }finally { //释放资源 TransactionManager.release(); } return rtValue; } }); return proxyAccountService; } }

当我们改造完成之后,业务层用于控制事务的重复代码就都可以删掉了。

最新回复(0)