一、什么是代理?
在现实生活中,大家都对代理商不陌生,代理商就是在其行业管理范围内接受他人委托,为他人促成或缔结交易的一般代理人。而在Java编程中,代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式,即通过代理对象访问目标对象,这样就可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。简单来说就是你想要做的事情我替你来完成,并且在完成你的事情的同时,我还可以做些其他事情,更加完美的完成这个事情。
二、静态代理与动态代理
静态代理是在程序运行前,这个代理类已经生成了,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类,然后通过调用相同的方法来调用目标对象的方法,所以缺点就很明显,因为代理对象需要与目标对象实现一样的接口,所以会产生很多代理类,还有就是一旦接口增加方法,目标对象与代理对象都要维护。
动态代理是在程序运行的时候,通过反射机制动态创建而成。无需coder手写它的源代码,这样不仅简化了编程工作,而且还提高了软件系统的可扩展性。动态代理可以说是为了弥补静态代理的缺点而生的。
三、举例说明
假设演员演戏就是一个目标对象,而经纪人就是一个代理对象,演员演好戏,对导演做好服务就行了,像演出费、合同之类的事情就交给经纪人来做。
1、静态代理
首先要有一个唱歌的接口:
public interface IActor {
void action();
} 再来一个德艺双馨的明星演员:
public class FanActor implements IActor{
@Override
public void action() {
System.out.println("好开心,好激动,又开始演戏了。。。");
}
}只演戏可不行呀,还得签合同、谈费用和吃喝拉撒睡呢,这是经纪人出场,也就是代理对象:
public class MuActorProxy implements IActor{
private IActor iActor;
public MuActorProxy(IActor iActor) {
this.iActor = iActor;
}
@Override
public void action() {
System.out.println("签个合同吧!一大一小,导演您懂得!");
iActor.action();
System.out.println("我们至少要住五星级的,演出完了,还要坐飞机回去!");
}
}测试一下:
public class MuActorProxyTest {
public static void main(String[] args) {
IActor actor = new FanActor();
MuActorProxy proxy = new MuActorProxy(actor);
proxy.action();
}
}结果如下:
签个合同吧!一大一小,导演您懂得!
好开心,好激动,又开始演戏了。。。
我们至少要住五星级的,演出完了,还要坐飞机回去!不错,经纪人做了静态代理出色的完成了任务,但是有很多的演员,这样就会有很多的经纪人,并且演员有个其他事情或者发个小脾气,都会连累经纪人。下面就介绍另外一种经纪方式,统一的经纪公司,负责所有的演员,也就是动态代理。
2、动态代理之基于接口的JDK代理
JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)该方法是在Proxy类中是静态方法,且接收的三个参数依次为:
ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型
InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
建造一个经纪公司:
public class ActorFactoryProxy {
private Object target;
public ActorFactoryProxy(Object target) {
this.target = target;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("签个合同吧!一大一小,导演您懂得!");
Object returnValue = method.invoke(proxy, args);
System.out.println("我们至少要住五星级的,演出完了,还要坐飞机回去!");
return returnValue;
}
});
}
}测试一下:
public class ActorFactoryProxyTest {
public static void main(String[] args) {
IActor actor = new FanActor();
IActor actorProxy = (IActor) new ActorFactoryProxy(actor).getProxyInstance();
actorProxy.action();
}
}结果如下:
签个合同吧!一大一小,导演您懂得!
好开心,好激动,又开始演戏了。。。
我们至少要住五星级的,演出完了,还要坐飞机回去!代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理。也就是演员得一定会演戏呀,要不经纪公司找你干嘛。
3、动态代理之基于子类的Cglib代理
Cglib是针对类进行动态代理的,原理是对指定的业务类生成一个子类,通过代理类实现业务类中的业务,并且附加一些其他业务的实现。因为此时业务类相当于父类,代理类相当于子类,这是继承关系,所以不能对final修饰的类进行代理。
这是实现业务类方法的代理类方法:
public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable首先创建一个演员,不用实现接口,天生会表演:
public class WangActor {
public void action(){
System.out.println("我天生会表演。。。");
}
}创建一个代理工厂,也就是经纪公司:
public class CgProxyFactory implements MethodInterceptor{
private Object target;
public CgProxyFactory(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("合同和演出费你们看着办。。。");
Object returnValue = method.invoke(target, args);
System.out.println("演完了,我走了。。。");
return returnValue;
}
public Object getProxyInstance(){
//通过Enhancer创建代理对象
Enhancer hancer = new Enhancer();
//设置创建子类的类
hancer.setSuperclass(target.getClass());
hancer.setCallback(this);
return hancer.create();
}
}测试一下:
public class CgProxyTest {
public static void main(String[] args) {
WangActor actor = new WangActor();
WangActor proxy = (WangActor) new CgProxyFactory(actor).getProxyInstance();
proxy.action();
}
}结果如下:
合同和演出费你们看着办。。。
我天生会表演。。。
演完了,我走了。。。四、总结 静态代理是通过在代码中显式定义一个业务实现类的一个代理,在代理类中对同名的业务方法进行包装,程序通过通过代理类调用被包装过的方法;
JDK动态代理是基于接口的,通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;Cglib动态代理是基于子类的,通过继承业务类,动态生成代理类;一般来说,如果一个类实现了接口,就用JDK动态代理,如果没有实现接口,就用Cglib动态代理。
本文详细介绍了Java中的代理模式,包括静态代理与动态代理的概念及应用。通过实例对比静态代理和两种动态代理(JDK代理与Cglib代理)的特点与适用场景。

2421

被折叠的 条评论
为什么被折叠?



