Java动态代理

动态代理

实现方式一,JDK动态代理
public class Main {
    public static void main(String[] args) {
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        Hello hello = (Hello) myInvocationHandler.newProxy(new HelloWorld());
        hello.morning("lin");
    }
}
// 目标接口
public interface Hello {
    void morning(String name);
}

// 目标类
public class HelloWorld implements Hello {
    @Override
    public void morning(String name) {
        System.out.println("Good Moning,"+name);
    }
}

// 代理类;方法调用会被转发到该类的invoke()方法。
class MyInvocationHandler implements InvocationHandler{
    // 目标代理对象,本例中的HelloWorld的实例
    private Object targetObject;
    // 构造代理对象
    public Object newProxy(Object targetObject){
        this.targetObject = targetObject;
        return Proxy.newProxyInstance(
                targetObject.getClass().getClassLoader(), //
                targetObject.getClass().getInterfaces(),
                this
        );
    }
    //利用反射,在原逻辑上进行增强
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理执行之前");
        Object invoke = method.invoke(targetObject, args);
        System.out.println("代理执行之后");
        return invoke;
    }
}
//打印结果:
代理开始之前
Good Moning,lin
代理开始之后

调用过程中的堆栈信息:

image.png

实现方式二,CGLIB动态代理

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。 首先导入maven依赖

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>

因为没有实现接口该类无法使用JDK代理,通过CGLIB代理实现如下:

  1. 首先实现一个MethodInterceptor,方法调用会被转发到该类的intercept()方法。
  2. 然后在需要使用HelloJava的时候,通过CGLIB动态代理获取代理对象。
// 目标类
public class HelloJava {
    public void hello(String name){
        System.out.println("hello,"+name);
    }
}
// 代理类
class MyMethodInterceptor implements MethodInterceptor{
	// 进行增强
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理执行之前");
        Object res = methodProxy.invokeSuper(o, args);
        System.out.println("代理执行之后");
    }
}
public class Main {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(HelloJava.class);
        enhancer.setCallback(new MyMethodInterceptor());

        // 通过enhancer创建HelloJava实例
        HelloJava helloJava = (HelloJava) enhancer.create();
        helloJava.hello("lin");
    }
}
// 结果输出:
代理执行之前
hello,lin
代理执行之后

调用过程中的堆栈信息:

image.png

总结动态代理对象

动态代理是JDK在运行期动态使用反射机制创建class字节码并加载的过程,通过动态代理,我们可以在对象创建前后进行增强,或者对象方法调用前后进行增强,在Spring中借助该技术实现了AOP。