代理与动态代理

本文介绍了代理模式的基本实现,并详细探讨了动态代理的工作原理。通过示例代码展示了静态代理与动态代理的区别,以及如何利用动态代理对多个接口进行方法调用的拦截。

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

代理模式:

public interface Interface {
void doSomething();
void somethingElse(String arg);
}
public class RealSubject implements Interface {
public void doSomething() {
System.out.println("realSubject.doSomething()...");
}
public void somethingElse(String arg) {
System.out.println("realSubject.somethingElse(" + arg + " )...");

}
}
public class SimpleProxy implements Interface {
private Interface real;
public SimpleProxy(Interface obj) {
this.real = obj;
}
public void doSomething() {
System.out.println("simpleProxy--before");
real.doSomething();
}
public void somethingElse(String arg) {
System.out.println("simpleProxy--before");
real.somethingElse(arg);
}
}
public class Main {
public static void main(String[] args) {
Interface obj = new RealSubject();
Interface simpleProxy = new SimpleProxy(obj);
simpleProxy.doSomething();
simpleProxy.somethingElse("testString");
}
}

这个基本上是最简单的代理模式实现了.
对Interface接口方法的调用,都被SimpleProxy截获了.


动态代理:
能够在运行时实现接口但在编译时不用声明其实现接口的特殊类.////
Java的动态代理比代理的思想又向前了一步.因为它可以动态的创建代理并动态地处理对所有代理的方法调用.在动态代理上所做的所有调用都会被重定向到单一的调用处理器上.(Thinking in Java)
SimpleProxy在编译期已经存在,但动态代理可以在运行期生成代理类,及代理实例.

用动态代理改写上面的例子:

public class InvocationHandlerImpl implements InvocationHandler {
private Object target;
public InvocationHandlerImpl(Object obj) {
this.target = obj;
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
System.out.println("methodName:" + method.getName());
System.out.println("proxy:" + proxy.getClass().getName());
if (args != null) {
for(Object o : args) {
System.out.println(o);
}
}
return method.invoke(target,args); //1:转发请求
}
}
public class Main {
public static void main(String[] args) {
Interface real = new RealSubject();
Interface proxy = (Interface)Proxy.newProxyInstance(Interface.class.getClassLoader(),new Class[]{Interface.class},new InvocationHandlerImpl(real));
proxy.doSomething();
proxy.somethingElse("proxyString");
}
}


此时可以对多个接口进行方法调用的拦截,AOP的实现.
普通代理模式可能要针对一个接口实现一个代理.
动态代理则只需要编写一个调用处理器的实现类,根据传入的代理接口列表动态生成代理类和代理实例.



public interface OtherInterface {
public void play();
}

在这里再给出一个接口,但是对这个接口没有默认实现类.
改写上面的调用处理器实现类:


public class InvocationHandlerImpl2 implements InvocationHandler {
private Object target;
public InvocationHandlerImpl2(Object obj) {
this.target = obj;
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
System.out.println("methodName:" + method.getName());
System.out.println("proxy:" + proxy.getClass().getName());
if ("play".equals(method.getName())) {
System.out.println("invoke OtherInterface.play method!");
return null;
}
if (args != null) {
for(Object o : args) {
System.out.println(o);
}
}
return method.invoke(target,args);
}
}
public class Main {
public static void main(String[] args) {
Interface real = new RealSubject();
Object proxyObject = Proxy.newProxyInstance(Interface.class.getClassLoader(),new Class[]{Interface.class,OtherInterface.class},new InvocationHandlerImpl2(real));
Interface proxy = (Interface)proxyObject;
proxy.doSomething();
proxy.somethingElse("proxyString");
OtherInterface otherProxy = (OtherInterface)proxyObject;
otherProxy.play();
}
}


可能的结果:
methodName:doSomething
proxy:$Proxy0
realSubject.doSomething()...
methodName:somethingElse
proxy:$Proxy0
proxyString
realSubject.somethingElse(proxyString )...
[color=red]methodName:play
proxy:$Proxy0
invoke OtherInterface.play method![/color]


调用处理器截获对OtherInterface.play()方法的调用.作出处理后并返回,因为没有RealSubject,因些也无法向真实对象进行请求转发.
从外部看:好像Interface的实例经过调用处理器的处理,他又实现了另外一个接口.

现再调用处理器的作用不再只是进行对方法截获进行处理,请求转发;
它实际在做一种实现工作,
(只是进行对方法截获进行处理,而没有进行请求转发就可以看成一种重写了)

再从另个一个角度看,此时的调用处理器不只是进行代理,而还有适配器的形,但可能完全没有适配器的目的,因为Interface和OtherInterface完全没有关系.但可以从一个Interface的实例转型为一个OtherInterface.

甚至在调用Proxy.newProxyInstance()方法生成代理实例的时候,不传入RealSubject对象,那么调用处理器完全冲当代理接口的实现类,而没有了请求转发这一步骤.
不过这完全不是代理的初衷了!
注:1处的转发调用是当有传入RealSubject对象时才可以调用,如果传入null,则要进行单独处理.

动态的意思:1.可以横行为一组接口实现横切逻辑.
2.可以在运行时动态实现一个接口实例,Proxy$X为接口的实现类.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值