文章目录
动态代理(dynamic proxy)
1. 什么是动态代理
动态代理比起静态代理更加重要,因为动态代理使用的范围比起静态代理更广,所以也更加普遍。需要好好地进行研究。
动态代理的本意是,在以后的程序的进行中呢,代理类的内容不需要自己去编写了。
在编写静态代理类的时候,我们需要编写两个类,一个真实角色类,一个代理角色类。
在动态代理中,代理类的生成,都是交给工具来实现的。所以称为动态生成代理类。
2. 动态代理(动态生成代理类)的几种方式:
- JDK自带的动态代理类
- javaassist 字节码操作库实现
- CGLIB
- ASM(底层使用指令,可维护性差)
3. 动态代理相比较静态代理的优点
- 抽象角色中(接口)声明的所有方法都被转移到调用处理器一个几种的方法中处理,这样我们可以更加灵活和统一的处理众多的方法。
3. 动态代理(JDK 自带的实现)
-
JDK 自带的动态代理
-
java.lang.reflect.proxy
- 作用:动态生成代理类和对象
-
java.lang.reflect.InvocationHandler (处理器接口)
- 可以通过 invoke 方法实现对真实角色的代理访问。
- 每次通过 Proxy 方法生成代理类对象时都要指定对应的处理器对象
Star realStar = new RealStar(); StarHandler handler = new StarHandler(readStar); Star proxy = (Star) Proxy.newProxyInstance(Class.Loader.getSystemClassLoader(), new Class[]{Star.class}, handler); proxy.sing();
这里以之前的歌手和经纪人之间的关系做类比。
首先,realStar 是我们的真实角色,下面的 Handler 是处理器接口,将真实角色传入进去。StarHandler 主要用来作我们的流程控制。然后呢,通过 Proxy 生成一个代理对象。然后去调用代理对象的方法 Proxy.sing()。在 Proxy.newProxyInstance() 方法中,传入了类加载器 Class.Loader.getSystemClassLoader(), 使用我们系统默认的;然后还有 Star.class 这个接口,我们将接口传入 Class[] (因为生成的不止一个),这个代理类就会自动地实现这个接口,最后一个参数是处理器。这是一个固定的套路
-
4. 使用代码实现动态代理
还是以歌手和经纪人之间的关系为类比:
-
首先还是先创建抽象角色:
package com.designmodel.proxy.dynamicproxy; public interface Star { /** * 面谈 */ void confer(); /** * 签合同 */ void signContract(); /** * 订票 */ void bookTicket(); /** * 唱歌 */ void sing(); /** * 收钱 */ void collectMoney(); }
-
然后依据抽象角色创建真实角色:
package com.designmodel.proxy.dynamicproxy; public class RealStar implements Star { public void confer() { System.out.println("RealStar.confer()"); } public void signContract() { System.out.println("RealStar.signContact()"); } public void bookTicket() { System.out.println("RealStar.bookTicket()"); } public void sing() { System.out.println("RealStar(周杰伦本人).sing()"); } public void collectMoney() { System.out.println("RealStar.collectMoney()"); } }
-
然后创建处理器:
package com.designmodel.proxy.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class StarHandler implements InvocationHandler { Star realStar; public StarHandler(Star realStar) { this.realStar = realStar; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object object = null; // 所有的方法调用都会从这里进入, 只有当调用的方法是 sing 方法,我们才会让 // 歌手去唱歌 System.out.println("真正的方法执行前:"); System.out.println("面谈,签合同,预付款,订机票"); if(method.getName().equals("sing")) { object = method.invoke(realStar, args); } System.out.println("唱完歌之后:"); System.out.println("收尾款"); return object; } }
-
最后在客户端中进行调用:
package com.designmodel.proxy.dynamicproxy; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { Star realStar = new RealStar(); StarHandler handler = new StarHandler(realStar); // 这里返回了一个 Star 对象 Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, handler); // 运行时,我们会发现,所有的方法调用,最终都会进入 StarHandler.invoke() 方法中 // 这样我们就可以进行流程的控制了。 proxy.sing(); } }
-
运行结果:
/* * 真正的方法执行前: * 面谈,签合同,预付款,订机票 * RealStar(周杰伦本人).sing() * 唱完歌之后: * 收尾款 */