AOP详解

发布时间 2023-08-04 20:21:20作者: 蜗牛攀爬

1:AOP:AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

它提倡的是针对同一类问题的统一处理,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术

利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

2:AOP主要应用场景

日志记录,性能统计,安全控制,事务处理,异常处理等等。

3:各个时期的AOP:

 

 4:AOP分为静态AOP和动态AOP

1)静态AOP:APT和AspectJ

AspectJ 意思就是Java的Aspect,Java的AOP。AspectJ属于静态AOP,它是在编译时进行增强,会在编译时期将AOP逻辑织入到代码中。

由于是在编译器织入,所以它的优点是不影响运行时性能,缺点是不够灵活。

AspectJ框架用法:

 

 

基于AspectJ的框架Hugo:

 

 

动态AOP:

1)JDK动态代理(反射机制),使用InvocationHandler接口:

缺点:反射,影响性能。

Class<?> iActivityManagerClass = Class.forName("android.app.IActivityManager");
            Object mInstanceProxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                    new Class[]{iActivityManagerClass}, new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {


                            if ("startActivity".equals(method.getName())) {
                                int index = 0;
                                for (int i = 0; i < args.length; i++) {
                                    if (args[i] instanceof Intent) {
                                        index = i;
                                        break;
                                    }
                                }
                                Intent intent = (Intent) args[index];

                                //启动代理的Intent
                                Intent intentProxy = new Intent();
                                //宿主定义的用于欺骗AMS的Activity类
                                intentProxy.setClassName("packagename", "className");

                                //将插件的intent信息保存起来,供后续重新拿出来使用
                                intentProxy.putExtra(ORIGINAL_INTENT_INFO, index);

                                args[index] = intentProxy;
                            }
                            //第一个参数,系统的IActivity对象
                            return method.invoke(mInstance, args);
                        }
                    });


            //用代理对象替换掉系统的IActivityManager
            mInstanceField.set(singleton, mInstanceProxy);

 2)动态字节码生成

在运行期,目标类加载后,动态构建字节码文件生成目标类的子类,将切面逻辑加入到子类中,没有接口也可以织入,但扩展类的实例方法为final时,则无法进行织入。比如Cglib

CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。

3)自定义类加载器

在运行期,目标加载前,将切面逻辑加到目标字节码里。如:Javassist

Javassist是可以动态编辑Java字节码的类库。它可以在Java程序运行时定义一个新的类,并加载到JVM中;还可以在JVM加载时修改一个类文件。

4)ASM

ASM可以在编译期直接修改编译出的字节码文件,也可以像Javassit一样,在运行期,类文件加载前,去修改字节码。