目录:
1.动态代理与静态代理的使用区别
2.动态代理实现原理
3.动态代理的使用场景
1.静态代理
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介角色。
public interface Iinterface {
void dosomething();
}
public class RealMovie implements Iinterface {
@Override
public void dosomething() {
System.out.println("做一些事");
}
}
上面是具体的实现类,下面是代理类
public class ProxyA implements Iinterface {
ProxyA mo;
public ProxyA(ProxyA mo) {
super();
this.mo = mo;
}
@Override
public void dosomething() {
ganbiedeshi(true);
mo.play();
}
public void ganbiedeshi(boolean isStart){
System.out.println("做一些别的事!");
}
}
调用时候就直接使用代理类,不直接使用实现类,里面可以做一些额外的逻辑。
2.动态代理
使用代码入下:
public interface IActionInterface{
void eat();
}
public static class Dog implements IActionInterface{
@Override
public void eat() {
Log.e("动态代理", "eat: 狗吃肉");
}
}
public void main(String[] args) {
Dog dog = new Dog();
IActionInterface action = (IActionInterface) Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), new Class[]{IActionInterface.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.e("动态代理", "method:" + method.getName());
return method.invoke(dog,args);
}
});
action.eat();
}
比起静态代理,没增加一个需要代理的对象都要增加代理类,而动态代理直接作用接口,在运行时候,动态创建代理类到内存数据分区中的方法区中,如果我们想看到,也可以通过下面代码在java中生成。
String name = IActionInterface.class.getName()+"$Proxy0"; //生成代理指定接口的Class数据
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{IActionInterface.class});
FileOutputStream fos = null;
try {
fos = new FileOutputStream("lib/" + name+".class");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
fos.write(bytes);
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
3.动态代理实现原理
根据上面的生成代码,我们把运行时生成的类写出来后,代码如下:
public final class $Proxy0 extends Proxy implements IActionInterface
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
/**
*注意这里是生成代理类的构造方法,方法参数为InvocationHandler类型,看到这,是不是就有点明白
*为何代理对象调用方法都是执行InvocationHandler中的invoke方法,而InvocationHandler又持有
*
*/
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
/**
*
*这里调用代理对象的giveMoney方法,直接就调用了InvocationHandler中的invoke方法,并把m3传了进去。
*this.h.invoke(this, m3, null);这里简单,明了。
*来,再想想,代理对象持有一个InvocationHandler对象,InvocationHandler对象持有一个被代理的对象,
*再联系到InvacationHandler中的invoke方法。嗯,就是这样。
*/
public final void eat()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("proxy. IActionInterface").getMethod("eat", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
1.首先执行
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
// 1.首先使用原型设计模式,保存传入的接口
final Class<?>[] intfs = interfaces.clone();
// 2.主线!!!!
Class<?> cl = getProxyClass0(loader, intfs);
try {
// 3.获取到上面类 通过反射创建并返回对象
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
}
return cons.newInstance(new Object[]{h});
//省略代码
}
可以看到就简单的几步,首先保存了传入的接口,然后获取到类,再通过反射创建类的对象并返回
2.类如何生成的
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
//完成检测接口数量后,调用代理缓存类中获取
return proxyClassCache.get(loader, interfaces);
}
3.通过代码proxyClassCache.get生成类
1.生成规则命名就是Proxy$0 0到N命名.生成的类继承Proxy,实现我们要代理的接口
2.构造方法传入了InvacationHandeler 给到super
3.默认静态代码块中反射创建m1 ,m2 ....作为参数包含我们的方法和object的方法
4.具体的方法中调用this.h.invoke(this, m3, null); 也就是重写的invoke方法
动态代理的使用场景
1.retrofit框架中调用create时候返回一个动态代理对象
public <T> T create(final Class<T> service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
————————————————
版权声明:本文为CSDN博主「Simple_ R 」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/M_sdn/article/details/84856273
2.ASM进程通信也使用到
3.可以做一些接口执行的统计,比如耗时,当然有网络请求拦截器