集中式登录架构设计(AOP)

这篇文章讲的是面向切面思想之集中式登录架构设计,也就是AOP。

什么是面向切面思想之集中式登录架构设计呢,这里我觉得可以联系一下拦截功能,就好理解了。

比如一个电商的App,有三个功能模块,分别是我的专区,我的优惠券,我的积分。且这三个功能模块有一个共同的特点就是,他们必须要登录之后,才能进到具体的页面去得到更多的服务。

作为资深工程师的我们一定不会在每个入口处手写登录校验逻辑这种不符合我们资深工程师身份的写法。

这时候我们AOP,面向切面的编程思想就出来了。

在这里插入图片描述
既然好几个模块都需要走登录这个流程,那我们就将登录页面一刀切,进入三个模块的具体页面时都需要经过登录校验,这就是我们这边文章将的核心内容了。

录屏
在这里插入图片描述
日志:
在这里插入图片描述

本文中的切面设计使用aspectj来实现:

buildscript {
    
    dependencies {
        。。。

        // 版本界限:As-3.0.1 + gradle4.4-all (需要配置r17的NDK环境)
        // 或者:As-3.2.1 + gradle4.6-all (正常使用,无警告)
        classpath 'org.aspectj:aspectjtools:1.8.9'
        classpath 'org.aspectj:aspectjweaver:1.8.9'
    }
}
implementation 'org.aspectj:aspectjrt:1.8.13'

关键代码:

1、定义ClickBehavior和LoginCheck两个注解。

// 用户点击痕迹(行为统计)  IoC容器
@Target(AnnotationTarget.FUNCTION)  // 目标作用在方法之上
@Retention(value = AnnotationRetention.RUNTIME)
annotation class ClickBehavior(val value: String)
// 用户登录检测
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class LoginCheck()

2、在Activity中定义了一个登录按钮模拟登录,定义“我的专区”,“我的优惠券”,“我的积分”,将定义好的两个注解加到对应的点击事件上去。

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private val TAG = "lr >>> "

    companion object {
        var isLogin = false
    }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }


    // 登录点击事件(用户行为统计)
    @ClickBehavior("登录")
    fun login(view: View) {
        Log.e(TAG, "模拟接口请求……验证通过,登录成功!")
        isLogin = true
    }

    // 用户行为统计(友盟统计?!后台要求自己统计)
    @ClickBehavior("我的专区")
    @LoginCheck
    fun area(view: View) {
        Log.e(TAG, "开始跳转到 -> 我的专区 Activity")
        startActivity(Intent(this, OtherActivity::class.java))
    }

    // 用户行为统计
    @ClickBehavior("我的优惠券")
    @LoginCheck
    fun coupon(view: View) {
        Log.e(TAG, "开始跳转到 -> 我的优惠券 Activity")
        startActivity(Intent(this, OtherActivity::class.java))
    }

    // 用户行为统计
    @ClickBehavior("我的积分")
    @LoginCheck
    fun score(view: View) {
        Log.e(TAG, "开始跳转到 -> 我的积分 Activity")
        startActivity(Intent(this, OtherActivity::class.java))
    }
}

3、接下来就是如何对拦截到的事件做处理了,这里就用到了Aspect,参考代码如下。

@Aspect
class ClickBehaviorAspect {

    private val TAG = "lr >>> "

    // 1、应用中用到了哪些注解,放到当前的切入点进行处理(找到需要处理的切入点)
    // execution,以方法执行时作为切点,触发Aspect类
    // * *(..)) 可以处理ClickBehavior这个类所有的方法
    @Pointcut("execution(@pers.owen.aop_login.annotation.ClickBehavior * *(..))")
    public fun methodPointCut() {}

    // 2、对切入点如何处理
    @Around("methodPointCut()")
    @Throws(Throwable::class)
    open fun jointPotin(joinPoint: ProceedingJoinPoint): Any? {
        // 获取签名方法
        val methodSignature = joinPoint.signature as MethodSignature

        // 获取方法所属的类名
        val className = methodSignature.declaringType.simpleName

        // 获取方法名
        val methodName = methodSignature.name

        // 获取方法的注解值(需要统计的用户行为)
        val funName: String =
            methodSignature.method.getAnnotation(ClickBehavior::class.java).value

        // 统计方法的执行时间、统计用户点击某功能行为。(存储到本地,每过x天上传到服务器)
        val begin = System.currentTimeMillis()
        Log.e(TAG, "ClickBehavior Method Start >>> ")
        val result = joinPoint.proceed() // MainActivity中切面的方法
        val duration = System.currentTimeMillis() - begin
        Log.e(TAG, "ClickBehavior Method End >>> ")
        Log.e(
            TAG, String.format("统计了:%s功能,在%s类的%s方法,用时%d ms",
                funName, className, methodName, duration
            )
        )
        return result
    }
}
@Aspect // 定义切面类
class LoginCheckAspect {

    private val TAG = "lr >>> "

    // 1、应用中用到了哪些注解,放到当前的切入点进行处理(找到需要处理的切入点)
    // execution,以方法执行时作为切点,触发Aspect类
    // * *(..)) 可以处理ClickBehavior这个类所有的方法
    @Pointcut("execution(@pers.owen.aop_login.annotation.LoginCheck * *(..))")
    fun methodPointCut(){}

    // 2、对切入点如何处理
    @Around("methodPointCut()")
    @Throws(Throwable::class)
    open fun jointPotin(joinPoint: ProceedingJoinPoint): Any? {
        val context = joinPoint.getThis() as Context
        return if (MainActivity.isLogin) { // 从SharedPreferences中读取
            Log.e(TAG, "检测到已登录!")
            joinPoint.proceed()
        } else {
            Log.e(TAG, "检测到未登录!")
            Toast.makeText(context, "请先登录!", Toast.LENGTH_SHORT).show()
            context.startActivity(Intent(context, LoginActivity::class.java))
            null // 不再执行方法(切入点)
        }
    }
}

参考Demo下载地址


About

AOP面向切面架构设计
集中式登录架构设计(AOP)

架构师系列文章一览

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT小瓯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值