Java代理

Posted by Codeboy on May 27, 2019

代理是在开发中经常用到的一种模式,不暴露真实的对象,取而代之的提供代理对象,在代理对象中可以对实际操作的前后进行一些处理,也即流行的面向切面编程(AOP),Spring中的拦截器使用的就是代理模式。

我们对一个需要两步完成的任务,使用普通模式、静态代理、动态代理和cglib分别实现下:

准备工作

定义接口 ITask 和实现类 Task

package me.codeboy.test.proxy;

/**
 * 任务
 * Created by yuedong.li on 2019-05-27
 */
public interface ITask {
    /**
     * 步骤一
     */
    public void step1();

    /**
     * 步骤二
     */
    public void step2();
}

package me.codeboy.test.proxy;

/**
 * 任务
 * Created by yuedong.li on 2019-05-27
 */
public class Task implements ITask {
    @Override
    public void step1() {
        System.out.println("step1 print task!!");
    }

    @Override
    public void step2() {
        System.out.println("step2 print task!!");
    }
}

普通模式

该模式下,创建 Task 实例后,直接调用对应方法

package me.codeboy.test.proxy;

/**
 * 普通模式
 * Created by yuedong.li on 2019-05-27
 */
public class CommonMain {
    public static void main(String[] args) {
        ITask task = new Task();
        task.step1();
        task.step2();
    }
}

运行结果:

step1 print task!!
step2 print task!!

静态代理

由一个代理类来进行实际方法调用

package me.codeboy.test.proxy;

/**
 * 任务静态代理
 * Created by yuedong.li on 2019-05-27
 */
public class TaskStaticProxy implements ITask {
    private Task task;

    public TaskStaticProxy(Task task) {
        this.task = task;
    }

    @Override
    public void step1() {
        System.out.println("-----> before step1");
        task.step1();
        System.out.println("-----> after step1");
    }

    @Override
    public void step2() {
        System.out.println("-----> before step2");
        task.step2();
        System.out.println("-----> after step2");
    }
}
package me.codeboy.test.proxy;

/**
 * 静态代理
 * Created by yuedong.li on 2019-05-27
 */
public class StaticProxyMain {
    public static void main(String[] args) {
        ITask task = new TaskStaticProxy(new Task());
        task.step1();
        task.step2();
    }
}

运行结果:

> -----> before step1
> step1 print task!!
> -----> after step1
> -----> before step2
> step2 print task!!
> -----> after step2

动态代理

由Proxy创建一个代理 ITask 接口的代理来进行实际方法调用

package me.codeboy.test.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 任务动态代理
 * Created by yuedong.li on 2019-05-27
 */
public class TaskDynamicProxy implements InvocationHandler {
    private Task task;

    public TaskDynamicProxy(Task task) {
        this.task = task;
    }

    /**
     * 创建动态代理
     */
    public ITask getProxy() {
        return (ITask) Proxy.newProxyInstance(task.getClass().getClassLoader(), task.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-----> before " + method.getName());
        Object ret = method.invoke(task, args); //执行真正的方法
        System.out.println("-----> after " + method.getName());
        return ret;
    }
}
package me.codeboy.test.proxy;

/**
 * 动态代理
 * Created by yuedong.li on 2019-05-27
 */
public class DynamicProxyMain {
    public static void main(String[] args) {
        ITask task = new TaskDynamicProxy(new Task()).getProxy();
        task.step1();
        task.step2();
    }
}

运行结果:

-----> before step1
step1 print task!!
-----> after step1
-----> before step2
step2 print task!!
-----> after step2

cglib代理

创建一个代理 Task 类的代理类来进行实际方法调用

package me.codeboy.test.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * cglib代理
 * Created by yuedong.li on 2019-05-27
 */
public class TaskCglibProxy<T> implements MethodInterceptor {

    /**
     * 获取代理对象
     *
     * @param object 对象
     * @return proxy 对象
     */
    public T getProxy(T object) {
        Enhancer enhancer = new Enhancer(); //创建Enhancer来生成动态代理类
        enhancer.setSuperclass(object.getClass());
        enhancer.setCallback(this);  //设置回调,之后所有的方法调用将会执行intercept方法
        return (T) enhancer.create();
    }

    /**
     * 代理对象的执行会回调到此方法中
     */
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("-----> before " + method.getName());
        Object result = proxy.invokeSuper(obj, args); //调用业务类的方法
        System.out.println("-----> after " + method.getName());
        return result;
    } 
}
package me.codeboy.test.proxy;

/**
 * cglib代理
 * Created by yuedong.li on 2019-05-27
 */
public class CglibProxyMain {
    public static void main(String[] args) {
        ITask task = new TaskCglibProxy<ITask>().getProxy(new Task());
        task.step1();
        task.step2();
    }
}

运行结果:

-----> before step1
step1 print task!!
-----> after step1
-----> before step2
step2 print task!!
-----> after step2

小结

根据上面的例子,简单的总结一下几种代理模式的使用场景和特点:

类型 场景 特点
静态代理 代理比较简单的类 代理多个方法后会比较繁琐,可能会有很多重复代码
动态代理 代理接口 只能代理接口,不能代理实现类
cglib代理 代理实现类 和动态代理互补

如有任何知识产权、版权问题或理论错误,还请指正。

转载请注明原作者及以上信息。