代理模式分动态代理和静态代理,写起来也比较简单,先上代码:
public interface Goal {
void sayHello();//定义一个接口,声明好要做的事儿
}
然后实现他,真实的目的
public class RealGoal implements Goal {
@Override
public void sayHello() {
System.out.println("hello! think you very much!");
}
}
这时候我们想打印hello! think you very much!,只需要 new RealGoal().sayHello(); 这样只执行代码就可以,但是既然是代理模式,肯定不能这样亲自动手,要找个代理人执行,所以还要创建个代理人
public class ProxyGoal implements Goal {
private Goal goal;
public ProxyGoal(Goal goal) {
this.goal = goal;
}
@Override
public void sayHello() {
goal.sayHello();
}
}
如何具体应用呢?
public class Test {
public static void main(String[] args) {
Goal realGoal = new RealGoal();
Goal proxyGoal = new ProxyGoal(realGoal);
proxyGoal.sayHello();
}
}
执行结果:
**刚开始学的时候,不知道你们有没有和我一样,有那种脱裤子放屁多此一举的感觉,既然我们想执行sayHello(),直接用realGoal.sayHello()就完了呗,为什么还要搞一个代理类呢????????**在回答这个问题之前,再来看看动态代理怎么写!
public class GoalHandler implements InvocationHandler {
Object object;
public GoalHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("I'm Proxy, I'm invoking...");
method.invoke(object, args);
System.out.println("invoke end!");
return null;
}
}
执行测试
public static void main(String[] args) {
Goal realGoal = new RealGoal();
InvocationHandler goalHandler = new GoalHandler(realGoal);
Goal dynamicProxyGoal = (Goal) Proxy.newProxyInstance(realGoal.getClass().getClassLoader(), realGoal.getClass().getInterfaces(), goalHandler);
dynamicProxyGoal.sayHello();
}
动态代理其实也一样,也多此一举,所以一定要结合使用场景,设计模式才有意义。这个代理模式很简单吧,顾名思义,多出来一个代理人,相当于你从基层员工直接变领导了,比如你想发个快递,本来你要亲自跟快递员打交道,但是代理模式让你拥有了一个小弟(proxy),有什么事儿你就叫你小弟去办理,然后你小弟再去找快递;当然这个事儿还可以是买烟,具体什么事儿无所谓,重点是多了一个小弟,而且这个小弟完全在你的掌握之中.
hook技术很简单,所谓hook点有点找后门的意思,只要找到hook点,就可以,现在模拟一个场景,android里面有个ActivityManagerNative,这个对象,他是和AMS进行通信的对象,所有的startActivity方法最后都要经过它里面的binder对象发送给AMS,这部分没看过源码的同学可能不懂,不过不要紧这不是重点;重点是这些类 这些对象正常情况下都是遥不可及的,我们无法直接使用他们;但是通过动态代理+反射就可以,这时候我们就可以走后门了,我们可以监听到startActvity的一些信息,从而做自己的手脚,先来写个小demo
代码结构很简单,system下代表系统级别的类,我们正常开发是无法使用的;我们能使用的只有应用层的Activity如图
Activity就是模拟我们android里的android.app.Activity 先来看结构,system下
public interface IActivityManager {
int startActivity(String intent);
}
public class ActivityManagerNative {
public static IActivityManager binder = new ActivityManagerImpl();
public static IActivityManager gDefault() {
return binder;
}
}
public class Log {
public static void i(String tag, String value) {
System.out.println(tag+" : "+value);
}
}
public class ActivityManagerImpl implements IActivityManager {
@Override
public int startActivity(String intent) {
System.out.println("我是AMS,将要启动activity对象是: "+intent);
return 0;
}
}
再来看application包下的activity
public class Activity {
public void statActivity(String i) {
ActivityManagerNative.gDefault().startActivity(i);
}
}
上面这些都是已经存在的类,我们这时候自定义一个activity,并且执行startActvity方法,告诉系统我们要启动的Activity是哪个
public class MainActivity extends Activity {
public static void main(String[] args) {
MainActivity mainActivity = new MainActivity();
mainActivity.statActivity("MainActivity");
}
}
那么问题来了!,我要在不影响正常开发的时候,我要对运行结果进行更改如何做?接着写一个类,里面包含了一个逻辑,检测要启动的activity是否包含NeedLogin,如果包含NeedLogin则直接打印LoginActivity,如果不包含就正常打印,不做改变
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class HookUtil {
private static final String TAG = "HookUtil";
/**
* 获取IActivityManager对象 将其替换掉
* 这里需要动态代理;
* 动态代理也是个时髦的技术;
*/
public void hookActivityStart() {
try {
//获取ActivityManager类
Class<?> activityManagerClass = Class.forName("com.example.myapplication.system.ActivityManagerNative");
//获取其IActivityManagerSingleton属性
Field iActivityManagerSingleton = activityManagerClass.getDeclaredField("binder");
iActivityManagerSingleton.setAccessible(true);
Object binder = iActivityManagerSingleton.get(activityManagerClass);
HookHandler hookHandler = new HookHandler(binder);
Object proxyInstance = Proxy.newProxyInstance(binder.getClass().getClassLoader(), binder.getClass().getInterfaces(), hookHandler);
//proxyInstance代理IActivityManager
iActivityManagerSingleton.set(activityManagerClass, proxyInstance);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
class HookHandler implements InvocationHandler {
private Object object;
public HookHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//拦截startActivity()方法
String name = method.getName();
Log.i(TAG, "调用" + name + "方法了");
if ("startActivity".contains(name)) {
// Log.i(TAG, "调用startActivity方法了");
//获取intent参数
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (arg instanceof String) {
if(((String) arg).contains("NeedLogin"))//此处判断逻辑,如果里面包含NeedLogin,则跳转LoginActivity,否则就正常执行
args[i] = "LoginActivity";
}
}
}
return method.invoke(object, args);
}
}
}
然后我们写测试的时候这样写
public class MainActivity extends Activity {
public static void main(String[] args) {
HookUtil hookUtil = new HookUtil();
hookUtil.hookActivityStart();
MainActivity mainActivity = new MainActivity();
mainActivity.statActivity("MainActivity");
mainActivity.statActivity("MineActivityNeedLogin");
}
}
我们可以看,字符串里包含NeedLogin的执行结果集完全变了,这就是典型的动态代理+反射 实现的hook结束、一般插件化、热修复或者某些场景都需要用到。
AOP的全称是Aspect-Oriented Programming,即面向切面编程(也称面向方面编程)。它是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式。就是一种编程思想。代码注入是AOP中的重要部分:AOP可用于日志埋点、性能监控、动态权限控制、甚至是代码调试等等。实现AOP的一个方式就有动态代理的模式,未完待续…