概念
说到动态代理就会联想到热门的java框架spring中强大的AOP功能,使用AOP将切面,与主体相分离,增加了程序的灵活性。那到底什么是动态代理呢?其实所谓的动态代理跟反射一样,是java中的一个动态特性:
- 可以在运行时动态创建一个类,实现一个或者多个接口
- 可以在不修改原有类的基础上动态为通过该类获取的对象添加方法,修改行为,并广泛的应用于spring,mybatis等热门的框架中
在java中与动态代理相对应的就是静态代理,我们这里先讨论一下什么是静态代理
静态代理
静态代理是一种设计模式,代理背后一般至少有一个实际对象 我们来看一个例子:
public class SimpleStaticProxyDemo {
static interface IService{
public void sayHello();
}
//被代理的类
static class RealService implements IService{
@Override
public void sayHello() {
System.out.println("hello");
}
}
//实际代理的类
static class TraceProxy implements IService{
//让代理的类就有被代理类的功能
private IService realService;
public TraceProxy(IService realService){
this.realService = realService;
}
@Override
public void sayHello() {
//不改变原来的程序,并加入新的东西,下面同理
System.out.println("进入 sayHello");
realService.sayHello();
System.out.println("离开 sayHello");
}
}
public static void main(String[] args) {
//实例化元类
IService realService = new RealService();
//实例化代理类
IService proxyService = new TraceProxy(realService);
proxyService.sayHello();
}
}
代理和实际的对象一般会有一个相同的接口:IService
实际的对象:RealService
那自然代理它的就是:TraceProxy并且在构造方法中传入被代理类的对象
我们简单的理解就是TraceProxy代理了RealService的功能,并且在它的基础上添加了打印日志的功能:System.out.println("进入 sayHello");和System.out.println("离开 sayHello");并且并没有修改原有的类。并且最后通过TraceProxy的对象调用sayHello()达到同样的功能。
程序运行结果:
但是这样其实很麻烦,比如我们有很多的类需要代理的话,那么就需要为每个类都要写一个代理类,这样就不太好了,那么此时动态代理就孕育而出了。
动态代理
先看一个动态代理的例子:
public class SimpleJDKDynamicproxyDemo {
static interface IService{
public void sayHello();
}
//元类
static class RealService implements IService{
@Override
public void sayHello() {
System.out.println("hello");
}
}
//代理类
static class SimpleInvocationHandler implements InvocationHandler {
private Object realObj;
public SimpleInvocationHandler(Object realObj) {
this.realObj = realObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入" + method.getName());
//达到了调用实际对象对应的方法的目的
Object result = method.invoke(realObj,args);
System.out.println("离开" + method.getName());
return result;
}
}
public static void main(String[] args) {
//实例化元类
IService realService = new RealService();
//实例化代理类
IService proxyService = (IService) Proxy.newProxyInstance(
IService.class.getClassLoader(),
new Class<?>[]{IService.class},
new SimpleInvocationHandler(realService));
proxyService.sayHello();
}
}
就是让代理类去implements一个接口InvocationHandler,并且重写接口里面的方法invoke,invoke中的参数意思如下:
- proxy:表示代理对象本身,不是被代理的对象,这个参数一般用处不大
- method: 表示正在被调用的方法
- args: 表示方法的参数
与静态代理不同的是,创建代理类对象的方式也不同了,变为了
IService proxyService = (IService) Proxy.newProxyInstance(
IService.class.getClassLoader(),
new Class<?>[]{IService.class},
new SimpleInvocationHandler(realService));
在Proxy.newProxyInstance()方法中形参的意思是:
- loader:表示类加载器
- interface:表示代理要实现的接口列表,元素的类型只能是接口,不能是普通的类
- h:类型为InvocationHandler对代理接口所有的方法调用都会传给该接口,注意这里就传入了InvocationHandler的实现类SimpleInvocationHandler
我们就使用proxyService就可以调用sayHello的方法了
程序运行结果:
下面我们探讨一下动态代理的基本原理
基本原理
实际上,创建代理对象的方式也可以是这样的:
//创建代理类
Class<?> proxyClass = Proxy.getProxyClass(IService.class.getClassLoader(), new Class<?>[]{IService.class});
//获取代理类参数类型是InvocationHandler的构造器
Constructor<?> constructor = proxyClass.getConstructor(new Class<?>[]{InvocationHandler.class});
InvocationHandler handler = new SimpleInvocationHandler(realService);
//通过这个构造器去实例化对象
IService proxyService = (IService) constructor.newInstance(handler);
proxyService.sayHello();
那么在第一步的时候,会动态生成一个类,这个代理类的名字是$Proxy,这个类继承了Proxy,并且实现了代理接口Iservice,这个类有个构造方法,它实际上调用的是父类的参数类型为InvocationHandler的构造方法,那么这个动态生成的代理类就可以使用这个h了,这个代理类又实现了Iservice接口,那么就可以通过它的对象调用接口的方法,怎么调用的呢?
我们以sayHello来举例子,实际上就是通过h.invoke.(this,m3,null)来实现的,这个invoke是不是很熟悉?实际上就是例子中的代理类SimpleInvocationHandler中的invoke方法,这样就一目了然了。
动态生成的代理类,在调用方法的时候,通过h.invoke实际上调用的就是在例子中定义的代理类中重写的invoke方法,通过重写的invoke中的Object result = method.invoke(realObj,args);真正调用该方法。代理类对象调用不同方法的时候给invoke传递的参数也是不同的。
下一篇将说明动态代理的优点,以及实现一个简单的AOP功能