`
xwood
  • 浏览: 100728 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Proxy模式

 
阅读更多
        Proxy模式是在客户端不方便或者不能直接访问业务逻辑时,通过第三方类提供访问的一种方法。这种代理除了提供业务逻辑访问之外,还可以增加业务功能,好比Decorator模式。通常情况下,它包含三个部分:
  • 1.Component:需要提供的业务功能抽象
  • 2.Proxy:代理类
  • 3.RealComponent:真实需要提供的业务功能


UML图:


        以下是归纳的经常使用代理的地方:
  • 远程(Remote)代理:为一个位于不同的地址空间的对象提供代理,这个地址空间要么是用户不知道的,要么是没权限直接访问的。
  • 虚拟(Virtual)代理:根据需要创建一个资源消耗大的对象,使得此对象只在需要时才被真正创建,像输入输出流,数据库连接,网络TCP连接等。
  • Copy-on-Write代理:把Copy拖延到只有在需要Write的时候才采取行动。
  • 保护(Protect or Access)代理:控制一个对象的访问,如果需要,可以给不同的用户提供不同的访问权限。
  • Cache代理:为某一个目标操作结果提供临时的存储空间,以便多个客户端可以共享这些结果。
  • 防火墙代理:保护目标,不让恶意用户接近。
  • 分布式同步代理:使几个用户可以同时使用一个对象而没有冲突。
  • 智能引用:当一个对象被引用时,提供一些额外的操作,如计算,记录状态等。



        下面再谈一下Java的动态代理对对象代理的实现。这一块主要关注的API有java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler两个。Proxy类生成代理对象的代理实例,但对代理对象的方法调用则主要是通过InvocationHandler.invoke利用反射机制实现的。下面是一个包含了简单AOP的例子。

1.ProxyFactory:Proxy对象的生成工厂
/**
 * 
 * @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);
	}

}


2.IProxyTarget: 被代理类的接口定义
public interface IProxyTarget {
	
	public void process(int num);
	
}


3.ProxyTargetImpl: 实际的被代理对象
public class ProxyTargetImpl implements IProxyTarget {

	@Override
	public void process(int num) {
		System.out.println("--------- Now, Well Done! Boy.");
		//return String.valueOf(num);
	}

}


4.ProxyInvocationHandler: 具体代理方法的执行逻辑
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";
	}

}


5.Aspect: AOP的切面构建类
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;
	};
}


6.Advice: 具体AOP类型
public class Advice {

	/**
	 * 
	 * @param status: 1:before; 2:after;
	 */
	public void processAdvice(int status){
		
	};
}


        需要注意的一点就是Java的动态代理只能实现对接口的代理,所以要对某个对象进行代理,一定要提前定义好接口。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics