Proxy模式是在客户端不方便或者不能直接访问业务逻辑时,通过第三方类提供访问的一种方法。这种代理除了提供业务逻辑访问之外,还可以增加业务功能,好比Decorator模式。通常情况下,它包含三个部分:
[list]
[*]1.[b]Component[/b]:需要提供的业务功能抽象
[*]2.[b]Proxy[/b]:代理类
[*]3.[b]RealComponent[/b]:真实需要提供的业务功能
[/list]
[size=large][b]UML图:[/b][/size]
[align=center][img]http://f-1.tuzhan.com:8080/p-2/l/2012/09/15/15/aaa864f25e3a4ad7a3ae70a01fc787f3.bmp[/img][/align]
[size=large]以下是归纳的经常使用代理的地方:[/size]
[list]
[*][b]远程(Remote)代理[/b]:为一个位于不同的地址空间的对象提供代理,这个地址空间要么是用户不知道的,要么是没权限直接访问的。
[*][b]虚拟(Virtual)代理[/b]:根据需要创建一个资源消耗大的对象,使得此对象只在需要时才被真正创建,像输入输出流,数据库连接,网络TCP连接等。
[*][b]Copy-on-Write代理[/b]:把Copy拖延到只有在需要Write的时候才采取行动。
[*][b]保护(Protect or Access)代理[/b]:控制一个对象的访问,如果需要,可以给不同的用户提供不同的访问权限。
[*][b]Cache代理[/b]:为某一个目标操作结果提供临时的存储空间,以便多个客户端可以共享这些结果。
[*][b]防火墙代理[/b]:保护目标,不让恶意用户接近。
[*][b]分布式同步代理[/b]:使几个用户可以同时使用一个对象而没有冲突。
[*][b]智能引用[/b]:当一个对象被引用时,提供一些额外的操作,如计算,记录状态等。
[/list]
下面再谈一下Java的动态代理对对象代理的实现。这一块主要关注的API有java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler两个。Proxy类生成代理对象的代理实例,但对代理对象的方法调用则主要是通过InvocationHandler.invoke利用反射机制实现的。下面是一个包含了简单AOP的例子。
[size=large]1.[b]ProxyFactory[/b]:Proxy对象的生成工厂[/size]
[size=large]2.[b]IProxyTarget[/b]: 被代理类的接口定义[/size]
[size=large]3.[b]ProxyTargetImpl[/b]: 实际的被代理对象[/size]
[size=large]4.[b]ProxyInvocationHandler[/b]: 具体代理方法的执行逻辑[/size]
[size=large]5.[b]Aspect[/b]: AOP的切面构建类[/size]
[size=large]6.[b]Advice[/b]: 具体AOP类型[/size]
[b][size=large]需要注意的一点就是Java的动态代理只能实现对接口的代理,所以要对某个对象进行代理,一定要提前定义好接口。[/size][/b]
[list]
[*]1.[b]Component[/b]:需要提供的业务功能抽象
[*]2.[b]Proxy[/b]:代理类
[*]3.[b]RealComponent[/b]:真实需要提供的业务功能
[/list]
[size=large][b]UML图:[/b][/size]
[align=center][img]http://f-1.tuzhan.com:8080/p-2/l/2012/09/15/15/aaa864f25e3a4ad7a3ae70a01fc787f3.bmp[/img][/align]
[size=large]以下是归纳的经常使用代理的地方:[/size]
[list]
[*][b]远程(Remote)代理[/b]:为一个位于不同的地址空间的对象提供代理,这个地址空间要么是用户不知道的,要么是没权限直接访问的。
[*][b]虚拟(Virtual)代理[/b]:根据需要创建一个资源消耗大的对象,使得此对象只在需要时才被真正创建,像输入输出流,数据库连接,网络TCP连接等。
[*][b]Copy-on-Write代理[/b]:把Copy拖延到只有在需要Write的时候才采取行动。
[*][b]保护(Protect or Access)代理[/b]:控制一个对象的访问,如果需要,可以给不同的用户提供不同的访问权限。
[*][b]Cache代理[/b]:为某一个目标操作结果提供临时的存储空间,以便多个客户端可以共享这些结果。
[*][b]防火墙代理[/b]:保护目标,不让恶意用户接近。
[*][b]分布式同步代理[/b]:使几个用户可以同时使用一个对象而没有冲突。
[*][b]智能引用[/b]:当一个对象被引用时,提供一些额外的操作,如计算,记录状态等。
[/list]
下面再谈一下Java的动态代理对对象代理的实现。这一块主要关注的API有java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler两个。Proxy类生成代理对象的代理实例,但对代理对象的方法调用则主要是通过InvocationHandler.invoke利用反射机制实现的。下面是一个包含了简单AOP的例子。
[size=large]1.[b]ProxyFactory[/b]:Proxy对象的生成工厂[/size]
/**
*
* @author xwood
*
* @param <T> 被代理类的接口类型
*/
public class ProxyFactory<T> {
/**
* 利用Class提供的方法实现代理的实例化
* @param clzz 被代理类的接口类型(Class 对象)
* @param target 实际被代理的对象实体, 主要用于InvocationHandler.invoke方法实现方法反射
* @return
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public T getProxyInstance(Class<T> clzz, Object target) throws NoSuchMethodException,
InvocationTargetException, IllegalAccessException,
InstantiationException{
InvocationHandler handler = new ProxyInvocationHandler(target);
Class<?> proxyClass = Proxy.getProxyClass(
clzz.getClassLoader(),
new Class[]{clzz});
@SuppressWarnings("unchecked")
T proxy = (T)proxyClass.getConstructor(new Class[]{InvocationHandler.class})
.newInstance(new Object[]{handler});
return proxy;
}
/**
* 利用Class提供的方法实现代理的实例化
* @param clzz 被代理类的接口类型
* @param target 实际被代理的对象实体, 主要用于InvocationHandler.invoke方法实现方法反射
* @return
*/
public T getProxyInstance1(Class<T> clzz, Object target) {
return (T)Proxy.newProxyInstance(clzz.getClassLoader(),
new Class[]{clzz},
new ProxyInvocationHandler(target));
}
/**
* @param args
*/
public static void main(String[] args) {
ProxyFactory<IProxyTarget> factory = new ProxyFactory<IProxyTarget>();
IProxyTarget proxy = null;
// try {
// proxy = factory.getProxyInstance(IProxyTarget.class);
// } catch (NoSuchMethodException e) {
// e.printStackTrace();
// } catch (InvocationTargetException e) {
// e.printStackTrace();
// } catch (IllegalAccessException e) {
// e.printStackTrace();
// } catch (InstantiationException e) {
// e.printStackTrace();
// }
proxy = factory.getProxyInstance1(IProxyTarget.class, new ProxyTargetImpl());
if(proxy == null) return;
// String reVal = (String)proxy.process(1);
// System.out.println(reVal);
proxy.process(1);
}
}
[size=large]2.[b]IProxyTarget[/b]: 被代理类的接口定义[/size]
public interface IProxyTarget {
public void process(int num);
}
[size=large]3.[b]ProxyTargetImpl[/b]: 实际的被代理对象[/size]
public class ProxyTargetImpl implements IProxyTarget {
@Override
public void process(int num) {
System.out.println("--------- Now, Well Done! Boy.");
//return String.valueOf(num);
}
}
[size=large]4.[b]ProxyInvocationHandler[/b]: 具体代理方法的执行逻辑[/size]
public class ProxyInvocationHandler implements InvocationHandler {
/**
* 被代理类型的实体对象
*/
private Object target;
/**
* 仅有于需要复杂AOP时针对每次代理实现的Aspect对象
*/
private Aspect aspect;
public ProxyInvocationHandler(Object target){
this.target = target;
}
public ProxyInvocationHandler(Object target, Aspect aspect){
this.target = target;
this.aspect = aspect;
}
/**
* 实际代理运行时的主要方法。
* 代理对象在被调用时,将被调用方法、参数及代理对象本身传递给invoke方法,
* 在invoke方法内实现真正的方法调用。这类似于Decorator模式中主方法的调用。
* 在invoke方法内的实现可以与proxy或者target完全无关,甚至也可以不用method
* 等传递的参数,具体如何使用根据实际情况而定。
* 在返回值方面,如果被代理方法有返回值,则采用invoke方法的返回值;否则,
* 依然返回空。
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return method.invoke(target, args);
//如果需要AOP处理,则可以将具体实现交给aspect进行处理。
//return aspect.processAspect(target, method, args);
//如果需要返回值,则采用invoke方法的返回值。
//return "123";
}
}
[size=large]5.[b]Aspect[/b]: AOP的切面构建类[/size]
public class Aspect {
private List<Advice> adviceMap;
//TODO 生成你的adviceMap
public void initiate(){
}
public Object processAspect(Object target, Method method, Object[] args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException{
Iterator<Advice> it = adviceMap.iterator();
Advice advice = null;
while(it.hasNext()){
advice = (Advice)it.next();
advice.processAdvice(1);
}
Object obj = method.invoke(target, args);
it = adviceMap.iterator();
while(it.hasNext()){
advice = (Advice)it.next();
advice.processAdvice(2);
}
return obj;
};
}
[size=large]6.[b]Advice[/b]: 具体AOP类型[/size]
public class Advice {
/**
*
* @param status: 1:before; 2:after;
*/
public void processAdvice(int status){
};
}
[b][size=large]需要注意的一点就是Java的动态代理只能实现对接口的代理,所以要对某个对象进行代理,一定要提前定义好接口。[/size][/b]