AOP实现Android集中式登录架构,Android核心知识点

我们先来了解一下AOP,因为这个架构是基于AOP编程实现的。

  • 什么是AOP

关于AOP是什么,这里我简单介绍一下,AOP是Aspect Oriented Programming的缩写,即面向切面编程,与面向对象编程(oop)是两种不同的思维方式,也可以看做是对oop的一种补充。传统的oop开发会提倡功能模块化等,而aop适合于针对某一类型的问题统一处理。AOP思想的讲解不是我们本篇文章的重点,如果有同学对AOP思想不是很理解,这里我推荐一篇文章,讲得很不错Java AOP & Spring AOP 原理和实现

  • AspectJ介绍

AspectJ是一个面向切面编程的一个框架,它扩展了java语言,并定义了实现AOP的语法。我们知道,在将.java文件编译为.class文件时默认使用javac编译工具,而AspectJ会有一套符合java字节码编码规范的编译工具来替代javac,在将.java文件编译为.class文件时,会动态的插入一些代码来做到对某一类特定东西的统一处理。我举个例子,比如在应用中有很多个button的onClick事件需要检测是否登录,如果没有登录则需要去登录之后才能继续执行,针对这一类型的问题,相对笨一点的做法就是在每一个onClick方法中都显式的去判断登录状态,这样不免过于麻烦。而我们用AOP的方式实现的话,就需要在每一个onClick方法上加入一个标注,让编译器在编译时能识别到这个标注,然后根据标注来生成一些代码检测登录状态。好了,如果有同学对AOP还不是很理解的话也不用急,下面我会用例子来给大家演示如何使用AOP实现统一的集中式登录。

AOP实现集中式登录
  • aspectj环境搭建

首先,我们导入AspectJ的jar包,AspectJ的jar网上一搜就有,也可以直接去我demo里面拿,LoginArchitecture AOP实现集中式登录 github链接点我。demo里jar包导入: 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
好了,导入jar后还需要在app.gradle配置如下:

buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath ‘org.aspectj:aspectjtools:1.8.8’
classpath ‘org.aspectj:aspectjweaver:1.8.8’
}
}

然后在文件末尾添加如下代码:

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

variants.all { variant ->
//标注2
if (!variant.buildType.isDebuggable()) {
log.debug(“Skipping non-debuggable build type ‘${variant.buildType.name}’.”)
return;
}
//标注3
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);
//标注4
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;
}
}
}
}

关于上面这一大片代码就是对aspectj的配置,先看标注1,获取log打印工具和构建配置,然后标注2判断是否debug,如果打release把return去掉就可以,标注3处意思是使aspectj配置生效,标注4就是为了在编译时打印信息如警告、error等等,这些东西在网上也有很多,大家如果不理解,可以去搜索一下,这里不再详细解释。

  • 切面代码编写

好了,配置完上面的内容之后,我们就开始编写代码了,首先,定义一个注解LoginFilter,用来注解方法,以便在编译期被编译器检测到需要做切面的方法。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LoginFilter {

int userDefine() default 0;

}

大家看到我在注解里加了个userDefine,就是为了给用户提供自定义实现,如根据userDifine值不同做不同的登录处理。

然后,编写LoginSDK文件用于初始化和接收登录事件,代码如下:

public class LoginSDK {

public void init(Context context, ILogin iLogin) {
applicationContext = context.getApplicationContext();
LoginAssistant.getInstance().setApplicationContext(context);
LoginAssistant.getInstance().setiLogin(iLogin);
}

//…

}

然后,新建LoginFilterAspect.java文件用来处理加入LoginFilter注解的方法,对这些方法做统一的切面处理。

@Aspect
public class LoginFilterAspect {
private static final String TAG = “LoginFilterAspect”;

@Pointcut(“execution(@com.xsm.loginarchitecture.lib_login.annotation.LoginFilter * *(…))”)
public void loginFilter() {}

@Around(“loginFilter()”)
public void aroundLoginPoint(ProceedingJoinPoint joinPoint) throws Throwable {
//标注1
ILogin iLogin = LoginAssistant.getInstance().getiLogin();
if (iLogin == null) {
throw new NoInitException(“LoginSDK 没有初始化!”);
}

//标注2
Signature signature = joinPoint.getSignature();
if (!(signature instanceof MethodSignature)) {
throw new AnnotationException(“LoginFilter 注解只能用于方法上”);
}
MethodSignature methodSignature = (MethodSignature) signature;
LoginFilter loginFilter = methodSignature.getMethod().getAnnotation(LoginFilter.class);
if (loginFilter == null) {
return;
}

Context param = LoginAssistant.getInstance().getApplicationContext();
//标注3
if (iLogin.isLogin(param)) {
joinPoint.proceed();
} else {
iLogin.login(param, loginFilter.userDefine());
}
}
}

代码并不多,我们来一一解释。首先看loginFilter方法,这个方法上加入@Pointcut注解,并指定了LoginFilter注解的路径,@Pointcut注解包括aroundLoginPoint()方法上的@Around注解等都是AspectJ定义的API。@Pointcut注解代表切入点,具体就是指哪些方法需要被执行"AOP"。execution()里指定了LoginFilter注解的路径,即加入LoginFilter注解的方法就是需要处理的切面。@Around注解表示这个方法执行时机的前后都可以做切面处理,常用到的还有@Before、@After等等。@Before即方法执行前做处理,@After反之。
好了,aroundLoginPoint(ProceedingJoinPoint joinPoint)方法就是对切面的具体实现了,这里ProceedingJoinPoint参数意为环绕通知,这个类里面可以获取到方法的签名等各种信息。

标注1

首先看标注1处,我们先获取用户实现的ILogin类,如果没有调用init()设置初始化就抛出异常。

标注2

标注2处先得到方法的签名methodSignature,然后得到@LoginFilter注解,如果注解为空,就不再往下走。

标注3

然后看标注3,调用iLogin的isLogin()方法判断是否登录,这个isLogin是留给使用者自己实现的,如果登录,就会继续执行方法体调用方法直到完成,如果没有登录,调用ilogin的login方法,并把userDefine传过去,login方法是用户自己实现的。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后

由于题目很多整理答案的工作量太大,所以仅限于提供知识点,详细的很多问题和参考答案我都整理成了 PDF文件

]

最后

由于题目很多整理答案的工作量太大,所以仅限于提供知识点,详细的很多问题和参考答案我都整理成了 PDF文件

[外链图片转存中…(img-KKj19Dg8-1711924303610)]

[外链图片转存中…(img-LDaBRUTp-1711924303611)]

[外链图片转存中…(img-oUWYE4h4-1711924303611)]

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值