Java两种动态代理

162 阅读2分钟

代理模式

这是十分重要的一个设计模式,在我理解就是在调用实际的业务逻辑对象的方法之前之后添加一些预先业务逻辑和后置的业务逻辑。例如,一个学生有一个去上课的方法,在调用这个方法之前,需要检查衣服是否符合学校规范,检查书包文具用品是否带齐等逻辑。

JDK动态代理

下面为一个简单的动态代理实现过程。 首先动态代理一定要先为需要代理的对象写一个接口,以便后续的代理对象挂在这一接口下。

package Chapter2;

public interface Student {
    void goToSchool();
}

实现类StudentImpl

public class StudentImpl implements Student{
    String studentName;
    
    StudentImpl(String name){
       this.studentName = name;
    }
    
    @Override
    public void goToSchool() {
        System.out.println(this.studentName + " is on the way to school....");
    }
}

实现代理类

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

public class StudentProxy implements InvocationHandler {
    StudentImpl realStudent = null;

    public Object bind(StudentImpl student){
        this.realStudent = student;

        return Proxy.newProxyInstance(realStudent.getClass().getClassLoader(),
                    student.getClass().getInterfaces(),
                    this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("checking uniforms...");
        System.out.println("checking bag...");
        
        Object ret = method.invoke(realStudent);
        
        System.out.println("finished...");
        
        return ret;
    }
}

bind方法将一个实际的对象绑定给一个代理对象,newProxyInstance方法第一个参数就是实际对象的类加载器,第二个参数为代理对象将要挂在的一个接口,这里即为Student接口,第三个参数为定义实现方法逻辑的代理类,这里为this。 代理类必须要override的一个方法:invoke 这里定义了代理类的实现方法逻辑。

下面为测试类代码

public class StudentJdkTest {
    public static void main(String[] args) {
        StudentImpl realStudent = new StudentImpl("Henry");

        StudentProxy studentProxy = new StudentProxy();
        Student student = (Student) studentProxy.bind(realStudent);
        student.goToSchool();
    }
}

输出结果:

checking uniforms...
checking bag...
Henry is on the way to school....
finished...

CGLIB动态代理

在一些无法生成接口的情况下,JDK动态代理就变得无法使用了,这时候,就需要用第三方代理,CGLIB就是很好的一个选择。

实现代理类

package Chapter2;

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.ArrayList;
import java.util.List;

public class StudentProxyCGLIB implements MethodInterceptor {
    public Object getProxy(Class cls, String name){
        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(cls);
        enhancer.setCallback(this);

        Class[] argumentTypes = new Class[1];
        Object[] arguments = new Object[1];

        argumentTypes[0] = String.class;
        arguments[0] = name;
        return enhancer.create(argumentTypes,arguments);
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("checking uniforms...");
        System.out.println("checking bag...");
    
        Object ret = methodProxy.invokeSuper(o, null);

        System.out.println("finished...");

        return ret;
    }
}

CGLIB通过enhancer来设置超类代理,回调类为this。 测试类代码

package Chapter2;

public class StudentCDLIBTest {
    public static void main(String[] args) {
        StudentProxyCGLIB studentProxyCGLIB = new StudentProxyCGLIB();

        StudentImpl student = (StudentImpl) studentProxyCGLIB.getProxy(StudentImpl.class, "Henry");
        student.goToSchool();
    }
}

测试结果同上。