java代理分为静态代理和动态代理,在spring的核心AOP中,我们用到了动态代理,其中包括jdk自带的代理以及通过第三方cglib字节码的方式实现动态代理,所以学习好动态代理有助于我们理解spring的aop,本篇文章主要讲解jdk自身的动态代理。
jdk自身的代理我们就需要知道InvocationHandler和Proxy,我们看下官方的文档介绍:
/**
* {@code InvocationHandler} is the interface implemented by
* the <i>invocation handler</i> of a proxy instance.
* <p>Each proxy instance has an associated invocation handler.
* When a method is invoked on a proxy instance, the method
* invocation is encoded and dispatched to the {@code invoke}
* method of its invocation handler.
*/
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用.
再看下Proxy的方法:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
这个方法的作用就是创建一个代理类对象,它接收三个参数,我们来看下几个参数的含义:
loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载
interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法。
h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用。
下面我们看下具体的例子:
首先定义动物接口类:
package com.proxy;
public interface Animal {
void eat();
}
然后狗实现了动物的eat方法:
package com.proxy;
public class Dog implements Animal {
@Override
public void eat() {
System.out.println("dog eat");
}
}
然后我们写一个eat的处理程序:
package com.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class EatHandler implements InvocationHandler {
private Object obj;
public EatHandler() {
}
public EatHandler(Object obj) {
this.obj = obj;
}
/**
* 通过Proxy类的newProxyInstance方法创建代理对象,我们来看下方法中的参数
* 第一个参数:people.getClass().getClassLoader(),使用handler对象的classloader对象来加载我们的代理对象
* 第二个参数:people.getClass().getInterfaces(),这里为代理类提供的接口是真实对象实现的接口,这样代理对象就能像真实对象一样调用接口中的所有方法
* 第三个参数:handler,我们将代理对象关联到上面的InvocationHandler对象上
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//具体要操作的地方
System.out.println("before invoke。。。");
Object invoke = method.invoke(obj, args);
System.out.println("after invoke。。。");
return invoke;
}
}
接下来我们测试:
package com.proxy;
import java.lang.reflect.Proxy;
import org.junit.jupiter.api.Test;
class ProxyTest {
@Test
void test() {
Animal dog = new Dog();
EatHandler handler = new EatHandler(dog);
Animal dogProxy = (Animal) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
dog.getClass().getInterfaces(), handler);
dogProxy.eat();
}
}
我们看看测试结果:
before invoke。。。
dog eat
after invoke。。。
总结:上面只是简单的介绍了jdk的动态代理和应用,实际aop中用到的会比这个复杂了多。