Proxy模式

本文详细介绍了Java动态代理的实现方式,包括Proxy、InvocationHandler等关键类的使用,并通过一个简单的AOP示例展示了如何在实际项目中应用动态代理来实现面向切面编程。此外,文章还探讨了动态代理在不同场景下的应用,如远程代理、虚拟代理等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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]
/**
*
* @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]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值