Java中的代理
来源:互联网 发布:特朗普 知乎 编辑:程序博客网 时间:2024/06/06 07:49
代理,简单的说就是将事情交给别人代替你去处理,典型的应用就是AOP(面向切面编程).
代理又分为静态代理和动态代理.
1.静态代理:直接为每一个实现类写一个代理类
package com.h.proxy;public interface HelloService { void say();}
package com.h.proxy;public class HelloServiceImpl implements HelloService { @Override public void say() { System.out.println("say hello"); }}
package com.h.proxy;/** * HelloServic的静态代理类 */public class HelloServiceProxy implements HelloService{ private HelloServiceImpl helloService; public HelloServiceProxy(HelloServiceImpl helloService) { this.helloService = helloService; } @Override public void say() { before(); helloService.say(); after(); } private void before(){ System.out.println("Before"); } private void after(){ System.out.println("After"); }}
客户端调用:
package com.h.proxy;public class Client { public static void main(String[] args) { HelloService helloServiceProxy = new HelloServiceProxy(new HelloServiceImpl()); helloServiceProxy.say(); }}
2.JDK动态代理
JDK动态代理的核心就是一个类java.lang.reflect.Proxy和他的一个方法newProxyInstance(),该方法的参数有三个:
参数1:ClassLoader
参数2:该实现类的所有接口
参数3:动态代理对象
package com.h.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class DynamicProxy implements InvocationHandler { private Object target; public DynamicProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(target,args); after(); return result; } private void before(){ System.out.println("Before"); } private void after(){ System.out.println("After"); }}
package com.h.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;public class Client { public static void main(String[] args) { HelloService helloService = new HelloServiceImpl(); ClassLoader classloader = helloService.getClass().getClassLoader(); Class<?>[] interfaces = helloService.getClass().getInterfaces(); InvocationHandler handler = new DynamicProxy(helloService); /** * 这里一定要强转为接口类型,而不能是具体的实现类,否则会抛出异常: java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.h.proxy.HelloServiceImpl,JDK的动态代理就是针对接口的代理 */ HelloService proxy = (HelloService) Proxy.newProxyInstance(classloader,interfaces,handler); proxy.say(); }}
上面的before()和after()方法都是写死的,能不能可以更灵活呢?
package com.h.proxy;public interface BeforeAdvise { void before();}
package com.h.proxy;public interface AfterAdvise { void after();}
package com.h.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.Objects;public class JDKDynamicProxy implements InvocationHandler{ /** * 代理目标 */ private Object target; /** * 前置增强 */ private BeforeAdvise beforeAdvise; /** * 后置增强 */ private AfterAdvise afterAdvise; /** * 构造函数注入代理目标类以及前/后置增强类 */ public JDKDynamicProxy(Object target, BeforeAdvise beforeAdvise, AfterAdvise afterAdvise) { this.target = target; this.beforeAdvise = beforeAdvise; this.afterAdvise = afterAdvise; } /** * 获取被代理后的对象,最终干活的 * @param <T> * @return */ public <T> T getProxy( ){ return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Objects.nonNull(beforeAdvise)){ beforeAdvise.before(); } Object result = method.invoke(target, args); if (Objects.nonNull(afterAdvise)){ afterAdvise.after(); } return result; }}
package com.h.proxy;public class Client { public static void main(String[] args) { JDKDynamicProxy jdkDynamicProxy = new JDKDynamicProxy(new HelloServiceImpl(), new BeforeAdvise() { @Override public void before() { System.out.println("Before"); } }, new AfterAdvise() { @Override public void after() { System.out.println("After"); } }); HelloService proxy = jdkDynamicProxy.getProxy(); proxy.say(); }}
JDK 给我们提供的动态代理只能代理接口,而不能代理没有接口的类。有什么方法可以解决呢?
3.CGLib动态代理
CGLib 类库可以代理没有接口的类,这样就弥补了 JDK 的不足。
package com.h.proxy;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;import java.util.Objects;public class CGLibDynamicProxy implements MethodInterceptor{ public <T>T getProxy(Class<T> cls){ return (T) Enhancer.create(cls,this); } public static CGLibDynamicProxy getInatance(){ return SingletonHolder.instance; } /** * 私有化构造方法 */ private CGLibDynamicProxy(){} /** * 类级的内部类,该内部类的实例与外部类的实例没有绑定关系, * 而且只有被调用到才会装载,从而实现了延迟加载 */ private static class SingletonHolder{ /** * 静态初始化器,由JVM来保证线程安全 * 静态成员仅被 JVM 加载一次,可以确保实例的唯一性。 */ private static CGLibDynamicProxy instance = new CGLibDynamicProxy(); } /** * 前置增强 */ private BeforeAdvise beforeAdvise; /** * 后置增强 */ private AfterAdvise afterAdvise; public void setBeforeAdvise(BeforeAdvise beforeAdvise) { this.beforeAdvise = beforeAdvise; } public void setAfterAdvise(AfterAdvise afterAdvise) { this.afterAdvise = afterAdvise; } @Override public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { if (Objects.nonNull(beforeAdvise)){ beforeAdvise.before(); } Object result = methodProxy.invokeSuper(target,objects); if (Objects.nonNull(afterAdvise)){ afterAdvise.after(); } return result; }}
package com.h.proxy;public class Client { public static void main(String[] args) { CGLibDynamicProxy dynamicProxy = CGLibDynamicProxy.getInatance(); dynamicProxy.setBeforeAdvise(new BeforeAdvise() { @Override public void before() { System.out.println("Before"); } }); dynamicProxy.setAfterAdvise(new AfterAdvise() { @Override public void after() { System.out.println("After"); } }); HelloServiceImpl proxy = dynamicProxy.getProxy(HelloServiceImpl.class); proxy.say(); }}
总结:jdk默认的动态代理就是接口的代理,所以必须有接口。cglib是针对类的,本质是继承了你的目标类,作为其子类进行方法调用的.但是注意,final 类是不能有子类的,而 CGLib 动态代理恰恰是要去生成这个子类,所以 CGLib 无法对 final 类进行动态代理,运行时会报错。此外,对于 final 方法是无效的,此时不会报错。
阅读全文
0 0
- Java中的代理模式
- JAVA中的代理技术
- Java中的代理模式
- Java中的代理
- Java中的代理模式
- java中的动态代理
- Java 中的代理模式
- java中的动态代理》》》》》
- 浅谈java中的代理
- JAVA 中的 动态代理
- java中的代理
- java中的动态代理
- java中的代理
- Java中的代理
- java中的动态代理
- Java中的动态代理
- Java中的动态代理
- JAVA中的动态代理
- Java集合之Set
- Spring整合JMS异步消息
- CSS Flex column排列时的容器宽度问题
- loadrunner将参数化的数据传给变量
- 【笔记】2-路插入排序
- Java中的代理
- 三、K-均值聚类算法对未标注的数据分组
- Spark Summit 2017 Europe全部PPT及视频下载[共69个]
- javascript之use strict
- 关于unity中使用yield return newWaitForSeconds()后面语句不执行
- java序列化与反序列化
- html分页功能
- canvas学习
- CommonJs