Copyright statement: This article is an original article by the blogger and may not be reproduced without the blogger's permission.
Reprint please indicate the source: http://www.cnblogs.com/cavalier-/p/8888459.html
What is AOP
AOP is the abbreviation of Aspect Oriented Programming, that is, aspect-oriented programming. Unlike the object-oriented OOP programming that is usually encountered, OOP is the modularization of functions, and AOP is the unified treatment of problems of the same type. For example, log burying, performance monitoring, dynamic permission control, etc.
AspectJ
AspectJ is actually the practice of AOP programming. There are still many AOP implementations, such as ASMDex, but the author chooses AspectJ.
Using AspectJ in an Android project
If you use native AspectJ to configure in the project, it will be very troublesome. There is an open source SDK gradle_plugin_android_aspectjx on GitHub based on gradle configuration.
Access instructions
Please check the access configuration process in the open source project by yourself
Introduction to Join Points in AspectJ
Join Points are a key concept in AspectJ. Join Points can be regarded as an execution point when the program is running. For example, a function call can be regarded as a Join Points, which is equivalent to a code entry point. But in AspectJ, only the following execution points are considered Join Points:
Join Points | illustrate | example |
---|---|---|
method call | function call | For example, calling Log.e(), which is a Join Point |
method execution | function execution | For example, inside the execution of Log.e() is a Join Points. Note that here is the inside of the function |
constructor call | constructor call | Similar to method call |
constructor execution | constructor execution | Similar to method execution |
field get | get a variable | For example, read the DemoActivity.debug member |
field set | set a variable | For example, set the DemoActivity.debug member |
pre-initialization | Some of the work that Object does in the constructor. | - |
initialization | The work that Object does in the constructor. | - |
static initialization | class initialization | Such as class static{} |
handler | exception handling | For example, in try catch, the execution in the corresponding catch |
advice execution | This is the content of AspectJ | - |
Introducing Pointcuts
A program will have multiple Join Points, even if the same function is divided into call and execution types of Join Points, but not all Join Points are what we care about, Pointcuts is to provide a way for developers to choose value The desired JoinPoints method.
Advice
Advice is the way in which the code we insert can be inserted, including Before, After, and Around.
Here's an example:
@Before(“execution(* android.app.Activity.on**(..)))”)
public void onActivityMethodBefore(JoinPoint joinPoint) throws Throwable{
}
This will be divided into several parts, let's look at them in turn:
- @Before: Advice, which is the specific insertion point
- execution: handle the type of Join Point, such as call, execution
(* android.app.Activity.on**(..))
: This is the most important expression. The first one*
represents the return value, which*
means that the return value is of any type. The latter is a typical package name path, which can*
contain for wildcarding, and*
there is no difference between several. At the same time&&、||、!
, conditions can be combined here. () represents the parameters of this method, you can specify the type, such as android.os.Bundle, or (..) to represent any type and any number of parameters.- public void onActivityMehodBefore: The code that actually cuts in.
Before and After are actually well understood, that is, insert code before and after Pointcuts, then Android, literally, inserting code before and after the method, it includes all the functions of Before and After, code show as below:
@(“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);
}
In the above code, proceedingJoinPoint.proceed() represents the execution of the original method, before and after, various logical processing can be performed.
Custom Pointcuts
Custom Pointcuts allow us to cut into one or more specified entry points more precisely.
First we need to define an annotation class
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface DebugTrace {
}
Add this annotation where you need to insert code, for example in MainActivity:
public class MainActivity extends AppCompatActivity{
final String TAG = MainActivity.class.getSimpleName();
@Override
protedcted void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
logTest();
}
@DebugTrace
public void logTest(){
Log.e(TAG,”log test");
}
}
Finally create the cut-in code
@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);
}
Call
In the pointcut expression of AspectJ, we have used execution before, and there is actually a type - call, so what is the difference between these two syntaxes? For call:
Call (Before)
Pointcut{
Pointcut Method
}
Call (After)
For Execution:
Pointcut{
execution (Before)
Pointcut Method
execution (After)
}
Withincode
This syntax is usually used to filter some pointcut conditions for more precise entry control, as follows:
public class MainActivity extends AppCompatActivity{
final String TAG = MainActivity.class.getSimpleName();
@Orveride
protected void onCreate(Bundle savedInstanceState){
super.onCreate(saveInstanceState);
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(), and aspectJ3() all call the aspectJTest method, but only want to insert code when aspectJ2 calls aspectJTest. At this time, you need to use the combination of Pointcut and withcode to accurately locate the entry point.
@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();
}
execution syntax
execution() is the most commonly used pointcut function, and its syntax is as follows:
For example, the following syntax:
@Around(“execution(* *..MainActivity+.on*(..))")
The entire expression can be divided into five parts:
- execution() is the expression body
- The first
*
sign represents the return type, and the * sign represents all types. - The package name indicates the package name that needs to be intercepted, and *. is used here to match all package names.
- The second * sign indicates the class name, followed by .MainActivity refers to the specific class name MainActivity.
*(..)
The last asterisk represents the method name, +. represents the specific function name, the*
sign wildcard includes the parameters of the method in brackets, and the two dots represent any parameters.
errors encountered
- The following errors can be solved using gradle2.2.3, which is caused by not yet adapting to gradle3.0
Error:Execution failed for task ':app:transformClassesWithDexBuilderForDebug'.
> Unexpected scopes found in folder '/Users/ram/WorkSpace/AndroidWorkSpace/MyDemo/app/build/intermediates/transforms/AspectTransform/debug'. Required: PROJECT, SUB_PROJECTS, EXTERNAL_LIBRARIES. Found: EXTERNAL_LIBRARIES, PROJECT, PROJECT_LOCAL_DEPS, SUB_PROJECTS, SUB_PROJECTS_LOCAL_DEPS