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 方法是无效的,此时不会报错。