In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)05/31 Report--
Most people do not understand the knowledge points of this article "how to achieve aspect-oriented programming in Android", so the editor summarizes the following content, detailed content, clear steps, and has a certain reference value. I hope you can get something after reading this article. Let's take a look at this "how to achieve aspect-oriented programming in Android" article.
1. The concept of AOP
If you have done background development with java, then you must know the concept of AOP. It doesn't matter if you don't know. Using the introduction of Baidu encyclopedia can also let you understand what this thing is for:
AOP is the abbreviation of Aspect Oriented Programming, which means: a technology for aspect-oriented programming, which realizes the unified maintenance of program functions through precompilation and run-time dynamic agents. AOP is the continuation of OOP, is a hot spot in software development, is also an important content of Spring framework, and is a derivative paradigm of functional programming. Each part of the business logic can be isolated by using AOP, which reduces the coupling between the various parts of the business logic, improves the reusability of the program, and improves the efficiency of development at the same time.
2. Project scenario
In the process of project development, there may be such a requirement that we need to log after the execution of the method (which is more common in background development), or calculate the execution time of this method. Without using AOP, we can call another special logging method at the end of the method, or obtain the time at the beginning and end of the method body. Then the time spent on the execution of the entire method is calculated by calculating the time difference, which can also meet the requirements. What if there is more than one way to play like this? Do you write the same code for each method? What if the post-processing logic changes? In the end, the boss said that we had to delete this function one by one.
Obviously, this is impossible, we are not only code porters, we are also thoughtful software development engineers. So low absolutely does not do, this kind of problem we can use AOP to solve, isn't it to insert a piece of code before and after the method? AOP will do it in minutes.
3. The implementation of AOP.
Note that AOP is just a concept, and there are several ways to implement it (tools and libraries):
AspectJ: a seamless extension of the JavaTM language for aspect programming (for Android).
Javassist for Android: an Android platform portable version of Javassist, a well-known java class library for bytecode manipulation.
DexMaker: on the Dalvik virtual machine, the Java API that generates code at compile time or run time.
ASMDEX: an ASM-like bytecode operation library that runs on the Android platform and manipulates Dex bytecode.
The protagonist of this article is AspectJ. Let's take a look at how AspectJ-style AOP can be used in Android development.
II. The introduction of AspectJ
The introduction of eclipse and Android Studio is not the same, this article only introduces how to introduce Android Studio to AspectJ,eclipse, please go to Baidu. Android Studio needs to be introduced in the build.gradle file of the app module, which is divided into three steps:
1) add core dependencies
Dependencies {... Compile 'org.aspectj:aspectjrt:1.8.9'}
2) write gradle compilation script
Buildscript {repositories {mavenCentral ()} dependencies {classpath 'org.aspectj:aspectjtools:1.8.9' classpath' org.aspectj:aspectjweaver:1.8.9'}}
AspectJ relies on maven repositories.
3) add gradle task
Dependencies {.} / / posted the useless code above to illustrate that the following task code is at the same level as dependencies import org.aspectj.bridge.IMessageimport org.aspectj.bridge.MessageHandlerimport org.aspectj.tools.ajc.Mainfinal 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;}
Just paste it to the end of the build.gradle file and don't nest it in other instructions.
III. Basic knowledge of AOP
Before using AspectJ, you still need to introduce the basic knowledge of AOP, which can be skipped by familiar viewers.
1. AOP terminology
Notification, enhanced processing (Advice): the functionality you want, that is, logging, time-consuming computing, etc.
JoinPoint: there are many places that allow you to notify (Advice), basically before and after every method (both are fine), or when an exception is thrown can be a join point (spring only supports method join points). AspectJ also allows you to do either constructor or property injection, but you don't normally do this, just remember that there are join points before and after the method.
Pointcut (Pointcut): define pointcuts on the basis of the join points mentioned above. There are 15 methods in your class, so there are more than a dozen join points, right? but you don't want to use notifications in all method attachments (using weaving, we'll talk about it below). You just want a few of them to do something before, after, or when you throw an exception. Then define these methods with pointcuts, let pointcuts filter join points, and select the methods you want.
Facet (Aspect): an aspect is a combination of notification and pointcut. Now found out, there is no connection to anything, the connection point is to make it easy for you to understand the tangent point, just understand this concept. The notification specifies what to do and when to do it (you can know when through AOP annotations such as before,after,around), while the pointcut indicates where to do it (specify which method), which is a complete aspect definition.
Weaving the process of applying a section to a target object to create a new proxy object.
Introduction allows us to add new method properties to existing classes. Doesn't this mean applying the aspect (that is, the new method property: notification defined) to the target class?
The target class mentioned in the introduction of target, that is, the object to be notified, that is, the real business logic, can be woven into the aspect by us without our knowledge. Second, I focus on the logic of the business itself.
How the proxy implements the whole AOP mechanism is through the proxy, which will be explained in detail in a moment.
Target object-the original Java component of the project.
AOP proxy-java objects are generated by the AOP framework.
AOP proxy method = advice + method of the target object.
2. Comments and use of AOP
@ Aspect: declare aspects, mark classes
@ Pointcut (tangent expression): define tangent point, mark method
@ Before (pointcut expression): pre-notification, executed before pointcut
@ Around (pointcut expression): surround the notification and execute before and after the pointcut
@ After (pointcut expression): post notification, executed after pointcut
@ AfterReturning (pointcut expression): returns the notification, and executes after the pointcut method returns the result
@ AfterThrowing (pointcut expression): exception notification, which is executed when the pointcut throws an exception
@ Pointcut, @ Before, @ Around, @ After, @ AfterReturning, @ AfterThrowing need to be used in aspect classes, that is, in classes that use @ Aspect.
1) what is the tangent expression?
This is the pointcut expression: execution (* com.lqr..*.* (..)). The tangent expression consists of the following:
Execution (?)
All items are optional except for the return type pattern, the method name pattern, and the parameter pattern.
Modifier patterns refer to public, private, protected, and exception patterns refer to NullPointException, and so on.
The understanding of pointcut expressions is not the focus of this article. Here are a few examples to illustrate:
@ Before ("execution (public * * (..)") public void before (JoinPoint point) {System.out.println ("CSDN_LQR");}
Match all public methods and print "CSDN_LQR" before the method executes.
@ Around ("execution (* * to (..)") public void around (ProceedingJoinPoint joinPoint) {System.out.println ("CSDN"); joinPoint.proceed (); System.out.println ("LQR");}
Match all methods that end with "to", print "CSDN" before method execution, and print "LQR" after method execution.
@ After ("execution (* com.lqr..*to (..)") public void after (JoinPoint point) {System.out.println ("CSDN_LQR");}
Match the methods that end with "to" in the com.lqr package and its subpackages, and print "CSDN_LQR" after the method is executed.
@ AfterReturning ("execution (int com.lqr.* (..)") public void afterReturning (JoinPoint point, Object returnValue) {System.out.println ("CSDN_LQR");}
Match all methods under the com.lqr package whose return type is int, and print "CSDN_LQR" after the method returns the result.
@ AfterThrowing (value = "execution (* com.lqr..* (..)", throwing = "ex") public void afterThrowing (Throwable ex) {System.out.println ("ex =" + ex.getMessage ());}
Match all the methods in the com.lqr package and its subpackages, and print "ex = error message" when the method throws an exception.
2) use of @ Pointcut
@ Pointcut is specifically used to define pointcuts so that pointcut expressions can be reused.
You may need to do some actions before the pointcut executes and when the pointcut reports an exception (such as logging when an error occurs), you can do this:
@ Before ("execution (* com.lqr..* (..)") public void before (JoinPoint point) {System.out.println ("CSDN_LQR");} @ AfterThrowing (value = "execution (* com.lqr..* (..)", throwing = "ex") public void afterThrowing (Throwable ex) {System.out.println ("logging");}
As you can see, the expression is the same, so how do you reuse it? This requires the @ Pointcut annotation, which is annotated on an empty method, such as:
@ Pointcut ("execution (* com.lqr..* (..)") public void pointcut () {}
At this point, "pointcut ()" is equivalent to "execution (* com.lqr..* (..)", so the above code can be changed like this:
@ Before ("pointcut ()") public void before (JoinPoint point) {System.out.println ("CSDN_LQR");} @ AfterThrowing (value = "pointcut ()", throwing = "ex") public void afterThrowing (Throwable ex) {System.out.println ("logging");}
IV. Actual combat
After the above study, it is time for actual combat, here we will give a simple example.
1. Tangent point
This is the click event of a button on the interface, it is just a simple method, we use it to try the knife.
Public void test (View view) {System.out.println ("Hello, I am CSDN_LQR");}
2. Section class
To weave a piece of code into the target class method, you must have a facet class. Here is the code for the facet class:
@ Aspectpublic class TestAnnoAspect {@ Pointcut ("execution (* com.lqr.androidaopdemo.MainActivity.test (..)") Public void pointcut () {} @ Before ("pointcut ()") public void before (JoinPoint point) {System.out.println ("@ Before");} @ Around ("pointcut ()") public void around (ProceedingJoinPoint joinPoint) throws Throwable {System.out.println ("@ Around");} @ After ("pointcut ()") public void after (JoinPoint point) {System.out.println ("@ After") } @ AfterReturning ("pointcut ()") public void afterReturning (JoinPoint point, Object returnValue) {System.out.println ("@ AfterReturning");} @ AfterThrowing (value = "pointcut ()", throwing = "ex") public void afterThrowing (Throwable ex) {System.out.println ("@ afterThrowing"); System.out.println ("ex =" + ex.getMessage ();}})
3. The implementation results of each notification
Let's first try to see how the implementation of these annotations turns out.
No, some of the button clicks print "Hello, I am CSDN_LQR". There is no such thing here. How can it be fat?
Here, because the @ Around surround notification will block the execution of the contents of the original method, we need to release it manually. The code is modified as follows:
@ Around ("pointcut ()") public void around (ProceedingJoinPoint joinPoint) throws Throwable {System.out.println ("@ Around"); joinPoint.proceed (); / / Target method execution completed}
That's not right, there is a @ AfterThrowing notification missing. This notification is executed only when the pointcut throws an exception, and we can make the code have a simple run-time exception:
Public void test (View view) {System.out.println ("Hello, I am CSDN_LQR"); int a = 1 / 0;}
The @ AfterThrowing notification is indeed invoked and an error message (divide by zero) is printed. However, the @ AfterReturning notification is not executed. The reason is very simple. An exception is thrown, and the pointcut must not return the result. In other words, @ AfterThrowing notifications and @ AfterReturning notifications conflict and cannot occur at the same pointcut at the same time.
4. the realization of time-consuming calculation of the method.
Because @ Around is a circular notification, you can perform some operations before and after the pointcut. In order to be sure whether the operation is before or after the pointcut, AspectJ needs to manually execute joinPoint.proceed () in the @ Around notification to determine that the pointcut has been executed, so the code before joinPoint.proceed () will be executed before the pointcut, and the code after joinPoint.proceed () will be executed after the pointcut. Therefore, the implementation of the time-consuming calculation of the method is as simple as this:
@ Around ("pointcut ()") public void around (ProceedingJoinPoint joinPoint) throws Throwable {long beginTime = SystemClock.currentThreadTimeMillis (); joinPoint.proceed (); long endTime = SystemClock.currentThreadTimeMillis (); long dx = endTime-beginTime; System.out.println ("time:" + dx + "ms");}
5. The function of JoinPoint
Found that no, all the above notifications will carry at least one JointPoint parameter, which contains all the information about the pointcut. Let's explain what method information can be obtained by joinPoint in combination with the button's click event method test ():
MethodSignature signature = (MethodSignature) joinPoint.getSignature (); String name = signature.getName (); / / method name: testMethod method = signature.getMethod (); / / method: public void com.lqr.androidaopdemo.MainActivity.test (android.view.View) Class returnType = signature.getReturnType (); / / return value type: voidClass declaringType = signature.getDeclaringType (); / / method class name: MainActivityString [] parameterNames = signature.getParameterNames (); / / Parameter name: viewClass [] parameterTypes = signature.getParameterTypes () / / Parameter type: View
6. Note tangent point
The previous tangent expression structure is as follows:
Execution (?)
But in fact, the structure of the above pointcut expression is incomplete and should look like this:
Execution (?)
This means that the pointcut can be marked with annotations.
1) Custom Annotation
If we use annotations to mark pointcuts, we will generally use custom annotations to facilitate our expansion.
Target (ElementType.METHOD) @ Retention (RetentionPolicy.RUNTIME) public @ interface TestAnnoTrace {String value (); int type ();}
@ Target (ElementType.METHOD): indicates that the comment can only be annotated on the method. If you want to use both classes and methods, you can write @ Target ({ElementType.METHOD,ElementType.TYPE}), and so on.
Retention (RetentionPolicy.RUNTIME): indicates that the annotation is visible when the program is running (and SOURCE and CLASS respectively specify which level the annotation is visible to, usually using RUNTIME).
Value and type are their own extended properties to facilitate the storage of some additional information.
2) use custom annotations to mark pointcuts
This custom annotation can only be annotated on methods (except for constructors, which are also called constructors and need to use ElementType.CONSTRUCTOR). You can use it as usual with other annotations:
TestAnnoTrace (value = "lqr_test", type = 1) public void test (View view) {System.out.println ("Hello, I am CSDN_LQR");}
3) Tangent expression of annotations
Since the pointcut is marked with annotations, the pointcut expression must be different, as follows:
@ Pointcut ("execution (@ com.lqr.androidaopdemo.TestAnnoTrace * * (..)") public void pointcut () {}
Pointcut expressions use annotations, which must be the full path of @ + annotations, such as @ com.lqr.androidaopdemo.TestAnnoTrace.
The personal test is available, not the map.
4) get the attribute value of the annotation
The above declared two properties, value and type, when writing a custom annotation, and assigned values to it when using the annotation, so how do you get these two property values in the notification? Remember the parameter JoinPoint, which can get the attribute values in the annotation, as shown below:
MethodSignature signature = (MethodSignature) joinPoint.getSignature (); Method method = signature.getMethod (); / / get annotations on the pointcut through the Method object TestAnnoTrace annotation = method.getAnnotation (TestAnnoTrace.class); String value = annotation.value (); int type = annotation.type () The above is about the content of this article on "how to achieve aspect-oriented programming in Android". I believe we all have some understanding. I hope the content shared by the editor will be helpful to you. If you want to know more related knowledge, please pay attention to the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.