This is a very simple Spring AOP tutorial using AspectJ. This assumes that you have gone through the “Setting up Java, Maven and Eclipse” tutorial and the other Spring tutorials 1 to 3. This annotation profiles the time taken to execute the annotated methods.
You need to have a project structure as shown below with the relevant artifacts.
Step 1: pom.xml file with spring dependendencies. You can try using different (i.e. latest version of spring).
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mytutorial</groupId> <artifactId>simple</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>simple</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>3.1.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.1.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.1.0.RELEASE</version> </dependency> <!-- Spring AOP + AspectJ --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>3.1.0.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.11</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.11</version> </dependency> </dependencies> </project> |
Step 2: Define an annotation. The methods that are annotated with this annotation “@Profile ” will be profiled.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.mytutorial.util; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Inherited public @interface Profile { } |
Step 3: Define the Aspect “ProfileAspect“, which actually performs the profiling on methods that are annotated with “@Aspect“.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package com.mytutorial.util; import java.lang.reflect.Method; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; @Component @Aspect public class ProfileAspect implements Ordered { @Around(value = "@annotation(profile)", argNames = "profile") public Object invoke(final ProceedingJoinPoint pjp, final Profile profile) throws Throwable { Object target = pjp.getTarget(); MethodSignature signature = (MethodSignature) pjp.getSignature(); Method method = signature.getMethod(); long nanoTimeStart = System.nanoTime(); Object result = pjp.proceed(); // execute the method long nanoTimeFinish = System.nanoTime(); System.out.println("Completed " + method.getName() + " on " + target.getClass() + " in " + (nanoTimeFinish - nanoTimeStart) + " nano seconds"); return result; } public int getOrder() { return 0; } } |
Step 4: Define the DAO layer Java interface and implementation for Course.
|
1 2 3 4 5 |
package com.mytutorial.dao; public interface CourseDao { abstract void readAllCourses(); } |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.mytutorial.dao; import org.springframework.stereotype.Repository; import com.mytutorial.util.Profile; @Repository("courseDao") public class CourseDaoImpl implements CourseDao { @Profile public void readAllCourses() { //logic to read courses System.out.println("read all courses from a datasource not shown here"); } } |
Step 3: Define the Service layer Java interface and implementation for Course.
|
1 2 3 4 5 |
package com.mytutorial.service; public interface CourseService { abstract void findAllCourses(); } |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package com.mytutorial.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import com.mytutorial.dao.CourseDao; import com.mytutorial.util.Profile; @Service("courseService") public class CourseServiceImpl implements CourseService { @Autowired @Qualifier("courseDao") private CourseDao dao; // spring injects this @Profile public void findAllCourses() { System.out.println("started executing the service layer"); dao.readAllCourses(); System.out.println("finished executing the service layer"); } } |
Note: Note that “CoursDaoImpl” need to be injected via Spring into the “CourseServiceImpl”. The @Profile annotation is added to gather times.
Step 4: The Spring context XML file that wires up dependnecies. It defines the DAO and Service Java classes with “CoursDaoImpl” being injected into “CourseServiceImpl” via the setter injection using annotations.
conf/courseApplicationContext.xml
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <aop:aspectj-autoproxy /> <context:component-scan base-package="com.mytutorial" /> </beans> |
Note: “aop:aspectj-autoproxy” is added.
Step 5: Finally, bootstrap the “courseApplicationContext.xml” via the App.java with the main method to execute this stand alone.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package com.mytutorial; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.mytutorial.service.CourseService; /** * Hello world! * */ public class App { public static void main( String[] args ) { System.out.println( "Hello World!" ); ApplicationContext applicationContext = new ClassPathXmlApplicationContext("conf/courseApplicationContext.xml"); CourseService courseService = (CourseService)applicationContext.getBean("courseService"); courseService.findAllCourses(); } } |
Output:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Hello World! 22/10/2014 3:49:37 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@38c5c3ac: startup date [Wed Oct 22 15:49:37 EST 2014]; root of context hierarchy 22/10/2014 3:49:37 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [conf/courseApplicationContext.xml] 22/10/2014 3:49:37 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@72c743eb: defining beans [org.springframework.aop.config.internalAutoProxyCreator,appConfig,courseDao,courseService,profileAspect,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy started executing the service layer read all courses from a datasource not shown here Completed readAllCourses on class com.mytutorial.dao.CourseDaoImpl in 52392 nano seconds finished executing the service layer Completed findAllCourses on class com.mytutorial.service.CourseServiceImpl in 1020110 nano seconds |
Note: You can see the “52392” ns and “1020110” ns for the execution of methods “readAllCourses” and “findAllCourses” respectively. AOP is very powerful for things like
1) Logging/Auditing.
2) Profiling time/memory.
3) Service retry.
These are all cross-cutting concerns.


