使用过spring的读者都会知道,spring有一个强大的功能——面向切面编程(AOP)。AOP底层其实是基于Java的动态代理的。本篇文章就来了解一下动态代理机制。
Java的动态代理机制实现方式有两种,一种是基于JDK自带的动态代理机制,一种是基于cglib的动态代理机制。说到JDK自带的动态代理机制,我们不得不说一下InvocationHandler接口。我们看一下JDK中InvocationHandler源码:
public interface InvocationHandler {
/**
* 集中处理代理类的方法调用
*
* @param proxy 代理类的实例
* @param method 代理类调用的方法实例
* @param args 调用方法参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
可以看到,InvocationHandler是一个接口,里面只提供一个invoke方法。所有需要动态代理类都需要实现此接口,并且每一个代理类都关联到一个InvocationHandler,当我们调用代理类的方法的时候,就会触发invoke方法。
在Java动态代理机制中,我们还会使用到Proxy类,这个类负责创建具体代理类的实例,我们可以调用Proxy的静态方法newProxyInstance来创建具体代理类的实例。
下面,我们通过一个例子来学习JDK自带的动态代理机制:
创建一个接口
public interface IProgrammer {
void code();
void commit();
}
实现接口(被代理的类)
public class WebProgrammer implements IProgrammer {
public void code() {
System.out.println("工程师编写代码");
}
public void commit() {
System.out.println("工程师提交代码");
}
}
创建一个类,实现InvocationHandler的接口(用于创建代理类)
public class ProgrammerProxy implements InvocationHandler {
/**
* 被代理类实例
*/
private Object delegate;
/**
* 绑定被代理对象,返回代理类实例
*
* @param delegate 被代理类的对象
* @return 代理类实例
*/
public Object bind(Object delegate) {
this.delegate = delegate;
return Proxy.newProxyInstance(this.delegate.getClass().getClassLoader(),
this.delegate.getClass().getInterfaces(), this);
}
/**
* 集中处理代理类的方法调用
*
* @param proxy 代理类的实例
* @param method 代理类调用的方法实例
* @param args 调用方法参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object rs = null;
System.out.println(" method " + method.getName() + " is executing");
if (method.getName().equals("code")) {
System.out.println("工程师和产品经理确认需求,需求清晰");
} else if (method.getName().equals("commit")) {
System.out.println("CTO进行代码评审,代码质量可靠");
}
rs = method.invoke(this.delegate, args);
return rs;
}
}
测试代码
public class Client {
public static void main(String[] args) {
ProgrammerProxy proxy = new ProgrammerProxy();
WebProgrammer webProgrammer = new WebProgrammer();
IProgrammer programmer = (IProgrammer) proxy.bind(webProgrammer);
programmer.code();
programmer.commit();
}
}
运行测试类,输出
method code is executing
工程师和产品经理确认需求,需求清晰
工程师编写代码
method commit is executing
CTO进行代码评审,代码质量可靠
工程师提交代码
分析例子,我们可以知道,使用JDK自带的动态代理机制,我需要如下步骤:
-
创建代理类生成器,实现InvocationHandler接口(ProgrammerProxy)
-
创建被代理类(WebProgrammer)
-
使用代理类生成器创建代理类
-
执行代理类方法
那么,JDK的动态代理机制有哪些使用场景呢?开篇说了,Spring的AOP就是基于Java的动态代理机制的。凡是AOP可以使用到的地方,都是Java动态代理机制的使用场景。然而,不一定是JDK自带的动态代理机制的使用场景,因为Spring的AOP可以基于cglib进行对类的动态代理,而JDK自带的动态代理机制是对接口的动态代理,也就是说所有代理类都需要实现同一接口InvocationHandler。总之,Spring的AOP大多数的使用场景都是JDK自带动态代理的使用场景。