下面我们来个一个静态代理的实现。
我以一个坦克为例。
抽象主题角色:Moveable
[java] view plaincopy
package com.gjy.proxy;
public interface Moveable {
void move();
}
代理主题角色:TanktimeProxy
[java] view plaincopy
package com.gjy.proxy;
public class TanktimeProxy implements Moveable{
private Moveable t;
public TanktimeProxy(Moveable t) {
super();
this.t = t;
}
@Override
public void move() {
long time1 = System.currentTimeMillis();
System.out.println("time1="+time1);
t.move();
long time2 = System.currentTimeMillis();
System.out.println("time2="+time2);
System.out.println("运行时间为:"+(time2-time1));
}
}
实际被代理对象:Tank
[java] view plaincopy
package com.gjy.proxy;
public class Tank implements Moveable{
@Override
public void move() {
System.out.println("TanK moving........");
}
}
测试:
[java] view plaincopy
package com.gjy.proxy;
public class TestTank {
public static void main(String[] args) {
Tank t = new Tank();
Moveable move = new TanktimeProxy(t);
move.move();
}
}
上述为静态代理,动态代理是在静态代理基础上发展的
有静态代理可知,需要,
一个接口Moveable
被代理类,实现该接口
代理类也要实现该接口。
创建被代理类实例对象,和代理对象,并把被代理对象传递给代理对象。
调用代理对象的实现接口中的方法。
动态代理:
在程序运行时,创建类(该类在程序未运行时,不存在)的定义,并生成该类的实例对象。
(1)
Main(){
Tank t=new Tank(); //创建被代理类
InvocationHandler h=new TimeHandler(t); //创建逻辑功能,即切面
//Proxy的静态方法newProxyInstance返回代理类
Moveable m=( Moveable)Proxy.newProxyInstance(Moveable.class, h);
m.move();
}
(2)//该方法不能直接通过实例对象调用invoke()方法,因为不知道切入点,即在哪些方法执行之前或之后执行切面。该方法是为代理对象调用的。
Class TimeHandler implements InvocationHandler{
Object target; //该对象用于保存被代理对象
TimeHandler(Object target){
This.target=target;
}
invoke(Object proxy,Method m){proxy对象一般没有什么用处,如果使用method.invoke(proxy, args);会造成死循环
/*业务逻辑,切面*/
System.out.println(“时间1”);
m.invoke(target); //注意该invoke方法为Method对象的静态方法(jDK的)
System.out.println(“时间1”);
}
}
(3)
Interface InvocationHandler{
Invoke(Object o,Method m);
}
(4)
Class Proxy{
Static newProxyInstance(Class infce, InvocationHandler h){
1.根据反射,获取接口infce中的方法名,
2.创建infce的代理类的定义
3.创建代理类的实例对象,并把h参数传递给代理实例对象
4.返回代理对象
}
}
具体实现:
Static newProxyInstance(Class infce, InvocationHandler h){
String str=””;
遍历infce,获取方法名,如move
Str=”
Class TankTimeProxy implements “+infce.getName+”
{
InvocationHandler h;
TankTimeProxy(InvocationHandler h){ //创建构造方法
this.h=h;
}”+
move+”(){
h.invoke(this,”+Method1+”)
}
}
”
把str写入一个TankTimeProxy.java文件中,编译并加载该类
根据反射创建该类实例。C为TankTimeProxy类的字节码
Constructor ctr=c.getConstructor(InvocationHandler.class);
//得到参数为InvocationHandler类型的构造函数
Object m=ctr.newInstance(h);
//创建TankTimeProxy的一个实例对象,并传入h参数
return m;
}
其实:动态创建的代理类不具有任何逻辑,在实现接口方法中:
move(){
h.invoke(this,"move");
}
由于h中并没有使用this对象,而是target故实现代理功能。
分析:
Main(){
Tank t=new Tank(); //创建被代理类
InvocationHandler h=new TimeHandler(t); //创建逻辑功能,即切面
//Proxy的静态方法newProxyInstance返回代理类
Moveable m=(Moveable)Proxy.newProxyInstance(Moveable.class,h);
m.move();
}
总结:相当于TimeHandler代理Tank,TankTimeProxy又代理TimeHandler。
当调用TankTimeProxy对象的move,调用TimeHandler的move ,
TimeHandler调用Tank的move
和静态代理唯一不同的是TankTimeProxy是动态生成。
疑惑:为什么不直接把TimeHandler代理,不用再包装一道。
答:
(1)因为你会发现TimeHandler中不会出现被代理对象的方法名称,使用动态代理完全分离了TimeHandler与被代理对象的分离。任何需要该切片功能的对象都可以给TimeHandler代理。
静态代理则必须修改代理类源代码(硬编码了被代理对象的方法名),其实静态代理可以使用方法注入,实现分离。
(2)使用动态代理,只需要编写切片逻辑过程,代理类由JVM生成,可以直接调用Java API,不用单独写一个代理类。一个切面类,可以被多个类使用,代理类有JVM生成。
动态代理例子:
import java.util.*;
publicclass TestMain {
/**
* @param args
*/
publicstaticvoid main(String[] args) {
ArrayList target=newArrayList();
ProxyFactory proxyFactory=new ProxyFactory();
proxyFactory.setTarget(target);
Collection proxy=(Collection)proxyFactory.getProxy();
proxy.add("one");
System.out.println("--------------------间隔符--------------------------");
System.out.println(proxy.toString());//代理调用方法一次
}
}
/////////////////////////////////////////////////////////////////
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
publicclass ProxyFactory implements InvocationHandler {
private Object target;
publicvoid setTarget(Object target) {
this.target = target;
}
//该方法也可以在main()函数中
//把this对象换成ProxyFactory实例对象
public Object getProxy(){
if(target==null){
System.out.println("未设置目标类");
returnnull;
}
Object proxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)//proxy对象一般没有什么用处,如果使用method.invoke(proxy, args);会造成死循环,
// 因为proxy执行该方法使用的是ProxyFactory 中的invoke()方法
throws Throwable {
System.out.println("调用方法前");
Object returnValue=method.invoke(target, args);
System.out.println("调用方法后");
return returnValue;
}
//////////////////////////////////
运行结果:
调用方法前
调用方法后
--------------------间隔符--------------------------
调用方法前
调用方法后
[one]