AOP之使用AspectJ案例
来源:互联网 发布:蓝牙耳机控制软件 编辑:程序博客网 时间:2024/06/13 23:53
这篇文章作为自己学习笔记:
国内翻译教程
AOP翻译过来 “面向切面”。如果非要用一句话来理解的话:”在程序编译或者运行时,在代码某处切入另一段代码”。
AOP的出现是弥补OOM的不足。
作者:知乎用户
链接:https://www.zhihu.com/question/24863332/answer/48376158
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ,我们知道,面向对象的特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中往往称为职责分配。实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。 但是人们也发现,在分散代码的同时,也增加了代码的重复性。什么意思呢?比如说,我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象的设计让类与类之间无法联系,而不能将这些重复的代码统一起来。 也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入代码呢?这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。 一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。这样看来,AOP其实只是OOP的补充而已。OOP从横向上区分出一个个的类来,而AOP则从纵向上向对象中加入特定的代码。有了AOP,OOP变得立体了。如果加上时间维度,AOP使OOP由原来的二维变为三维了,由平面变成立体了。从技术上来说,AOP基本上是通过代理机制实现的。 AOP在编程历史上可以说是里程碑式的,对OOP编程是一种十分有益的补充
举个例子:
我们需要做用户行为统计,当用户点击个界面的按钮 ,会触发onClick或者onClick2
(界面有多个按钮 一个按钮对应一个onclick方法)
public void onClick(View view) { //记录当前用户点击了某个view从而触发onClick方法 long l = System.currentTimeMillis(); /** * 假设 这里发送 统计到 后台 * * */// send(XXXXXX); Log.e("fmy","我点了按钮"); } public void onClic2k(View view) { //记录当前用户点击了某个view从而触发onClick2方法 long l = System.currentTimeMillis(); /** * 假设 这里发送 统计到 后台 * * */// send(XXXXXX); Log.e("fmy","我点了按钮"); }
很显然两个方法有重复的代码段:
//记录当前用户点击了某个view从而触发onClick方法 long l = System.currentTimeMillis(); /** * 假设 这里发送 统计到 后台 * * */// send(XXXXXX);
这时候我们会把这个方法 封装到一个类中,然后调用类方法即可如下
public void onClick(View view) { //封装统计方法 A.statistics(); Log.e("fmy","我点了按钮"); } public void onClic2k(View view) { A.statistics(); Log.e("fmy","我点了按钮"); }
可是这样A类的方法和onClick产生了耦合,与我们提倡的低耦合高内聚相反。
这时候我们就孕育而生了AOP思想。在代码运行时或者编译时插入代码
这里使用AspectJ在Android下完成一个Demo程序。
使用环境:
- IDE:Android Studio
- 目的:利用AspectJ完成用户行为统计
创建一个项目:
包含两个moudle。
- acepctlibrary –>>利用AspectJ写的一个行为统计
- app –>>测试acepctlibrary类库
acepctlibrary:
一个Android Library
修改build.gradle
import com.android.build.gradle.LibraryPluginimport org.aspectj.bridge.IMessageimport org.aspectj.bridge.MessageHandlerimport org.aspectj.tools.ajc.Mainbuildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:2.3.3' classpath 'org.aspectj:aspectjtools:1.8.1' }}apply plugin: 'com.android.library'repositories { mavenCentral()}dependencies { compile 'org.aspectj:aspectjrt:1.8.1' compile files('libs/aspectjrt.jar')}android { compileSdkVersion 25 buildToolsVersion '25.0.3' lintOptions { abortOnError false }}android.libraryVariants.all { variant -> LibraryPlugin plugin = project.plugins.getPlugin(LibraryPlugin) JavaCompile javaCompile = variant.javaCompile javaCompile.doLast { String[] args = ["-showWeaveInfo", "-1.5", "-inpath", javaCompile.destinationDir.toString(), "-aspectpath", javaCompile.classpath.asPath, "-d", javaCompile.destinationDir.toString(), "-classpath", javaCompile.classpath.asPath, "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)] MessageHandler handler = new MessageHandler(true); new Main().run(args, handler) def log = project.logger 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: case IMessage.INFO: log.info message.message, message.thrown break; case IMessage.DEBUG: log.debug message.message, message.thrown break; } } }}
编写一个注解:
package com.example.acepctlibrary;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * Created by fmy on 2017/9/12. */@Retention(RetentionPolicy.CLASS)@Target(ElementType.METHOD)public @interface Statistics { String name () ; int type ();}
处理器:
package com.example.acepctlibrary;import android.util.Log;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import java.text.SimpleDateFormat;import java.util.Date;/** * Created by fmy on 2017/9/12. */@Aspectpublic class TraceAspect { /** * 设置切入点规则。可以指定返回值 形参等 如果*则表示 所有被次注解的都会被作为切入 * */ private static final String KEY = "execution(@com.example.acepctlibrary.Statistics * *(..))"; /** * 设置切入点规则 只要是被Statistics注解修饰的都会被作为切入点 */ @Pointcut(KEY) public void annoBehavior() { } private static final String TAG = "fmy"; SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // @Around传入切入点 就是方法名 @Around("annoBehavior()") public Object dealPoint(ProceedingJoinPoint point) throws Throwable{ //方法执行前 MethodSignature methodSignature= (MethodSignature) point.getSignature(); Statistics behaviorTrace=methodSignature.getMethod().getAnnotation(Statistics.class); String contentType=behaviorTrace.name(); int type=behaviorTrace.type(); Log.i(TAG,contentType+"使用时间: "+simpleDateFormat.format(new Date())); long beagin=System.currentTimeMillis(); //方法执行时 Object object=null; try { object=point.proceed(); }catch (Exception e) { } //方法执行完成 Log.i(TAG,"消耗时间: "+(System.currentTimeMillis()-beagin)+"ms"); return object; }}
app
一个测试上面library
注意这里也要修改buil.gradl:
import org.aspectj.bridge.IMessageimport org.aspectj.bridge.MessageHandlerimport org.aspectj.tools.ajc.Mainapply plugin: 'com.android.application'buildscript { repositories { mavenCentral() } dependencies { classpath 'org.aspectj:aspectjtools:1.8.9' classpath 'org.aspectj:aspectjweaver:1.8.9' }}android { compileSdkVersion 25 buildToolsVersion '25.0.3' defaultConfig { applicationId "com.example.fmy.aspectdemo" minSdkVersion 15 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}final def log = project.loggerfinal def variants = project.android.applicationVariantsvariants.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; } } }}dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.+' compile 'com.android.support.constraint:constraint-layout:1.0.2' testCompile 'junit:junit:4.12' compile project(':acepctlibrary')}
package com.example.fmy.aspectdemo;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import com.example.acepctlibrary.Statistics;public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Statistics(name="",type=1) public void onClick(View view) { Log.e("fmy","我点了按钮"); }}
GIT源码附上
- AOP之使用AspectJ案例
- AOP之Aspectj案例
- Spring aop之使用AspectJ
- spring学习之使用AspectJ实现AOP
- spring之基于aspectj注解aop使用
- Spring 之AOP 使用@AspectJ注解方式
- AOP之基于AspectJ注解总结与案例
- AOP之基于AspectJ注解总结与案例
- AOP之基于AspectJ注解总结与案例
- Java AOP 之 AspectJ
- Java AOP 之 AspectJ
- Spring AOP之AspectJ
- Spring AOP之AspectJ
- AOP之AspectJ
- Aop之AspectJ
- AOP笔记之AspectJ
- Spring-AOP 使用@AspectJ
- Spring AOP之AspectJ的XML方式使用
- hdu 6153 A Secret(kmp||扩展kmp)
- Vim 常用操作命令整理
- python之正则表达式的用法总结
- Android中ConvenientBanner的使用--获取本地图片 --(实现效果是自动轮播图片)
- validate和bootstrap的使用
- AOP之使用AspectJ案例
- skynet 常用lua函数汇总
- ERDAS大气校正
- RUP,极限编程与敏捷过程的概念
- mybatis之sql片段和一对多等配置
- MMC子系统调用过程浅析(Card层)
- Bitmap 解析大图时 OOM 解决办法
- 2016 ACM-ICPC Asia Regional B – Help the Princess!(bfs)
- python 内存二进制读取图片