代理模式(Proxy Pattern)是23种常用的面向对象软件的设计模式之一,作用是为其他对象提供一种代理以控制对这个对象的访问,直白说就是中间商或代购。如图。client发起请求到接口,正常是通过接口实现类impl来调用方法完成请求,但是增加了代理类后,可以直接用proxy的实例来调用interface的实现类的方法,并且可以增加额外的功能。
为什么要增加一层代理类呢,有两个优点:
1. 隐藏和保护接口实现类, 控制对接口实现类对象的直接访问
2. 可以增加新的功能实现,提高了系统的可扩展性
JDK动态代理是常用的代理机制之一,主要是通过反射来实现的,实现JDK动态代理,必须要实现 InvocationHandler 接口,实现这个接口同时,会要求重写invoke()方法,如下,参数列表中
proxy:动态代理类(给你代购的那个人)
method:被调用的方法
args:被调用的方法的参数
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
来写个实例展示动态代理的调用过程
首先是接口,写了一个方法,并重载了这个方法
package pers.hong;
/**
* @Description:
* @Auther: hong
* @Date: 2018/09/13
*/
public interface TicketProvider {
public void getTrainTicket();
public void getTrainTicket(int count);
}
然后是它的实现类
package pers.hong;
/**
* @Description:
* @Auther: hong
* @Date: 2018/09/13
*/
public class TicketProviderImpl implements TicketProvider {
@Override
public void getTrainTicket() {
System.out.println("购买火车票");
}
@Override
public void getTrainTicket(int count) {
System.out.println("购买火车票"+count+"张");
}
}
然后是代理类,实现了InvocationHandler接口,重写了invoke方法
package pers.hong;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Description:
* @Auther: hong
* @Date: 2018/09/13
*/
public class TicketProviderProxy implements InvocationHandler {
//实际对象,也就是代购要去的商店
private Object target;
//构造器赋值
public TicketProviderProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----before in method invoke-----");
//invoke()方法通过是实际对象和参数,找到对应的方法
method.invoke(target, args);
System.out.println("Add functionality to the method");
System.out.println("-----after in method invoke-----");
return null;
}
}
然后就是代理测试
package pers.hong;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* @Description:
* @Auther: hong
* @Date: 2018/09/13
*/
public class ProxyTest {
public static void main(String[] args) {
//接口实现类
TicketProvider ticketProvider = new TicketProviderImpl();
//InvocationHandler实现类,用到了刚才定义的构造器
InvocationHandler handler = new TicketProviderProxy(ticketProvider);
//newProxyInstance()生成动态代理类实例,args[0]是实现类,args[1]是要接口类,
//args[2]是InvocationHandler实现类,即处理器,处理传入的需要被代理的真实对象
TicketProvider ticketProviderProxy = (TicketProvider) Proxy.newProxyInstance(
ticketProvider.getClass().getClassLoader(),
ticketProvider.getClass().getInterfaces(),
handler);
//传入参数测试
ticketProviderProxy.getTrainTicket();
ticketProviderProxy.getTrainTicket(5);
}
}
输出结果为
可以看到,通过newProxyInstance()方法创建的代理对象可以调用到接口实现类的方法,并且还输出了增加的的方法。这样动态代理就实现了。
反射的使用地方在于,动态代理类proxy的生成,即newProxyInstance()方法,他实现了第二个参数,也就是接口类,然后在实现接口方法的内部,通过反射调用了handler的invoke()方法,invoke()方法再通过内部的method.invoke()校验传入的参数,然后根据参数的不同去调用接口实现类的方法。
这点在SpringAOP中的实现也是一样的,只不过AOP的动态代理机制多了cglib动态代理,用来代理没有实现接口的对象。像bean这种,就是用cglib来进行代理的。