Agent dynamique et application pratique

Examinons d'abord le modèle proxy

Le mode proxy est divisé en proxy dynamique et proxy statique. Il est relativement simple à écrire. Tout d'abord, ajoutez le code:

public interface Goal {
    
    
    void sayHello();//定义一个接口,声明好要做的事儿
}

Et puis atteindre son vrai but

public class RealGoal implements Goal {
    
    

    @Override
    public void sayHello() {
    
    
        System.out.println("hello! think you very much!");
    }
}

Pour le moment, nous voulons imprimer bonjour! Je vous en prie beaucoup !, nous n'avons besoin que de nouveau RealGoal (). SayHello (); pour que nous ne puissions exécuter que le code, mais comme il est en mode proxy, nous ne pouvons certainement pas faites-le de cette façon et trouvez un agent pour l'exécuter. Alors créez un agent

public class ProxyGoal implements Goal {
    
    

    private Goal goal;

    public ProxyGoal(Goal goal) {
    
    
        this.goal = goal;
    }

    @Override
    public void sayHello() {
    
    
        goal.sayHello();
    }
}

Comment l'appliquer spécifiquement?

public class Test {
    
    

    public static void main(String[] args) {
    
    

        Goal realGoal = new RealGoal();

        Goal proxyGoal = new ProxyGoal(realGoal);
        proxyGoal.sayHello();
    }
}

Résultat de l'exécution:
Insérez la description de l'image ici
** Quand j'ai commencé à apprendre, je me demande si vous avez l'impression d'enlever votre pantalon et de péter sans rien faire comme moi. Puisque nous voulons exécuter sayHello (), nous utilisons simplement realGoal.sayHello () et c'est fini. Pourquoi? Voulez-vous créer une classe proxy? ? ? ? ? ? ? ? ** Avant de répondre à cette question, voyons comment écrire un proxy dynamique!

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;
    }
}

Exécuter le test

    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();
    }

En fait, les agents dynamiques sont les mêmes et ils sont superflus, de sorte que le modèle de conception doit être combiné avec les scénarios d'utilisation pour avoir un sens. Ce modèle d'agence est très simple. Comme son nom l'indique, un agent supplémentaire équivaut à passer directement d'un employé de base à un responsable. Par exemple, si vous voulez envoyer un courrier, vous devez vous-même traiter avec le courrier, mais le modèle d'agence vous permet d'avoir un Bro (proxy), si vous avez quelque chose, demandez simplement à votre petit frère de s'en occuper, puis à votre petit frère de trouver le courrier; bien sûr, cette chose peut aussi acheter des cigarettes, c'est peu importe ce que la chose spécifique est, le fait est qu'il y a un petit frère supplémentaire, et ce petit frère est complètement à votre portée.

Utilisez le scénario 1: proxy dynamique + réflexion pour implémenter la technologie hook

La technologie de crochet est très simple. Le soi-disant point de crochet signifie rechercher une porte dérobée. Tant que vous trouvez le point de crochet, vous pouvez simuler une scène. Il existe un ActivityManagerNative dans Android. Cet objet est l'objet avec lequel il communique AMS. Toutes les méthodes startActivity sont à la fin. Il doit être envoyé à AMS via l'objet de classeur qu'il contient. Les étudiants qui n'ont pas lu le code source peuvent ne pas comprendre cette partie, mais cela n'a pas d'importance. Ce n'est pas le but; le point est que ces types d'objets sont normalement hors de portée et que nous ne pouvons pas les utiliser directement. Ils; mais par proxy dynamique + réflexion, nous pouvons passer par la porte dérobée, nous pouvons écouter certaines informations de startActvity, afin de faire les nôtres mains et pieds, d'abord pour écrire une petite
structure de code de démonstration est très simple, le système représente la classe de niveau système, nous ne pouvons pas l'utiliser dans le développement normal; nous ne pouvons utiliser que l'activité de la couche d'application. Comme le montre la figure,
Insérez la description de l'image ici
L'activité consiste à simuler l'activité android.app.Activity dans notre Android. Examinons d'abord la structure, sous système

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;
    }
}

Regardons l'activité sous le package d'application

public class Activity {
    
    

    public void statActivity(String i) {
    
    
        ActivityManagerNative.gDefault().startActivity(i);
    }

}

Les classes ci-dessus sont toutes des classes existantes. Pour le moment, nous personnalisons une activité et exécutons la méthode startActvity pour indiquer au système quelle activité nous voulons démarrer.

public class MainActivity extends Activity {
    
    

    public static void main(String[] args) {
    
    

        MainActivity mainActivity = new MainActivity();
        mainActivity.statActivity("MainActivity");

    }
}

Résultats de la:Insérez la description de l'image ici

Voici donc le problème! , Comment modifier le résultat en cours d'exécution s'il n'affecte pas le développement normal? Ensuite, écrivez une classe, qui contient une logique pour détecter si l'activité à démarrer contient NeedLogin, si elle contient NeedLogin, elle imprimera directement LoginActivity, si elle ne la contient pas, elle s'imprimera normalement sans aucune modification.

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);
        }
    }

}

Ensuite, quand nous écrivons le test, écrivez-le comme ceci

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");

    }
}

Résultats de la:
Insérez la description de l'image ici

Nous pouvons voir que le jeu de résultats d'exécution contenant NeedLogin dans la chaîne a complètement changé. C'est la fin du hook implémenté par le proxy dynamique typique + réflexion, plug-in général, réparation à chaud ou certains scénarios.

AOP (programmation orientée aspect)

Le nom complet d'AOP est la programmation orientée aspect, c'est-à-dire la programmation orientée aspect (également appelée programmation orientée aspect). Il s'agit d'un complément à la programmation orientée objet (POO) et est devenu une méthode de programmation relativement mature. C'est une sorte de pensée programmatique. L'injection de code est une partie importante d'AOP: AOP peut être utilisé pour l'enfouissement des journaux, la surveillance des performances, le contrôle d'accès dynamique et même le débogage de code. Une façon de réaliser AOP est le modèle proxy dynamique, à suivre ...

Je suppose que tu aimes

Origine blog.csdn.net/english111999/article/details/114044025
conseillé
Classement