Hook学习笔记-代理设计模式

291 阅读3分钟

什么是代理设计模式 为某个对象提供一个代理,控制对这个对象的访问。对象和代理对象实现共同的父类或接口。

简单代理 比如去银行办卡,可以用机器办理,也可以找柜台。实现共同的父类和接口,对象能做的事情,代理对象也都可以做。

统一的接口

public interface IBank {
    void bank();
}

办理业务的人

public class Man implements IBank {
    @Override
    public void bank() {
        System.out.println("---- real");
    }
}

业务员

public class Salesman implements IBank {
    IBank realBank;

    public Salesman(IBank iBank) {
        this.realBank = iBank;
    }

    @Override
    public void bank() {
        System.out.println("---办理手续");
        realBank.bank();
        System.out.println("---结束操作");

    }
}
public class Main {
    public static void main(String[] args) {
        Man realBank = new Man();
        Salesman salesman = new Salesman(realBank);
        salesman.bank();
    }
}

动态代理

public class Main {
    public static void main(String[] args) {

        IBank realBank = new RealBank();
        IBank iBank = (IBank) Proxy.newProxyInstance(IBank.class.getClassLoader(), new Class[]{IBank.class},
                new BankInvocationHandler(realBank));
        iBank.bank();
    }

    private static class BankInvocationHandler implements InvocationHandler {
        IBank realBank;

        public BankInvocationHandler(IBank realBank) {
            this.realBank = realBank;
        }

// proxy 为代理对象
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("--- bank");
            Object object = method.invoke(realBank, args);
            return object;
        }
    }

}

动态代理拦截view的点击事件

Hook源码中的简单应用。 比如拦截view的点击事件,做些额外的事情。

1,查看setOnClickListener方法源码,查看赋值的属性。


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = findViewById(R.id.textView);
        TextOnClickListener textOnClickListener = new TextOnClickListener();
        textView.setOnClickListener(textOnClickListener);
        new HookViewClick().hook(textView);
    }
    private class TextOnClickListener implements View.OnClickListener {
        @Override
        public void onClick(View v) {
            Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_SHORT).show();
        }
    }

}



在View的 ListenerInfo mListenerInfo;对象的mOnClickListener对象是实际持有者。

  public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }
    
ListenerInfo getListenerInfo() {
        if (mListenerInfo != null) {
            return mListenerInfo;
        }
        mListenerInfo = new ListenerInfo();
        return mListenerInfo;
    }

通过反射来获取到该对象。并且为该对象创建一个代理对象。通过反射将代理对象重新设置给mOnClickListener。

  public void hook(View view) {

        try {
        // 通过反射获取到对象实例
            Field mListenerInfoField = View.class.getDeclaredField("mListenerInfo");
            mListenerInfoField.setAccessible(true);
            Object o = mListenerInfoField.get(view);
//            Method method = View.class.getDeclaredMethod("getListenerInfo");
//            method.setAccessible(true);
//            Object o = method.invoke(textView);
            Class cl = Class.forName("android.view.View$ListenerInfo");
            Field listenerInfoOnClickField = cl.getDeclaredField("mOnClickListener");
            listenerInfoOnClickField.setAccessible(true);
            View.OnClickListener yListener = (View.OnClickListener) listenerInfoOnClickField.get(o);


// 动态代理。
            View.OnClickListener proxyOnClick = (View.OnClickListener)
                    Proxy.newProxyInstance(View.class.getClassLoader(),
                            new Class[]{View.OnClickListener.class},
                            new TextOnClickInvocationHandler(yListener));

// 静态代理
//            TextOnClickProxyListener proxyOnClick = new TextOnClickProxyListener(yListener);

            listenerInfoOnClickField.set(o, proxyOnClick);


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  // 动态代理
  private class TextOnClickInvocationHandler implements InvocationHandler {
        View.OnClickListener textOnClickListener;

        public TextOnClickInvocationHandler(View.OnClickListener textOnClickListener) {
            this.textOnClickListener = textOnClickListener;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            System.out.println("-----  invoke");

            Object object = method.invoke(this.textOnClickListener, args);


            return object;
        }
    }
    
    //静态代理
    private class TextOnClickProxyListener implements View.OnClickListener {
        View.OnClickListener mOnClickListener;

        public TextOnClickProxyListener(View.OnClickListener onClickListener) {
            mOnClickListener = onClickListener;
        }

        @Override
        public void onClick(View v) {
            System.out.println("---- onclick Proxy");
            mOnClickListener.onClick(v);
        }
    }

Retrofit中的动态代理

Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.from(EXECUTOR)))
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(builder.build())
                .build();
                
                
retrofit.create(clazz);            

 public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service); //检查service是不是一个接口
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          @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);
            }
            // 对method的注解进行解析,构造成我们适配的对象,call或者observable
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }


Proxy 原理

一般是通过 Proxy.newProxyInstance(,,) 创建和使用代理对象。那么这个方法是怎么来创建出的代理对象呢?是怎么回调到InvocationHandler的invoke方法中的呢?


@CallerSensitive

public static Object newProxyInstance(

ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

throws IllegalArgumentException

{

final Class<?>[] intfs = interfaces.clone();

Class<?> cl = getProxyClass0(loader, intfs);

final Constructor<?> cons = cl.getConstructor(constructorParams);

return cons.newInstance(new Object[]{h});

}

在这个方法里发现,先是clone了一下接口,然后就调用了 getProxyClass0 方法来获取了一个Class。 然后通过 getProxyClass0 返回的代理类Calss,创建了一个对象。


private static final WeakCache<ClassLoader, Class<?>[], Class<?>>

proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

private static Class<?> getProxyClass0(ClassLoader loader,

Class<?>... interfaces) {

if (interfaces.length > 65535) {

throw new IllegalArgumentException("interface limit exceeded");

}

return proxyClassCache.get(loader, interfaces);

}

而在 getProxyClass0 调用了 WeakCache 的get方法。WeakCache从名字来判断也可得知是一个用来缓存对象的。WeakCache原理, 而它的构造方法中第二个参数是创建一个 ProxyClassFactory 对象。


private static final class ProxyClassFactory

implements BiFunction<ClassLoader, Class<?>[], Class<?>>

{

// prefix for all proxy class names

private static final String proxyClassNamePrefix = "$Proxy";

// next number to use for generation of unique proxy class names

private static final AtomicLong nextUniqueNumber = new AtomicLong();

@Override

public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);

for (Class<?> intf : interfaces) {

/*

* Verify that the class loader resolves the name of this

* interface to the same Class object.

*/

Class<?> interfaceClass = null;

try {

interfaceClass = Class.forName(intf.getName(), false, loader);

} catch (ClassNotFoundException e) {

}

if (interfaceClass != intf) {

throw new IllegalArgumentException(intf + " is not visible from class loader");

}

// 不是interface的时候,抛出异常

if (!interfaceClass.isInterface()) {

throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");

}

/*

* Verify that this interface is not a duplicate.

*/

if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {

throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());

}

}

String proxyPkg = null; // package to define proxy class in

int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

for (Class<?> intf : interfaces) {

int flags = intf.getModifiers();

if (!Modifier.isPublic(flags)) {

accessFlags = Modifier.FINAL;

String name = intf.getName();

int n = name.lastIndexOf('.');

String pkg = ((n == -1) ? "" : name.substring(0, n + 1));

if (proxyPkg == null) {

proxyPkg = pkg;

} else if (!pkg.equals(proxyPkg)) {

throw new IllegalArgumentException(

"non-public interfaces from different packages");

}

}

}

if (proxyPkg == null) {

proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";

}

long num = nextUniqueNumber.getAndIncrement();

// 生成代理类名

String proxyName = proxyPkg + proxyClassNamePrefix + num;

//生成类的byte

byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);

try {

return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);

} catch (ClassFormatError e) {

throw new IllegalArgumentException(e.toString());

}

}

}

private static native Class<?> defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);

在这个方法里遍历了每一个Class,并生成 $Proxy0 类名,然后调用 ProxyGenerator.generateProxyClass来生成类的byte。defineClass0 是一个native方法,将byte内容写入到磁盘。


public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {

ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);

final byte[] var4 = var3.generateClassFile();

return var4;

}

private byte[] generateClassFile() {

this.addProxyMethod(hashCodeMethod, Object.class);

this.addProxyMethod(equalsMethod, Object.class);

this.addProxyMethod(toStringMethod, Object.class);

Class[] var1 = this.interfaces;

int var2 = var1.length;

int var3;

Class var4;

for(var3 = 0; var3 < var2; ++var3) {

var4 = var1[var3];

Method[] var5 = var4.getMethods();

int var6 = var5.length;

for(int var7 = 0; var7 < var6; ++var7) {

Method var8 = var5[var7];

this.addProxyMethod(var8, var4);

}

}

Iterator var11 = this.proxyMethods.values().iterator();

List var12;

while(var11.hasNext()) {

var12 = (List)var11.next();

checkReturnTypes(var12);

}

Iterator var15;

try {

this.methods.add(this.generateConstructor());

var11 = this.proxyMethods.values().iterator();

while(var11.hasNext()) {

var12 = (List)var11.next();

var15 = var12.iterator();

while(var15.hasNext()) {

ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();

this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));

this.methods.add(var16.generateMethod());

}

}

this.methods.add(this.generateStaticInitializer());

} catch (IOException var10) {

throw new InternalError("unexpected I/O Exception", var10);

}

if (this.methods.size() > 65535) {

throw new IllegalArgumentException("method limit exceeded");

} else if (this.fields.size() > 65535) {

throw new IllegalArgumentException("field limit exceeded");

} else {

this.cp.getClass(dotToSlash(this.className));

this.cp.getClass("java/lang/reflect/Proxy");

var1 = this.interfaces;

var2 = var1.length;

for(var3 = 0; var3 < var2; ++var3) {

var4 = var1[var3];

this.cp.getClass(dotToSlash(var4.getName()));

}

this.cp.setReadOnly();

ByteArrayOutputStream var13 = new ByteArrayOutputStream();

DataOutputStream var14 = new DataOutputStream(var13);

try {

var14.writeInt(-889275714);

var14.writeShort(0);

var14.writeShort(49);

this.cp.write(var14);

var14.writeShort(this.accessFlags);

var14.writeShort(this.cp.getClass(dotToSlash(this.className)));

var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));

var14.writeShort(this.interfaces.length);

Class[] var17 = this.interfaces;

int var18 = var17.length;

for(int var19 = 0; var19 < var18; ++var19) {

Class var22 = var17[var19];

var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));

}

var14.writeShort(this.fields.size());

var15 = this.fields.iterator();

while(var15.hasNext()) {

ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();

var20.write(var14);

}

var14.writeShort(this.methods.size());

var15 = this.methods.iterator();

while(var15.hasNext()) {

ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();

var21.write(var14);

}

var14.writeShort(0);

return var13.toByteArray();

} catch (IOException var9) {

throw new InternalError("unexpected I/O Exception", var9);

}

}

}

在这个方法里生成了代理类的内容,这个类继承了Proxy,并且实现了InvocationHandler。

在实现的接口中调用了 InvocationHandler 的 invoke 方法。第一个参数是代理对象,第二个是调用的方法,第三个是参数。