一、静态代理
实现代码:
(1)自定义接口HttpRequest
package com.it.test.proxy;
/**
* http 请求的接口
*/
public interface HttpRequest {
void get();
void post();
}
(2)创建实现类Retrofit、Vally。并实现HttpRequest接口
package com.it.test.proxy;
public class Retrofit implements HttpRequest {
@Override
public void get() {
System.out.println("Retrofit get");
}
@Override
public void post() {
System.out.println("Retrofit post");
}
}
package com.it.test.proxy;
public class Vally implements HttpRequest {
@Override
public void get() {
System.out.println("Vally get");
}
@Override
public void post() {
System.out.println("Vally post");
}
}
(3)创建代理类Agent,并实现HttpRequest接口,在代理类的构造方法中接受实际类,并在实现方法中通过实现类去调用。
/**
* 代理类
*/
public class Agent implements HttpRequest {
private HttpRequest request;
public Agent(HttpRequest request) {
this.request = request;
}
@Override
public void get() {
request.get();
}
@Override
public void post() {
request.post();
}
}
(4)测试
package com.it.test.proxy;
public class Http {
public static void main(String[] args) {
HttpRequest httpRequest = new Agent(new Retrofit());
httpRequest.get();
httpRequest.post();
HttpRequest httpRequest2 = new Agent(new Vally());
httpRequest2.get();
httpRequest2.post();
}
}
在实现中,我们只需要创建代理类,并传入具体的实际类。通过调用代理类的方法,其实内部完成实际类的调用。代理类,相当做了一层隔离。假如哪一天我们的实际类修改了,换成了别的。我们只需要修改传入相应的实际类即可。
缺点:当哪一天我们的实际类实现了多个接口,增加了方法,这样一来,代理类就没法代理。因为代理类的构造方法中只接受了一种类型。
二、动态代理
我们知道代理设计模式包含了三个对象
- 代理接口
- 代理类
- 被代理的类
被代理的类和代理类都实现了代理接口。在静态代理中,代理类只能代理实现一个接口的类,所以当被代理类实现多个接口的时候,无法被代理,因此出现了动态代理。动态代理可以代理多个接口。
1、动态代理使用方法
(1)创建代理接口IWash、IMessage
package com.example.lib;
public interface IWash {
void wash(String msg);
}
package com.example.lib;
public interface IMessage {
void outMessage();
}
(2)创建被代理类,实现IWash和IMessage接口
package com.example.lib;
public class Luxi implements IMessage,IWash {
@Override
public void outMessage() {
System.out.println("Luxi outMessage");
}
@Override
public void wash(String msg) {
System.out.println("Luxi wash"+msg);
}
}
(3)通过Proxy.newProxyInstance创建代理对象
/**
*动态代理
* Object o 代理对象
*
* luxi 被代理对象
*
*/
final Luxi luxi = new Luxi();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(luxi,objects);
}
};
/**
* 创建代理对象
* Object o
* newProxyInstance 方法会在底层生成一个代理类.class到内存中,
* 而在代理类的构造方法中接受了一个InvocationHandler handler。
* 我们传入匿名内部类,实现其invoke方法,
* 当我们通过代理对象调用代理接口方法的时候
* 在代理类里会通过传入的handler调用invoke方法,并传入 三个参数
* (1)Object o 代理对象
* (2)Method method 通过反射 获取到的接口的方法,也就是代理类调用接口的方法。
* (3)Object[] objects 方法的参数
* 接着就会回调我们实现的invoke方法
* 在invoke方法中通过反射 使用method 对象执行方法,传入我们被代理的类对象执行方法,其中还包含了方法的参数
*
*
*
*/
Object o = Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class[]{IMessage.class,IWash.class},handler );
/**
* 这个地方代理对象o之所以可以强转成IMessage,
* 又可以强转成IWash
* 是因为代理类可以实现多个接口,
* 所以可以强转成任意接口类型
*
*
*/
IMessage msg = (IMessage) o;
msg.outMessage();
IWash wash = (IWash) o;
wash.wash(" hello world");
// proxy();
}
通过代理对象调用outMessage和wash方法, 最终执行了被代理对象 Luxi的outMessage和wash方法
Luxi outMessage
Luxi wash hello world
2、动态代理原理分析
(1)创建动态代理对象,传入InvocationHandler handler
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(luxi,objects);
}
};
Object o = Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class[]{IMessage.class,IWash.class},handler );
我们通过Proxy.newProxyInstance方法传入classLoader,代理接口的class数组、和InvocationHandler handler创建了一个代理对象。
我们知道创建对象肯定需要类,那么此时我们需要创建一个代理类,才能实例化代理对象。因此在底层实现中首先会创建一个代理的类的class,也就是编译之后的class文件。写入到了内存。底层通过调用ProxyGenerator的generateProxyClass方法实现。为了分析动态代理的原理,我们手动创建一个代理类。
/**
* 生成代理类
*/
private static void proxy(){
String name = IMessage.class.getName()+"$Proxy";
//生成代理类 的Class数据
byte [] bytes = ProxyGenerator.generateProxyClass(name,new Class[]{IMessage.class,IWash.class});
try {
FileOutputStream outputStream =new FileOutputStream("lib/"+name+".class");
outputStream.write(bytes);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
下面是我们生成的代理类IMessage$Proxy
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.example.lib;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class IMessage$Proxy extends Proxy implements IMessage, IWash {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public IMessage$Proxy(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void wash(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void outMessage() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.lib.IMessage").getMethod("outMessage");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
也就是当我们调用 Object o = Proxy.newProxyInstance创建代理对象的时候,会先在内存中创建一个IMessageProxy的构造方法中接受了一个InvocationHandler 类型的参数,也就是我们传入的InvocationHandler handler ,你们内部类对象。实现了invoke方法。
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(luxi,objects);
}
};
当通过代理对象调用里面的wash方法的时候,就会调用super.h.invoke方法。
public final void wash(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
而h又是父类的成员,接受的正式我们传入的InvocationHandler 。
protected Proxy(InvocationHandler var1) {
Objects.requireNonNull(var1);
this.h = var1;
}
因此最终调用了我们内部类实现的invoke方法
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(luxi,objects);
}
};
也就是创建代理对象,通过代理对象调用代理接口的方法最终会调用到了我们内部类的invoke方法,
invoke方法有三个参数,我们可以在源码中看到。
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.lib.IMessage").getMethod("outMessage");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
public final void wash(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
- Object o对象指的是当前的代理对象
- Method method就是源码中的
m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));
就是通过反射获取代理接口中的方法,封装成Method。
- Object[] objects就是new Object[]{var1},通过代理对象调用方法的时候,我们方法传入的参数,封装成了一个数组。
最后在invoke方法中,我们拿到以上的Method对象和参数数组Object[] objects,我们可以通过调用 method.invoke(luxi,objects);方法,从而达到调用了被代理对象Luxi luxi中的方法。因为代理类和被代理都实现了同一个接口,因此代理类调用的方法,最终反射获取到该方法,再让被代理类调用完成最终的实现。
final Luxi luxi = new Luxi();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(luxi,objects);
}
};
小结
- 动态代理可以代理多个接口,静态代理只能代理一个接口
- 动态代理类不是通过我们手动生成,而是通过ProxyGenerator.generateProxyClass动态生成的一个class。
- 动态代理类创建代理对象的时候需要传入InvocationHandler 对象,而InvocationHandler 对象是一个接口,因此我们需要手动实现其中invoke方法,invoke方法包含了三个参数,当前代理类对象,Method对象(封装了要代理的方法),Object[]参数数组(封装了代理方法的参数值)
- 当我们创建代理对象之后,调用了代理方法,接着在代理类的内部调用了invoke方法,接着回调到了我们实现的invoke方法
- 在invoke方法中我们可以拿到代理的方法和参数,通过反射中method.invoke方法,传入被代理的对象。最终调用了代理对象的方法
网友评论