Java中的静态代理和动态代理
一、引入代理的概念
我叫蒙林,在北京租了一间房子。昨天我有事去了广东,当我到了广东后,房东王小三打电话给我说今天该交房租了(合同上写的是今天交房租,且过期不交房租将产生滞纳金),那么我怎么办呢? 于是我打电话给北京的朋友黄河,让他先替我把房租交给房东,那么黄河是以我的名义交的房租。
那么在这一事件中,黄河就是我蒙林的代理(英文为Proxy),当我不方便办理某一件事情的时候,代理可以替我完成。黄河(我的代理)和我都有交房租的这一能力。
二、Java中的代理
从面向对象的角度来说,蒙林和黄河各为一个类,他们都有一个交房租的功能,因此我可以让他们都实现同一接口,接口中定义二者的共同功能。
涉及到的类有:
MengLin.java ——蒙林
HuangHe_Proxy.java ——黄河
Function.java —— 功能类(定义二者共同的方法)
Test.java —— 测试类
package Proxy;
public abstract class Function {
// 二者都可以交房租
public abstract void jiaoFangZu();
}
package Proxy;
public class HuangHe_Proxy extends Function {
// 黄河是代理,他要代理谁?
private Function who = null;
// 通过构造函数确定代理谁
public HuangHe_Proxy(Function who) {
this.who = who;
}
// 如果我指定who为蒙林,那么黄河交房租实际上是蒙林交房租, 但是交房租之前黄河可以做些其他事情
@Override
public void jiaoFangZu() {
chiFan();
quQian();
who.jiaoFangZu();
}
public void quQian() {
System.out.println("先去银行取2000块钱。");
}
public void chiFan() {
System.out.println("吃饱了再说。");
}
}
package Proxy;
public class MengLin extends Function {
@Override
public void jiaoFangZu() {
System.out.println("房东,给你下个月的房租。");
}
}
public class Test {
public static void main(String[] args) {
// 蒙林和黄河都继承Function类
Function mengLin = new MengLin();
Function huangHe = new HuangHe_Proxy(mengLin);
huangHe.jiaoFangZu();
}
}
总结:上面讲的是静态代理模式,你只需要编写代理类、被代理类和他们的功能类。Spring中的AOP(面向切面编程)在调用一个方法前后可以做一些其他的处理(比如记录日志),它就是通过代理模式实现的。
三、什么是动态代理
讲完静态代理,该说说动态代理了。动态代理不需要像静态代理那样自己定义代理类,JVM提供了两个API帮助你在程序运行过程中生成代理,这就是“动态”的概念。
这两个API分别是java.lang.reflect.InvocationHandler和java.lang.reflect.Proxy。
InvocationHandler源码如下:
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
将来调用代理类中的方法时,实际上是调用invoke方法。
Proxy有一个方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
通过这个方法就可以得到一个代理类了。 其中 loader 是蒙林的类加载器, interfaces是蒙林实现的接口(如果蒙林没有实现接口那么将发生异常), h 是一个 InvocationHandler。
下面通过程序说明动态代理的实现。
涉及到的类有:
MengLin.java ——蒙林(同静态代理)
Function.java —— 功能类(必须改为接口)
Handler.java —— 实现InvocationHandle接口
Test.java —— 测试类
package Proxy;
public interface class Function {
public abstract void jiaoFangZu();
}
package Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class Handler implements InvocationHandler {
// 被代理者
private Object beProxyer = null;
public Handler(Object obj) {
this.beProxyer = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before call method: " + method);
Object result = method.invoke(beProxyer, args);
System.out.println("after call method: " + method);
return result;
}
}
package Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
Function mengLin = new MengLin();
// 定义InvocationHandler
InvocationHandler handler = new Handler(mengLin);
// 生成代理类,返回类型为Object
Object object = Proxy.newProxyInstance(mengLin.getClass().getClassLoader(), mengLin.getClass().getInterfaces(), handler);
// 将代理转换为被代理类类型
MengLin mengLinProxy = (Function)object;
// 现在调用mengLinProxy.jiaoFangZu()函数等同于mengLin.jiaoFangZu()
mengLinProxy.jiaoFangZu();
}
}
总结:上面讲的是动态代理模式,你只需要编写被代理类和他们的功能接口,然后通过Proxy类和InvocationHandler接口生成动态代理类。
四、应用
下面,通过动态代理实现拦截器功能。
package com.biocjm;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxyUtil implements InvocationHandler {
/** the Object will be proxyed */
private Object proxyer = null;
/**
* a interceptor, with it, you can do something you want before or after
* execute a proxyer's method
*/
private Interceptor interceptor = null;
/**
* this is a constructor, via it the util can get a proxyer
*
* @param proxyer-object will be proxyed
*/
public DynamicProxyUtil(Object proxyer) {
this.proxyer = proxyer;
}
/**
* set a interceptor
*
* @param interceptor
*/
public void setInterceptor(Interceptor interceptor) {
this.interceptor = interceptor;
}
/**
* you can change the proxyer during your use of DynamicProxyUtil
*
* @param proxyer-object will be proxyed
*/
public void setProxyer(Object proxyer) {
this.proxyer = proxyer;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeMethod();
Object result = method.invoke(proxyer, args);
afterMethod();
return result;
}
/**
* get a Proxy Object with the same interface with proxyer
*
* @return a Proxy
*/
public Object getProxy() {
return Proxy.newProxyInstance(proxyer.getClass().getClassLoader(), proxyer.getClass().getInterfaces(), this);
}
/** do before the proxyer's method execute */
public void beforeMethod() {
if (interceptor != null) {
interceptor.doBefore();
}
}
/** do after the proxyer's method execute */
public void afterMethod() {
if (interceptor != null) {
interceptor.doAfter();
}
}
interface Interceptor {
public void doBefore();
public void doAfter();
}
}
package com.biocjm;
import com.biocjm.DynamicProxyUtil.Interceptor;
public class Test {
public static void main(String[] args) {
dproxy();
}
// 动态代理工具类测试
public static void dproxy() {
Interceptor interceptor = new Interceptor() {
@Override
public void doBefore() {
System.out.println("before method.");
}
@Override
public void doAfter() {
System.out.println("after method. ");
}
};
DynamicProxyUtil dynamicProxyUtil = new DynamicProxyUtil(interceptor);
dynamicProxyUtil.setInterceptor(interceptor);
Object dyProxy = dynamicProxyUtil.getProxy();
// 切记,动态代理是基于借口编程的, 因此被代理类一定要实现至少一个接口,否则在类型转换时将出现异常
Interceptor interceptor2 = (Interceptor) dyProxy;
interceptor2.doAfter();
}
}