Java中的代理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/G0_hw/article/details/78434080

代理,简单的说就是将事情交给别人代替你去处理,典型的应用就是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 方法是无效的,此时不会报错。

阅读更多
换一批

没有更多推荐了,返回首页