Based on enhanced AspectJ code that implements time-consuming method of recording one line comment

background

Because of the need for performance testing method performed on the item, if the method were coupled before and after each following code

long beginTime = System.currentTimeMillis(); 
long endTime = System.currentTimeMillis(); 
long timeConsume = endTime - beginTime; 
复制代码

Apparently the code will become very jumbled, and where it is needed statistical performance may also have a lot of, if you can simply add a comment on the method, we can achieve recording method for performing time-consuming, so will be able to reduce the number of simple and complicated the code, more convenient extension

Technology Selection

Like this scene is a typical scenario AOP, search SpringAOP can find a lot of code samples, but the project does not depend on Spring, there is no need to introduce Spring. Usually to achieve this function, there are two options, one is like SpringAOP as dynamic proxy or by CGLib JDK dynamic proxy, when you create an object, the object is dynamically generated proxy class, the other is AspectJ, compiled logic when executed the code will need woven into the bytecode.

For dynamic proxy, you need to create an object proxy class before they can enhance, but the project, there are a lot of static methods, when used by the object is not to call, but even if the method is invoked by the object, there is no convenient Spring IOC mechanisms, we have to modify the code to handle all the new objects before they can use the enhanced proxy object, a little trouble. And if it is frequently create object because another step to create a proxy object of the operation, there will be some loss of performance.

For AspectJ this manner, it is possible to place the cut point satisfies the expression, are woven into the enhanced logic, but the need to rely on assistance weaving tools, to enhance the compiled bytecode. Fortunately, there has been a corresponding aspectj compiled plug-in on maven, can easily treated weaving

Under the comprehensive consideration, we decided to adopt the custom annotation (target) + ApsectJ (Aop Enhanced) + aspectj the Maven build plug-ins to achieve

Technical realization

1, custom annotation

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface TimeConsumeLogAnnotation { 

} 
复制代码

2, dependent on the introduction Aspectj

<dependency> 
​    <groupId>org.aspectj</groupId> 
​    <artifactId>aspectjrt</artifactId> 
​    <version>1.8.9</version> 
</dependency> 
复制代码

3, Aspectj section

@Aspect 
public class TimeConsumeLogAspectJ { 
​    //通过ThreadLocal隔离不同线程的变量 
​    ThreadLocal<Long> timeRecord = new ThreadLocal<>(); 

​    @Pointcut("execution(* *(..)) && @annotation(cn.freekiddo.annotation.TimeConsumeLogAnnotation)") 
​    public void jointPoint(){} 

​    @Before("jointPoint()") 
​    public void doBefore(JoinPoint joinPoint){ 
​        MethodSignature signature = (MethodSignature) joinPoint.getSignature(); 
​        Method method = signature.getMethod(); 
​        System.out.println("方法" + method.getName() + "开始"); 
​        timeRecord.set(System.currentTimeMillis()); 
​    } 

​    @After("jointPoint()") 
​    public void doAfter(JoinPoint joinPoint){ 
​        long beginTime = timeRecord.get(); 
​        System.out.println("方法" +joinPoint.getSignature().getName()+ "结束,耗时"+(System.currentTimeMillis()-beginTime) +"ms"); 
​    } 
} 
复制代码

4, the introduction maven compiler plugin

Longer work after the maven-compiler-plugin processed

<plugin> 
​    <groupId>org.codehaus.mojo</groupId> 
​    <artifactId>aspectj-maven-plugin</artifactId> 
​    <version>1.10</version> 
​    <configuration> 
​        <source>1.8</source> 
​        <target>1.8</target> 
​        <complianceLevel>1.8</complianceLevel> 
​    </configuration> 
​    <executions> 
​        <execution> 
​            <phase>compile</phase> 
​            <goals> 
​                <goal>compile</goal> 
​            </goals> 
​        </execution> 
​    </executions> 
</plugin> 
复制代码

5. Add @TimeConsumeLogAnnotation notes compiled to run on the target method

@TimeConsumeLogAnnotation() 
public static void sayHelloWorld(String name) { 
​    System.out.println("Hello " + name); 
} 
复制代码

Compiled bytecode

@TimeConsumeLogAnnotation 
public static void sayHelloWorld(String name) { 
​    JoinPoint var1 = Factory.makeJP(ajc$tjp_0, (Object)null, (Object)null, name); 
​    try { 
​        TimeConsumeLogAspectJ.aspectOf().doBefore(var1); 
​        System.out.println("Hello " + name); 
​    } catch (Throwable var4) { 
​        TimeConsumeLogAspectJ.aspectOf().doAfter(var1); 
​        throw var4; 
​    } 
​    TimeConsumeLogAspectJ.aspectOf().doAfter(var1); 
} 
复制代码

effect

方法sayHelloWorld开始 
Hello world 
方法sayHelloWorld结束,耗时1ms 
复制代码

6, stepped pit

(1) section executed twice

Section at the beginning of the expression is

@Pointcut("@annotation(cn.freekiddo.annotation.TimeConsumeLogAnnotation)") 
复制代码

The compiler will recognize aspectj of the method calls and method for performing an entry point in two stages, as will perform in two stages

Expression is modified by section

@Pointcut("execution(* *(..)) && @annotation(cn.freekiddo.annotation.TimeConsumeLogAnnotation)") 
复制代码

It may be defined as only the recognition method performed at this stage

(2) multi-module project fails to compile aspectj

If when the multi-module program, in a specific sub-class module declaration section, defined cut point expression, but the point of attachment of each cut dispersed in other modules, to the tangent point with the scanning AJC expression, present only in the corresponding scanning module connection point, the connection point of the other modules are cut into the cut surface for Sounds of no way, ajc is not going to go when scanning unravel some other module has no connection with the current cut-off point expression match point

By adding custom annotations and are cut in each module, the compiler can solve problems

More operations

Since the custom annotation support assignment, Aspectj section and can intercept method, and the method parameters to get through reflection, so you can do more customized optimization on this basis

Reference links

Spring AOP implementation principles and application CGLIB

AspectJ about things you might not know

AspectJ aspect performed twice Analysis

Multi-module maven project using the Eclipse AspectJ weaving in for Sounds

Guess you like

Origin juejin.im/post/5d569704e51d456210163b93