源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

AspectJ的基本用法

  • 时间:2021-10-03 01:27 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:AspectJ的基本用法
AOP虽然是方法论,但就好像OOP中的Java一样,一些先行者也开发了一套语言来支持AOP。目前用得比较火的就是AspectJ了,它是一种几乎和Java完全一样的语言,而且完全兼容Java(AspectJ应该就是一种扩展Java,但它不是像Groovy[1]那样的拓展。)。当然,除了使用AspectJ特殊的语言外,AspectJ还支持原生的Java,只要加上对应的AspectJ注解就好。所以,使用AspectJ有两种方法: 完全使用AspectJ的语言。这语言一点也不难,和Java几乎一样,也能在AspectJ中调用Java的任何类库。AspectJ只是多了一些关键词罢了。 或者使用纯Java语言开发,然后使用AspectJ注解,简称*@AspectJ*。 AspectJ的配置可以参考另一篇文章[url=http://www.1sucai.cn/article/110560.htm]Android中使用AspectJ详解[/url] [b]Join Points介绍[/b] Join Points是AspectJ中的一个关键概念。Join Points可以看作是程序运行时的一个执行点,比如:一个函数的调用可以看作是个Join Points,如Log.e()这个函数,e()可以看作是个Join Points,而调运e()的函数也可以认为是一个Join Points;设置一个变量,或者读取一个变量也可以是个Join Points;for循环也可以看作是Join Points。 理论上说,一个程序中很多地方都可以被看做是Join Points,但是AspectJ中,只有下面所示的几种执行点被认为是Join Points:
[b]Join Points[/b] [b]说明[/b] [b]示例[/b]
[b]method call[/b] 函数调用 比如调用Log.e(),这是一处JPoint
[b]method execution[/b] 函数执行 比如Log.e()的执行内部,是一处Join Points。注意它和method call的区别。method call是调用某个函数的地方。而execution是某个函数执行的内部。
[b]constructor call[/b] 构造函数调用 和method call类似
[b]constructor execution[/b] 构造函数执行 和method execution类似
[b]field get[/b] 获取某个变量 比如读取DemoActivity.debug成员
[b]field set[/b] 设置某个变量 比如设置DemoActivity.debug成员
[b]pre-initialization[/b] Object在构造函数中做得一些工作。
[b]initialization[/b] Object在构造函数中做得工作
[b]static initialization[/b] 类初始化 比如类的static{}
[b]handler[/b] 异常处理 比如try catch(xxx)中,对应catch内的执行
[b]advice execution[/b] 这个是AspectJ的内容,稍后再说
这里列出了AspectJ所认可的JoinPoints的类型。实际上,也就是你想把新的代码插在程序的哪个地方,是插在构造方法中,还是插在某个方法调用前,或者是插在某个方法中,这个地方就是Join Points,当然,不是所有地方都能给你插的,只有能插的地方,才叫Join Points。 [b]Pointcuts介绍[/b] 一个程序会有多个Join Points,即使同一个函数,也还分为call和execution类型的Join Points,但并不是所有的Join Points都是我们关心的,Pointcuts就是提供一种使得开发者能够选择自己需要的JoinPoints的方法。 [b]Advice[/b] Advice就是我们插入的代码以何种方式插入,有Before还有After、Around。 看个例子
@Before("execution(* android.app.Activity.on**(..))")
public void onActivityMethodBefore(JoinPoint joinPoint) throws Throwable {
}
这里会分成几个部分,我们依次来看: [list] [*]@Before:Advice,也就是具体的插入点[/*] [*]execution:处理Join Point的类型,例如call、execution[/*] [*](* android.app.Activity.on**(..)):这个是最重要的表达式,第一个*表示返回值,*表示返回值为任意类型,后面这个就是典型的包名路径,其中可以包含 * 来进行通配,几个 * 没区别。同时,这里可以通过&&、||、!来进行条件组合。()代表这个方法的参数,你可以指定类型,例如android.os.Bundle,或者(..)这样来代表任意类型、任意个数的参数。[/*] [*]public void onActivityMethodBefore:实际切入的代码。[/*] [/list] Before和After其实还是很好理解的,也就是在Pointcuts之前和之后,插入代码,那么Around呢,从字面含义上来讲,也就是在方法前后各插入代码,是的,他包含了Before和After的全部功能,代码如下:
@Around("execution(* com.xys.aspectjxdemo.MainActivity.testAOP())")
public void onActivityMethodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
 String key = proceedingJoinPoint.getSignature().toString();
 Log.d(TAG, "onActivityMethodAroundFirst: " + key);
 proceedingJoinPoint.proceed();
 Log.d(TAG, "onActivityMethodAroundSecond: " + key);
}
其中,proceedingJoinPoint.proceed()代表执行原始的方法,在这之前、之后,都可以进行各种逻辑处理。 [b]自定义Pointcuts[/b] 自定义Pointcuts可以让我们更加精确的切入一个或多个指定的切入点。 首先我们要定义一个注解类
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface DebugTrace {
}
在需要插入代码的地方加入这个注解。如在MainActivity中加入,
public class MainActivity extends AppCompatActivity {
 final String TAG = MainActivity.class.getSimpleName();

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 logTest();
 }

 @DebugTrace
 public void logTest() {
 Log.e(TAG, "log test");
 }
}
最后,创建切入代码
@Pointcut("execution(@com.kun.aspectjtest.aspect.DebugTrace * *..*.*(..))")
public void DebugTraceMethod() {}

@Before("DebugTraceMethod()")
public void beforeDebugTraceMethod(JoinPoint joinPoint) throws Throwable {
 String key = joinPoint.getSignature().toString();
 Log.e(TAG, "beforeDebugTraceMethod: " + key);
}
log如下 [img]http://files.jb51.net/file_images/article/201704/201704070927131.jpg[/img] 在AspectJ的切入点表达式中,我们前面都是使用的execution,实际上,还有一种类型——call,那么这两种语法有什么区别呢,对于Call来说:
Call(Before)
Pointcut{
 Pointcut Method
}
Call(After)
对于Execution来说:
Pointcut{
 execution(Before)
 Pointcut Method
 execution(After)
}
[b]withincode[/b] 这个语法通常来进行一些切入点条件的过滤,作更加精确的切入控制。如下
public class MainActivity extends AppCompatActivity {
 final String TAG = MainActivity.class.getSimpleName();
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 aspectJ1();
 aspectJ2();
 aspectJ3();
 }
 public void aspectJTest() {
 Log.e(TAG, "execute aspectJTest");
 }
 public void aspectJ1(){
 aspectJTest();
 }
 public void aspectJ2(){
 aspectJTest();
 }
 public void aspectJ3(){
 aspectJTest();
 }
}
aspectJ1(),aspectJ2(),aspectJ3()都调用了aspectJTest方法,但只想在aspectJ2调用aspectJTest时插入代码,这个时候就需要使用到Pointcut和withincode组合的方式,来精确定位切入点。
@Pointcut("(call(* *..aspectJTest()))&&withincode(* *..aspectJ2())")
public void invokeAspectJTestInAspectJ2() {
}

@Before("invokeAspectJTestInAspectJ2()")
public void beforeInvokeaspectJTestInAspectJ2(JoinPoint joinPoint) throws Throwable {
 Log.e(TAG, "method:" + getMethodName(joinPoint).getName());
}
private MethodSignature getMethodName(JoinPoint joinPoint) {
 if (joinPoint == null) return null;
 return (MethodSignature) joinPoint.getSignature();
}
log如下
04-02 23:44:40.681 12107-12107/ E/MainActivity: execute aspectJTest
04-02 23:44:40.681 12107-12107/ E/AspectTest: method:aspectJTest
04-02 23:44:40.681 12107-12107/ E/MainActivity: execute aspectJTest
04-02 23:44:40.681 12107-12107/ E/MainActivity: execute aspectJTest
以上就是Aspecj的基本使用方法,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持编程素材网!
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部