咱们你们都知道weishang 代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品。关于weishang代理,首先咱们从他们那里买东西时一般不知道背后的厂家到底是谁,也就是说,“委托者”对咱们来讲是不可见的;java
其次,weishang代理主要以朋友圈的人为目标客户,这就至关于为厂家作了一次对客户群体的“过滤”。咱们把weishang代理和厂家进一步抽象,前者可抽象为代理类,后者可抽象为委托类(被代理类)。经过使用代理,一般有两个优势,而且可以分别与咱们提到的weishang代理的两个特色对应起来:ide
实际上,中介类与委托类构成了静态代理关系,在这个关系中,中介类是代理类,委托类就是委托类;代理类与中介类也构成一个静态代理关系,在这个关系中,中介类是委托类,代理类是代理类。this
也就是说,动态代理关系由两组静态代理关系组成,这就是动态代理的原理。下面咱们来介绍一下如何”指示“以动态生成代理类。spa
若代理类在程序运行前就已经存在,那么这种代理方式被成为静态代理,这种状况下的代理类一般都是咱们在Java代码中定义的。 一般状况下,静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。下面咱们用Vendor类表明生产厂家,BusinessAgent类表明weishang代理,来介绍下静态代理的简单实现,委托类和代理类都实现了Sell接口,Sell接口的定义以下:代理
public interface Sell { void sell(); void ad();}
复制代码
Vendor类的定义以下:code
public class Vendor implements Sell {
public void sell() {
System.out.println("In sell method");
}
public void ad() {
System.out.println("ad method")
}
}
复制代码
代理类BusinessAgent的定义以下:cdn
public class BusinessAgent implements Sell {
private Vendor mVendor;
public BusinessAgent(Vendor vendor) {
mVendor = vendor;
}
public void sell() {
mVendor.sell();
}
public void ad() {
mVendor.ad();
}
}
复制代码
从BusinessAgent类的定义咱们能够了解到,静态代理能够经过聚合来实现,让代理类持有一个委托类的引用便可。
下面咱们考虑一下这个需求:给Vendor类增长一个过滤功能,只卖货给大学生。经过静态代理,咱们无需修改Vendor类的代码就能够实现,只需在BusinessAgent类中的sell方法中添加一个判断便可以下所示:对象
public class BusinessAgent implements Sell {
...
public void sell() {
if (isCollegeStudent()) {
vendor.sell();
}
}
...
}
复制代码
这对应着咱们上面提到的使用代理的第二个优势:能够实现客户与委托类间的解耦,在不修改委托类代码的状况下可以作一些额外的处理。静态代理的局限在于运行前必须编写好代理类,下面咱们重点来介绍下运行时生成代理类的动态代理方式。blog
在使用动态代理时,咱们须要定义一个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接口,这个接口的定义以下:接口
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args);
}
复制代码
从InvocationHandler这个名称咱们就能够知道,实现了这个接口的中介类用作“调用处理器”。当咱们调用代理类对象的方法时,这个“调用”会转送到invoke方法中,代理类对象做为proxy参数传入,参数method标识了咱们具体调用的是代理类的哪一个方法,args为这个方法的参数。这样一来,咱们对代理类中的全部方法的调用都会变为对invoke的调用,这样咱们能够在invoke方法中添加统一的处理逻辑(也能够根据method参数对不一样的代理类方法作不一样的处理)。所以咱们只需在中介类的invoke方法实现中输出“before”,而后调用委托类的invoke方法,再输出“after”。下面咱们来一步一步具体实现它。
动态代理方式下,要求委托类必须实现某个接口,这里咱们实现的是Sell接口。委托类Vendor类的定义以下:
public class Vendor implements Sell {
public void sell() {
System.out.println("In sell method");
}
public void ad() {
System.out.println("ad method")
}
}
复制代码
上面咱们提到过,中介类必须实现InvocationHandler接口,做为调用处理器”拦截“对代理类方法的调用。中介类的定义以下:
public class DynamicProxy implements InvocationHandler {
private Object obj; //obj为委托类对象
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result = method.invoke(obj, args);
System.out.println("after");
return result;
}
}
复制代码
动态生成代理类的相关代码以下:
public class Main { public static void main(String[] args) {
DynamicProxy inter = new DynamicProxy(new Vendor());
//加上这句将会产生一个$Proxy0.class文件,这个文件即为动态生成的代理类文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
//获取代理类实例sell
Sell sell = (Sell)(Proxy.newProxyInstance(Sell.class.getClassLoader(), new Class[] {Sell.class}, inter));
sell.sell();
sell.ad();
}
}
复制代码
在以上代码中,咱们调用Proxy类的newProxyInstance方法来获取一个代理类实例。这个代理类实现了咱们指定的接口而且会把方法调用分发到指定的调用处理器。这个方法的声明以下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException 复制代码
方法的三个参数含义分别以下:
loader:定义了代理类的ClassLoder;
interfaces:代理类实现的接口列表
h:调用处理器,也就是咱们上面定义的实现了InvocationHandler接口的类实例
咱们运行一下,看看咱们的动态代理是否能正常工做。我这里运行后的输出为:
说明咱们的动态代理确实奏效了。
上面咱们已经简单提到过动态代理的原理,这里再简单的总结下:首先经过newProxyInstance方法获取代理类实例,然后咱们即可以经过这个代理类实例调用代理类的方法,对代理类的方法的调用实际上都会调用中介类(调用处理器)的invoke方法,在invoke方法中咱们调用委托类的相应方法,而且能够添加本身的处理逻辑。