前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简单聊聊AspectJ

简单聊聊AspectJ

作者头像
提莫队长
发布2020-06-02 15:29:32
9920
发布2020-06-02 15:29:32
举报
文章被收录于专栏:刘晓杰刘晓杰

1.AspectJ引入

考虑一个要在某些应用中实施安全策略的问题。安全性是贯穿于系统所有模块间的问题,而且每一模块都必须添加安全性才能保证整个应用的安全性,并且安全性模块自身也需要安全性. 传统的面向对象编程中,每个单元就是一个类,而类似于安全性这方面的问题,它们通常不能集中在一个类中处理因为它们横跨多个类,这就导致了代码无法重用,它们是不可靠 和不可承继的,这样可维护性差而且产生了大量代码冗余,这是我们不愿意看到的。 使用传统的编程解决此问题非常的困难而且容易产生差错,这就正是 AspectJ 发挥作用的时候了。

2.相关概念

AspectJ 是一种面向方面程序(AOP)设计的基于 Java 的实现。它向 Java 中加入了连接点(Join Point)这个新概念。它向Java语言中加入少许新结构:切点(pointcut)、通知(Advice)、类型间声明(Inter-type declaration)和方面(Aspect)。 切点和通知动态地影响程序流程,类型间声明则是静态的影响程序的类等级结构,而方面则是对所有这些新结构的封装。 连接点是程序流中适当的一点。切点收集特定的连接点集合和在这些点中的值。一个通知是当一个连接点到达时执行的代码,这些都是AspectJ的动态部分。其实连接点就好比是程序中的一条一条的语句,而切点就是特定一条语句处设置的一个断点,它收集了断点处程序栈的信息,而通知就是在这个断点前后想要加入的程序代码。

3.简单实践

3.1配置

整个项目的gradle中如下修改

代码语言:javascript
复制
buildscript {
    
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.4'
        classpath 'org.aspectj:aspectjtools:1.9.4'
        classpath 'org.aspectj:aspectjweaver:1.9.4'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

app.gradle中如下修改

代码语言:javascript
复制
dependencies {
    ......
    implementation 'org.aspectj:aspectjrt:1.9.4'
    ......
}

import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
final def log = project.logger
final def variants = project.android.applicationVariants

variants.all { variant ->
    if (!variant.buildType.isDebuggable()) {
        log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return;
    }

    JavaCompile javaCompile = variant.javaCompile
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo",
                         "-1.8",
                         "-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
        log.debug "ajc args: " + Arrays.toString(args)

        MessageHandler handler = new MessageHandler(true);
        new Main().run(args, handler);
        for (IMessage message : handler.getMessages(null, true)) {
            switch (message.getKind()) {
                case IMessage.ABORT:
                case IMessage.ERROR:
                case IMessage.FAIL:
                    log.error message.message, message.thrown
                    break;
                case IMessage.WARNING:
                    log.warn message.message, message.thrown
                    break;
                case IMessage.INFO:
                    log.info message.message, message.thrown
                    break;
                case IMessage.DEBUG:
                    log.debug message.message, message.thrown
                    break;
            }
        }
    }
}
3.2定义注解
代码语言:javascript
复制
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BehaviorTrace {
    String value();
}
3.3实现切面(Aspect)
代码语言:javascript
复制
@Aspect
public class BehaviorAspect {

    // 定义切入点函数
    // 切点,执行com.xiaofan.customcontrol.annotation.BehaviorTrace路径下的注解
    // 后面的**..都是切入点指示符,在这里不细讲
    @Pointcut("execution(@com.example.liuxiaojie.aspectjdemo.BehaviorTrace * *(..))")
    public void annoBaviorTrace() {}

    /**
     * 五种通知
     */

    @Before("annoBaviorTrace()")
    public void before() {
        Log.i("wxf","before");
    }

    //执行annoBaviorTrace方法
    @Around("annoBaviorTrace()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        BehaviorTrace anno = methodSignature.getMethod().getAnnotation(BehaviorTrace.class);

        String functionName = anno.value();

        Log.i("tag","方法:"+functionName);
        long begin = System.currentTimeMillis();
        //控制方法执行
        Object result= joinPoint.proceed();

        long duration = System.currentTimeMillis() - begin;

        Log.i("tag","方法耗时:"+duration+" ms");
        return result;
    }

    @After("annoBaviorTrace()")
    public void after() {
        Log.i("tag","After");
    }

    @AfterReturning(value = "annoBaviorTrace()", returning = "returnVal")
    public void afterReturn(Object returnVal) {
        Log.i("tag","afterReturn" + returnVal);
    }

    @AfterThrowing(value = "annoBaviorTrace()", throwing = "e")
    public void afterThrow() {
        Log.i("tag","afterThrow");
    }
}
3.4测试

现在添加如下测试代码进行测试,调用test以后就可以看到对应的log打出

代码语言:javascript
复制
    @BehaviorTrace("method")
    public void test() {
        Log.i("wxf","test");
    }
3.5简单总结

先来简单看一下相关的class文件(test方法对应的class文件的内容)

代码语言:javascript
复制
    @BehaviorTrace("method")
    public void test() {
        JoinPoint var1 = Factory.makeJP(ajc$tjp_0, this, this);

        try {
            BehaviorAspect.aspectOf().before();
            test_aroundBody1$advice(this, var1, BehaviorAspect.aspectOf(), (ProceedingJoinPoint)var1);
        } catch (Throwable var4) {
            BehaviorAspect.aspectOf().after();
            throw var4;
        }

        BehaviorAspect.aspectOf().after();
        Object var3 = null;
        BehaviorAspect.aspectOf().afterReturn(var3);
    }

可以看到生成JoinPoint,然后按照顺序before,after一步一步执行下去 接下来可以对第二点相关概念进行更为详细的阐述

  • 连接点(Join Point)---就是你需要添加代码的具体的位置,由Aspect自动生成
  • 切点(pointcut)---就是加了Pointcut注解的函数,表示要添加代码的具体的位置,由它来决定Join Point的生成位置
  • 通知(Advice)---就是Before,Around等五种通知
  • 类型间声明(Inter-type declaration)---Aspect内部定义的属性,这个demo没有
  • 方面(Aspect)------就是以上四点的封装,也就是加了Aspect注解的BehaviorAspect类

总结:由pointcut决定Join Point的位置,然后通过Advice函数通知出去 具体可以参考关于 Spring AOP (AspectJ) 你该知晓的一切,《AspectJ程序设计指南.pdf》.第一篇文章里面还有对相关概念的详细解释

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.AspectJ引入
  • 2.相关概念
  • 3.简单实践
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档