什么是代理?
代理,你就可以直接的理解为是我们所熟知的中介,中间商,中间平台等等。目的就是为我们服务达到目的。
以上可以看出,代理可以实现我们的方法增强(如购物的打折),比如一些常用的日志,缓存等。也可以实现方法拦截(如真假货替换),代理方法可以修改愿方法的参数以及返回值。
静态代理
静态代理就是最基本的代理方式,下面用一个例子来介绍一下:
- 比如我们需要买东西,这时候需要提供一个购物的功能如下:
public interface Shopping {
Object[] goShopping(int money);
}
- 接着是我们的实现,我们要去亲自购物,如下:
public class ShoppingImpl implements Shopping {
@Override
public Object[] doShopping(int money) {
return new Object[] { "鞋子", "衣服"};
}
}
- 如果我们不想自己买,这个时候就需要代理的出现:
public class ProxyShopping implements Shopping {
Shopping base;
ProxyShopping(Shopping base) {
this.base = base;
}
@Override
public Object[] doShopping(int money) {
// 这里我们可以修改输入参数
int moneyCount = money-500;
System.out.println(String.format("花了%s块钱", moneyCount));
// 帮忙买东西
Object[] things = base.doShopping(moneyCount);
// 修改返回值,鞋子替换成袜子
if (things != null && things.length > 1) {
things[0] = "袜子";
}
return things;
}
由上可知,代理确实可以做到修改参数以及返回值,当然也可以做增强使用。
- 静态代理的缺点: 传统的静态代理模式需要为每一个需要代理的类写一个代理类,这样会浪费大量的时间。
动态代理
如果用动态代理实现上面的功能又是如何的呢?如下:
public static void main(String[] args) {
Shopping women = new ShoppingImpl();
// 正常购物
System.out.println(Arrays.toString(women.doShopping(100)
// 动态代理实现
women = (Shopping) Proxy.newProxyInstance(Shopping.class.getClassLoader(),
women.getClass().getInterfaces(),
new ShoppingHandler(womenSystem.out.println(Arrays.toString(women.doShopping(100)));
}
我们主要处理的类有ShoppingHandler
public class ShoppingHandler implements InvocationHandler {
/**
* 被代理的原始对象
*/
Object base;
public ShoppingHandler(Object base) {
this.base = base;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("doShopping".equals(method.getName())) {
// 这里是代理Shopping接口的对象
// 修改输入参数
int money = args[0];
int moneyCount = (long) (money -500);
// 帮忙买东西
Object[] things = (Object[]) method.invoke(base, moneyCount);
// 修改返回值,鞋子替换成袜子
if (things != null && things.length > 1) {
things[0] = "袜子";
}
return things;
}
if ("doSomething".equals(method.getName())) {
// 可以代理别的,做些别的事情
return null;
}
if ("doSomethingElse".equals(method.getName())) {
// 做些别的事情
return null;
}
return null;
}
}
试想一下,我们如果有很多的类,做相同的事情,是不是用动态代理更加方便呢?
动态代理的优点
-
只需要1个动态代理类就可以解决创建多个静态代理的问题,避免重复、多余代码
-
更强的灵活性
动态代理的缺点
-
效率低,相比静态代理中直接调用目标对象方法,动态代理则需要先通过Java反射机制 从而间接调用目标对象方法
-
应用场景局限,因为Java的单继承特性(每个代理类都继承了Proxy类),即只能针对接口 创建代理类,不能针对类创建代理类。
在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler接口、另一个则是 Proxy类,这个类和接口是实现我们动态代理所必须用到的。
InvocationHandler接口是给动态代理类实现的,负责处理被代理对象的操作的,而Proxy是用来创建动态代理类实例对象的,因为只有得到了这个对象我们才能调用那些需要代理的方法。