Search code examples
springperformanceaopaspectjdynamic-proxy

aop performance on spring (idk, aspectj)


I tried to test the performance of AOP on Spring framework 4.1.6 and

AOP methods were clean, jdk dynamic proxy and aspectJ.

I made one to five simple advices to them and checked elapsed time for each.

result:

jdk dynamic proxy:

    • aspect1: 2.499 sec.
    • aspect2: 2.574
    • aspect3: 2.466
    • aspect4: 2.436
    • aspect5: 2.563

    aspectJ (ctw):

      • aspect1: 2.648
      • aspect2: 2.562
      • aspect3: 2.635
      • aspect4: 2.520
      • aspect5: 2.574

      clean (no aspect):

        • aspect1: 2.699
        • aspect2: 2.513
        • aspect3: 2.527
        • aspect4: 2.458
        • aspect5: 2.402

        Before testing them, I expected AspectJ (ctw) will be faster than Jdk dynamic proxy because AspectJ modified bytecode. But it was wrong even there was no performance difference among them.

        So, I checked the target class(.class) modified to recognise that AspectJ Compiler used and found bytecode modified.

        Here, I have question: Is there any performance difference among them? (idk dynamic proxy, aspectj, no aop)

        My code:

        public class HelloAOP {
        
        public static void main(String [] args) {
        
            ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/application-context.xml");
            Order order = (Order) ctx.getBean("orderImpl");
            SimpleDateFormat format = new SimpleDateFormat("mm:ss.SSS");
        
            StopWatch watch = new StopWatch();
        
            watch.start();
            order.placeOrder();
            watch.stop();
        
            System.out.println("Elapsed: " + format.format(watch.getTotalTimeMillis()));
            }
        }
        

        target:

        @Service
        public class OrderImpl implements Order {
            public void placeOrder() {
                System.out.println("::Target Object");
                for(long i = 0; i < 5000000000L; i++);
            }
        }
        

        aspect:

        @Aspect
        @Component
        public class Aspect1 {
        
            @Before("execution(* com.cafe.beans.impl.OrderImpl.placeOrder())")
            public void aspect() {
                System.out.println("Aspect 1 *");
            }
        }
        

        pom.xml:

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>4.1.6</version>
            </dependency>
        
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>4.1.6</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-instrument</artifactId>
                <version>4.1.6.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.6</version>
            </dependency>
        
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>1.8.6</version>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjtools</artifactId>
                <version>1.8.6</version>
            </dependency>
        
        <build>
            <finalName>testAop</finalName>
            <plugins>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>3.3</source>
                        <target>3.3</target>
                    </configuration>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <includes>
                            <include>**/*Tests.java</include>
                        </includes>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.7</version>
                    <configuration>
                        <showWeaveInfo>true</showWeaveInfo>
                        <verbose>true</verbose>
                        <complianceLevel>1.8</complianceLevel>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
        

        Solution

      • You should not be surprised not to see any difference because you are just measuring one single method call. 99.9% of the time measured is the loop inside your method. Ergo you are not measuring the right thing. You should do it the other way around, maybe similar to what I did here:

        • The method should do nothing or next to nothing and print nothing.
        • You should measure the overall time of repeatedly calling an aspect-advised method because you want to find out about the overhead of applying an aspect, not about method body runtime (the method body remains unchanged by your aspect).

        Now you can compare Spring AOP to AspectJ performance and should see that AspectJ is superior. A few caveats:

        • I hope you know that you need to change the Spring configuration so as to switch from Spring AOP to AspectJ and vice versa. E.g. if you use the AspectJ Maven Plugin all the time for your builds, you will use compile-time AspectJ weaving, no matter if you configure Spring to use Spring AOP or AspectJ via load-time weaving as described in the Spring manual, section 10.8 Using AspectJ with Spring applications.
        • You should measure different types of pointcuts and advice, e.g. @Before/@After vs. @Around, (not) using parameter binding via this(), target() or args() etc.
        • Please also note that your sample code uses a pointcut on a class rather than an interface. JDK dynamic proxies do not work directly on classes, though, only on interfaces. In order to apply Spring AOP on classes, you need CGLIB as a dependency in Spring, otherwise it simply will not work. Edit: Okay, your class implements the Order interface, so it might still work with JDK dynamic proxies.