写给Android工程师的AOP知识

AbstractProcessor小例子 利用annotationProcessor插件在编译期创建Java文件,减少维护成本,提高工作效率 立即下载

作者:树獭非懒

如果你接触过Java后台开发,一定听过AOP的概念,它到底是什么东西,对我们Android开发有什么用呢?本博客站在Android工程师的角度探索一下AOP这个熟悉又陌生的概念:

AOP是个啥

AOP是Aspect Oriented Program的首字母缩写,翻译过来就是面向切面编程。这个概念中面向容易理解,编程可以理解,最关键的是切面是指什么?

在理解切面之前,先回顾一下我们熟悉的OOP(Object-Oriented Programming),面向对象编程。

我们知道,面向对象的特点是继承、多态和封装。而封装就要求将功能分散到不同的类中去,这在软件设计中往往称为职责分配,这样做的好处是降低了代码的复杂程度,使类具备了可重用性。

但是在分散代码的同时,也增加了代码的重复性。什么意思呢?

举个栗子,假设我们要对两个类的每个方法添加日志。按面向对象的设计方法,我们就必须在这两个类的方法中都加上日志的代码。也许添加的日志代码是完全相同的,但也正是因为面向对象的设计,让类与类之间无法联系,而不能将这些重复的代码统一起来。

也许你想到了方法:我们可以将这段代码写在一个独立的类的某个方法里(比如工具类),然后在两个类中调用。但是,这样一来,这两个类和新增独立的类就有耦合了,也就是说独立类代码的改变会直接影响这两个类。

那么,有没有什么办法,可以不需要干涉到两个类原本的关系而实现功能呢?

我们可以用抽象思维去思考这个问题,对类的每个方法添加日志这个操作是一个相对更泛的操作。

它不同于对A类的B方法添加日志这种偏向于具体的点的操作。所以它更像是对一个面来操作,这类操作就叫做切面。

一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。

由于OOP的编程思路,并不能帮我们实现这类切面操作,而我们确实有这类需求,所以就有了AOP的概念,AOP像OOP一样,只是一种编程范式,它本身并没有规定说一定要用什么方式去实现。从上面一大串的解释,也可以看出AOP其实是对OOP的一个补充。

简单的概括上面的内容就是,面向切面编程可以对多个没有关联的类的某一类功能进行管理。

AOP的实现方式

静态AOP

在编译器,切面直接以字节码的形式编译到目标字节码文件中。

1.AspectJ

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

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

2.AbstractProcessor

自定义一个AbstractProcessor,在编译期去解析编译的类,并且根据需求生成一个实现了特定接口的子类(代理类)

动态AOP

1.JDK动态代理

通过实现InvocationHandler接口,可以实现对一个类的动态代理,通过动态代理可以生成代理类,从而在代理类方法中,在执行被代理类方法前后,添加自己的实现内容,从而实现AOP。

2.动态字节码生成

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

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

3.自定义类加载器

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

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

4.ASM

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

AspectJ的应用

AspectJ的介绍

AspectJ提供了两套强大的机制:

第一套是切面语法。就是网上随便一搜的AspectJ使用方法,它把决定是否使用切面的权利还给了切面。就是说在写切面的时候就可以决定哪些类的哪些方法会被代理,从而从逻辑上不需要侵入业务代码。

由于这套语法实在是太有名,导致很多人都误以为AspectJ就是这一套切面语法,其实不然。

第二套是织入工具。上面介绍的切面语法能够让切面从逻辑上与业务代码解耦,但是从操作上来讲,当JVM运行业务代码的时候,他无从得知旁边还有个类想横插一刀。解决思路就是在编译期(或者类加载期)我们优先考虑一下切面代码,并将切面代码通过某种形式插入到业务代码中,这样业务代码不就知道自己被“切”了么?这种思路的一个实现就是aspectjweaver,就是这里的织入工具。

AspectJ提供了两套对切面的描述方法:

一种就是我们常见的基于java注解切面描述的方法,这种方法兼容java语法,写起来十分方便,不需要IDE的额外语法检测支持。

另外一种是基于aspect文件的切面描述方法,这种语法本身并不是java语法,因此写的时候需要IDE的插件支持才能进行语法检查。

AspectJ的使用方法

本文主要介绍基于java注解的这种常用使用方式。

先了解下AspectJ提供的注解:

  • @Aspect:表明这是一个AspectJ文件,编译器在编译的时候,就会自动去解析,然后将代码注入到相应的JPonit中
  • @Pointcut:表示具体的切入点,可以确定具体织入代码的地方。可以通过通配、正则表达式等指定点
  • @Before:表示在调用点之前,调用该方法
  • @After:表示在调用点之后,再调用该方法
  • @Around:使用该方法代替该点的执行

Join Point 表示连接点,即 AOP 可织入代码的点:

Pointcuts是具体的切入点,可以确定具体织入代码的地方。可以通过通配、正则表达式等指定点,常用的有:

区分execution和call:

execution: 用于匹配方法执行的连接点,意思是说,直接在方法内部的前或者后添加。

call: 调用匹配到的方法时调用

AspectJ在Android中的应用

AspectJ我们最常看到的是Spring中的应用,那么在Android中有没有它的用武之地呢?

那必然是有的,下面会用两个栗子来看看有什么应用场景会需要用到它

先准备好环境,需要使用AspectJX插件:AspectJX插件地址

project的build.gradle添加依赖

classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10'

module的build.gradle应用插件

plugins {
    id 'android-aspectjx'
}

AspectJX是一个基于AspectJ并在此基础上扩展出来可应用于Android开发平台的AOP框架,可作用于java源码,class文件及jar包,同时支持kotlin的应用。

为什么选用AspectJX而不是基础的AspectJ或其他?

目前其他的AspectJ相关插件和框架都不支持AAR或者JAR切入的,对于Kotlin更加无能为力(以下栗子均为kotlin实现)

栗子一:实现一种方式可防止View连续快速点击

相信客户端的同学应该都会被测试这样的手法摧残过吧:快速点击很多次某按钮导致xxx…

对于这个栗子来说,防止view快速点击这个操作就是一个切面,所以可以用AspectJ进行切面编程。

定义一个注解@FastClickView,参数interval表示多长时间内只有一次点击生效:

@Target(AnnotationTarget.FUNCTION)
@Retention(value = AnnotationRetention.RUNTIME)
annotation class FastClickView(val interval: Long = 3000L)

定义FastClickViewAspect类,把该类作为切面类:对该类添加@Aspect注解

确定切入点:只要使用了FastClickView注解的方法均生效。

使用execution匹配方法执行

// @com.example.aopdemo.FastClickView * *(..) 表示任何支持FastClickView注解的方法
@Pointcut("execution(@com.example.aopdemo.FastClickView * *(..))")

完整代码如下:

@Aspect
class FastClickViewAspect {
    @Pointcut("execution(@com.example.aopdemo.FastClickView * *(..))")
    fun executeFastClickViewLimit() { }
​
    @Around("executeFastClickViewLimit()")
    @Throws(Throwable::class)
    fun aroundExecuteFastClickViewLimit(joinPoint: ProceedingJoinPoint) {
        Log.d(TAG, "aroundClickCountLimit: ")
        val signature: MethodSignature = joinPoint.signature as MethodSignature
        // 取出JoinPoint的方法
        val method = signature.method
        if (method.isAnnotationPresent(FastClickView::class.java)) {
            val annotation: FastClickView? = method.getAnnotation(FastClickView::class.java)
            annotation?.let {
                val interval = annotation.interval
                val view = joinPoint.args[0] as View
                if (!FastClickCheckUtil.isFastClick(view, interval)) {
                    joinPoint.proceed()
                }
            }
        }
    }
}
​
​
object FastClickCheckUtil {
    private const val TAG = "FastClickCheckUtil"
    /**
     * 判断是否属于快速点击
     *
     * @param view     点击的View
     * @param interval 快速点击的阈值
     * @return true:快速点击
     */
    fun isFastClick(view: View, interval: Long): Boolean {
        val key: Int = view.id
        Log.d(TAG, "isFastClick: $view $interval")
        val currentClickTime: Long = System.currentTimeMillis()
        // 如果两次点击间隔超过阈值,则不是快速点击
        if (view.getTag(key) == null || currentClickTime - (view.getTag(key) as Long) > interval) {
            // 保存最近点击时间
            view.setTag(key, currentClickTime)
            return false
        }else{
            return true
        }
​
    }
}
​
// 测试:2s内防止快速点击
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_aop)
    btnFastClick.setOnClickListener(object: View.OnClickListener{
        @FastClickView(2000)
        override fun onClick(view: View?) {
            Log.d(TAG, "onClick: click me...")
        }
    })
}
栗子二:统计方法的耗时

在进行应用启动优化时,我们需要对方法进行方法耗时的统计,常规做法是手动在方法前后里添加代码,计算耗时时间。

这种方式侵入性强,且代码重复。此时使用AOP方式就很优雅:

定义注解@TimeConsume:只要在方法上添加该注解就可以统计出方法耗时并通过日志打印出来

@Target(AnnotationTarget.FUNCTION)
@Retention(value = AnnotationRetention.RUNTIME)
annotation class TimeConsume

定义切面类TimeConsumeAspect:

切入点:任何支持TimeConsume注解的方法

切入时机:注解的方法前@Before和方法后@After

@Aspect
class TimeConsumeAspect {
​
    companion object {
        private const val TAG = "TimeConsumeAspect"
    }
​
    var startTime: Long = 0
​
    @Pointcut("execution(@com.example.aopdemo.TimeConsume * *(..))")
    fun methodTimeConsumePoint() {}
​
    @Before("methodTimeConsumePoint()")
    fun doBefore(joinPoint: JoinPoint) {
        val signature: MethodSignature = joinPoint.signature as MethodSignature
        val method = signature.method
        Log.d(TAG, "doBefore: $method")
        startTime = System.currentTimeMillis()
    }
​
    @After("methodTimeConsumePoint()")
    fun doAfter() {
        val endTime = System.currentTimeMillis()
        val consumeTime = endTime - startTime
        Log.d(TAG, "开始于${startTime},结束于$endTime, 耗时 $consumeTime ms")
    }
}

测试代码:

//test: 
@TimeConsume
override fun onStart() {
    try {
        Thread.sleep(3000)
    }catch (e: Exception){
        e.printStackTrace()
    }
    super.onStart()
}
​
@TimeConsume
override fun onResume() {
    super.onResume()
}

查看打印结果:

D/TimeConsumeAspect: doBefore: protected void com.example.aopdemo.MainActivity.onStart()
D/TimeConsumeAspect: 开始于1645418155237,结束于1645418158240, 耗时 3003 ms
D/TimeConsumeAspect: doBefore: protected void com.example.aopdemo.MainActivity.onResume()
D/TimeConsumeAspect: 开始于1645418158247,结束于1645418158263, 耗时 16 ms

demo地址

AOP在Android的其他应用

AOP在Android的应用场景还有很多,比如:

  1. APT的应用:Dagger2、ButterKnife、ARouter
  2. Javassist:热更新
UE5新手必看:3种UI定位方法实战(含蓝图配置截图) 本文为UE5新手详细解析了三种核心UI定位方法:屏幕空间、场景空间和世界空间。通过实战蓝图配置与控件操作,指导开发者如何根据HUD、角色血条、3D物体标记等不同应用场景,正确选择并配置UI的定位方式,以实现清晰的信息传递与沉浸式体验。 阅读详情

相关推荐

西门子S7-1200模拟量的使用

模块类型核心参数输入信号处理输出信号配置转换原理数值范围TIA Portal配置编程要点 转换公式: 输出模拟量: 五、校准与线性化 硬件校准非线性补偿抗干扰措施数字滤波温度控制压力监控流量调节信号异常精度不足实践操作参考文档项目案例借鉴博客

weixin_51020122的博客 4774

安装xoops的报错解决方案

转载自:http://hi.baidu.com/moonknight/blog/item/63ebd62a18e20227d42af1bc.html 注:正好自己安装XOOPS 2.3.3中文版出现这几个问题,都给解决了,谢谢这位朋友的文章。 另外,我在安装xoops2.3.3时,因为数据库版本是mysql5.5.8,发现安装时能够创建数据库,但创建不了数据表:后来直接在mysql5...

weixin_30267785的博客 279

高效IT运维报告编写指南:实战经验与模板分享

本文提供了一份全面的IT运维报告编写指南,涵盖实战经验与实用模板分享。文章详细解析了高效运维报告的核心要素,包括结构设计、数据收集自动化和可视化技巧,并提供了月度报告和故障分析报告模板。通过自动化工具和写作技巧,帮助团队提升报告质量,支持决策和问题追踪。

u5v6w7的博客 928

XAOP:轻量级AOP(Android)应用框架

XAOP:轻量级AOP(Android)应用框架 项目基础介绍 XAOP 是一个轻量级的 AOP(面向切面编程)应用框架,专为 Android 应用开发设计。该项目由 优快云 公司开发,旨在简化 Android 开发中的常见需求,如权限请求、日志记录、内存和磁盘缓存等,通过切面编程的方式,将这些需求从业务代码中分离出来,提高代码的清晰度和可维护性。 编程语言 项目主要使用 Java 和 Kotl...

gitblog_00783的博客 873

从MFCC到GMM:手把手教你用Python实现说话人识别(附完整代码)

本文详细介绍了如何使用Python实现说话人识别系统,从MFCC特征提取到GMM模型训练,涵盖完整的技术流程和代码示例。通过梅尔频率倒谱系数(MFCC)和高斯混合模型(GMM)的结合,构建高效的说话人识别系统,适用于身份认证和智能交互场景。文章还探讨了从传统方法到深度学习的进阶话题,如i-vector和x-vector技术。

o1p2q3r的博客 200

PRIDE数据库20年:2025更新

PRoteomics IDEntifications (PRIDE)数据库(https://www.ebi.ac.uk/pride/)是全球领先的基于质谱(MS)的蛋白质组学数据存储库,也是ProteomeXchange联盟的创始成员之一。本文总结了过去3年中PRIDE资源及相关工具的发展情况。提交到PRIDE存档的数据集数量平均每月达到约534个。主要得益于基础设施的持续改进,如用于超大数据集的新文件传输协议(Globus)、新的数据重新提交流程以及自动数据集验证过程。

多组・学・多组学 2064

JAVA面试题

https://blog.youkuaiyun.com/u011279240/article/details/80532555 几个大厂的面试题目目录: java基础(40题) 多线程(51题) 设计模式(8点) JVM(12题) 数据结构与算法(17题) 数据库(22题) Spring (13题) Netty(7大题) 缓存(9题) 技术框架(8题) 技术深度(12题) 分布式(33题) 系统架构(18题)...

三番鱼 2919

基于cat12和SPM12进行VBM&SBM数据分析笔记1——数据预处理

基于cat12数据分析基础教程笔记 今年是小编步入研究生生活的第一年,研究方向待定,但主要以磁共振成像为主,以后会不断地总结这方面的知识,涉及MRI扫描,数据分析基础方法理论,软件操作教程,文献阅读笔记总结等等,用来记录我的研究生三年学习过程。编写尽量简洁明了,通俗易懂,本就是小白,也能体会小白的痛。不过这也要谢谢一个人手动@小白(网名),是他教我要把自己所学的写下来,讲出来才能真正的做到输入和输出,查漏补缺。而cat12软件操作是我面临的第一个数据分析的训练,写的可能也不会非常到位,还望各位专业人士指出改

Sophia2023的博客 4万+

iOS —— XMPP 详解

iOS - XMPP 的使用 转载https://www.cnblogs.com/QianChia/p/6411914.html 1、XMPP XMPP 是一个基于 Socket 通信的即时通讯的协议,它规范了即时通信在网络上数据的传输格式,比如登录,获取好友列表等等的格式。XMPP 在网络传输的数据是 XML 格式。 开发架构: iOS 框架:XMPPFra...

SHTLoveXX的专栏 1687

《第二十二篇》Cross-Attention:注意力机制详解-代码实现和公式详解《二》

本文详细介绍了Cross-Attention的原理、公式和实现。Cross-Attention用于Transformer解码器和Encoder-Decoder结构,通过查询向量(Q)与键、值向量(K、V)的交互实现序列对齐。核心公式为softmax(QK^T/√d_k)V,其中Q来自Decoder,K、V来自Encoder。文章还给出了多头注意力机制公式和PyTorch实现代码,包括投影计算、注意力分数计算和输出处理。代码示例展示了如何构建一个完整的Cross-Attention模块,并演示了其在解码器查询

guoguozgw的博客 2213

【制作100个unity游戏之30】使用unity实现一款2d俯视角RPG战斗游戏,主要使用InputSystem+有限状态机+A*寻路实现(完结,附带项目源码)

【制作100个unity游戏之30】使用unity实现一款2d俯视角RPG战斗游戏,主要使用InputSystem+有限状态机+A*寻路实现

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 4656

Xoops一览

Xoops 是什么XOOPS 是一个开放源码的web 内容和门户管理程序,安全、稳定、可靠,群组权限管理完善,对多字节语言特别是中文支持完美,适合于从小型到大型的动态交互社区、公司门户、企业内部网、个人/群组网络日志等的建设。...

smartrice的专栏 419

基于matlab的图像HOG特征提取算法仿真

方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。它通过计算和统计图像局部区域的梯度方向直方图来构成特征。Hog特征结合SVM分类器已经被广泛应用于图像识别中,尤其在行人检测中获得了极大的成功。需要提醒的是,HOG+SVM进行行人检测的方法是法国研究人员Dalal在2005的CVPR上提出的,而如今虽然有很多行人检测算法不断提出,但基本都是以HOG+SVM的思路为主。

平时工作较为繁忙,私信消息一般晚上回复,谢谢大家~~ 730

Android 工程师必知必会的“ AOP知识 ”

AOP 官方定义 AOP 译为(面向切面编程) 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程; 通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术;AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率 AOP 术语 横切关注点 对哪些方法进行拦截,拦截后怎

m0_70748458的博客 835

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Android AOP概述(1),安卓开发指南

System.out.println(“用户未登录”);System.out.println(“跳转到登录页”);经过这样封装之后,检查登录跳转登录页的逻辑作为横切关注点就和业务主体进行了分离。当有新的需求需要登录检查时,我们只需要通过LoginCheckHandler生成新的代理对象即可。

2401_84152719的博客 515

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Android AOP概述

网上很多人在介绍AOP时都这样说:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。个人认为这句话是错误。AOP和OOP一样,是一种程序设计思想,而非技术手段。程序设计有六大原则,其中第一原则就是单一职责原则。意思就是一个类只负责一件事情。这与OOP的封装特性相得益彰。在这个条件下,我们的程序会被分散到不同的类、不同的方法中去。这样做的好处是降低了类的复杂性,提高了程序的可维护性。但是同时,它也使代码变得啰嗦了。

2401_84132544的博客 956

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

2024年最全Android工程师必备知识,2024Android面试,2024年最新嵌入式工程师面试都问什么

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。还有。

2401_84544531的博客 710

Android面向切面编程(AOP)

一、简述 1、AOP的概念 如果你用java做过后台开发,那么你一定知道AOP这个概念。如果不知道也无妨,套用百度百科的介绍,也能让你明白这玩意是干什么的: AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降

黄宏的博客 299

Android AOP概述(1)

【Android 详细知识点思维脑图(技能树)】其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

2301_76352508的博客 1044

Android面向切面编程(AOP)——这篇文章就够了,通俗易懂

一、简述 1、AOP的概念 如果你用java做过后台开发,那么你一定知道AOP这个概念。如果不知道也无妨,套用百度百科的介绍,也能让你明白这玩意是干什么的: AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内...

Java和Android架构 1103

AOP面向切面编程,Android开发手册

同时在该文件中加入AspectJX模块3.AOP 偷懒式网络访问/***/@CheckNet/***/@CheckNet上面我只是加了1个注解,就实现了执行方法前的网络监测(其实还需要写下面的SectionNetAspect)。这个注解是我自己写的,如下:这里,解释一下,上面的Retention,首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;

2401_84150191的博客 1012

Android最傻瓜式的AOP框架,赶紧收藏备战金三银四

首先是感觉自己的基础还是不够吧,大厂好像都喜欢问这些底层原理。之前的准备只涉及了Java、Android、计网、数据结构与算法这些方面,面对面试官对其他基础课程的考察显得捉襟见肘。下一步还是要查漏补缺,进行针对性复习。最后的最后,那套资料这次一定要全部看完,是真的太全面了,各个知识点都涵盖了,几乎我面试遇到的所有问题的知识点这里面都有!希望大家不要犯和我一样的错误呀!!!一定要看完!要查漏补缺,进行针对性复习。

m0_60575487的博客 767

Android面向切面编程(AOP)

转自:https://www.jianshu.com/p/aa1112dbebc7 一、简述 1、AOP的概念 如果你用java做过后台开发,那么你一定知道AOP这个概念。如果不知道也无妨,套用百度百科的介绍,也能让你明白这玩意是干什么的: AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AO...

厚德出品,必是精品 311
上一篇: Android 高工对自己过往面试的汇总总结~
下一篇: 校招三面阿里Android岗过后,委婉拒收offer
懂你的大海
博客等级 码龄6年 9049粉丝 1381原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值