动态代理技术的运用

2020-06-02 10:06:50 浏览数 (1)

在前一篇文章我们了解了Spring AOP的简单运用,我们发现面向切面编程的核心是动态代理,我们这篇文章主要就是看一下:JDK自带的动态代理和CGLIB的动态代理

注:JDK实现动态代理方式需要被代理的类拥有接口,CGLIB方式要求被代理类没有被final修饰

相关文章:Spring AOP的简单应用

Class类文件结构

01

JDK动态代理技术

首先定义一个接口

代码语言:javascript复制
interface SuperObject {
    void execute();
}

被代理类:

代码语言:javascript复制
class RealObject implements SuperObject {

    @Override
    public void execute() {
        System.out.println("执行方法");
    }
}

声明一个代理类需要我们实现reflect包下面的一个接口InvocationHandler。其中invoke方法我们大概看一下proxy就是被代理的类了,其中Method也是reflect包下的类,代表了类的方法。

代码语言:javascript复制
public class JdkProxy  implements InvocationHandler{
    @Override
    public Object invoke(Object proxy, Method method,         Object[] args) throws Throwable {
        return null;
    }
}

代理类对被代理类进行方法的增强:

代码语言:javascript复制
public class JdkProxy implements InvocationHandler {
    private Object target;

    public JdkProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置方法");
        Object o = method.invoke(target, args);
        System.out.println("后置方法");
        return o;
    }

}

测试:Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)返回某个对象的代理对象。其中第一个参数是类加载器,第二个参数是代理类实现的接口,这也是我们说为什么要代理类要实现接口才行。第三个参数是调用处理器,调用实现了InvocationHandler 类的一个回调方法

代码语言:javascript复制
    public static void main(String[] args) {
        SuperObject superObject = (SuperObject)
                Proxy.newProxyInstance(RealObject.class.getClassLoader(),
                RealObject.class.getInterfaces(),
                new JdkProxy(new RealObject()));
        superObject.execute();
    }

结果:

代码语言:javascript复制
Connected to the target VM, address: '127.0.0.1:50982', transport: 'socket'
前置方法
执行方法
后置方法
Disconnected from the target VM, address: '127.0.0.1:50982', transport: 'socket'

02

CGLib动态代理技术

使用CGLIB实现动态代理需要我们引入Jar包,这里我导入相应的依赖文件

代码语言:javascript复制
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.10</version>
</dependency>

定义被代理的类,这个类实现MethodInterceptor,可以理解为方法拦截器,并且实现其方法intercept。

代码语言:javascript复制
public class ProxySubject implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz) {
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
 //用于创建无参的目标对象代理类,对于有参构造器则调用Enhancer.create(Class[] argumentTypes, Object[] arguments),第一个参数表示参数类型,第二个参数表示参数的值。
        return enhancer.create();   
    }

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("前置方法");
        Object result = methodProxy.invokeSuper(object, args);
        System.out.println("后置方法");
        return result;
    }
}

测试:

代码语言:javascript复制
public class Main {
    public static void main(String[] args) {
        RealSubject subject = (RealSubject) new ProxySubject().getProxy(RealSubject.class);
        subject.sayHello();
   
    }
}

结果:

代码语言:javascript复制
Connected to the target VM, address: '127.0.0.1:50982', transport: 'socket'
前置方法
hello
后置方法
Disconnected from the target VM, address: '127.0.0.1:50982', transport: 'socket'

到这里就介绍了JDK与CGLib两种动态代理技术,最近自己空闲时间也在研究关于Spring AOP的实现源码,发现了不少新的东西:比如ASM和拦截链,ASM框架是一个致力于字节码操作和分析的框架,它可以用来修改一个已存在的类或者动态产生一个新的类,换句话说他可以修改class文件,前面我们有一篇文章聊到了class文件说明,在一些博客上我看到有人说一些高手可以直接修改class文件,来修改方法,大家可以私下研究研究。

0 人点赞