we use Compile-time weaving - it's the most powerful possibility from all aspect-weaving possibilities (e.g. load-time weaving (LTW) doesn't allow to create aspects around private and final methods). Another advantage is that it doesn't have negative performance impact on running application (LTW makes weaving during class initialization). Disadvantage can be that compilation has to be by AspectJ compiler => build script and IDE must be adjust.
There is blog post about performance comparision: The results are a bit surprising for me for two reasons. First, creating objects marked as @Configurable is less than 4 times slower than creating ordinary objects using new operator.
|
pointcuts syntax = AspectJ syntax
Using aspectj-autoproxy means that @Aspect annotations are recognized, but Spring proxies are still being created, see this quote from the documentation: Do not be misled by the name of the element: using it will result in the creation of Spring AOP proxies. The @AspectJ style of aspect declaration is just being used here, but the AspectJ runtime is not involved. |
all production code (not test code) is compiled by aspectj with use aspectj-maven-plugin, standard compilation with maven-compiler-plugin is disabled (again for production code only)
<!-- configure Java compilers --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven-compiler-plugin.version}</version> <configuration> <!-- http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#configuration-metadata-annotation-processor --> <proc>none</proc> <source>${java.version}</source> <target>${java.version}</target> <encoding>UTF-8</encoding> <showDeprecation>true</showDeprecation> <showWarnings>true</showWarnings> </configuration> <!-- compiler is disabled because of aspectj compiler --> <executions> <execution> <id>default-compile</id> <phase>none</phase> </execution> </executions> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.10</version> <executions> <execution> <goals> <goal>compile</goal> </goals> </execution> </executions> <configuration> <!-- https://eclipse.org/aspectj/doc/next/devguide/ajc-ref.html --> <complianceLevel>${java.version}</complianceLevel> <source>${java.version}</source> <target>${java.version}</target> <Xlint>ignore</Xlint> <!--<showWeaveInfo>true</showWeaveInfo>--> <!--<forceAjcCompile>true</forceAjcCompile>--> <weaveDirectories> <weaveDirectory>${project.build.directory}/classes</weaveDirectory> </weaveDirectories> <aspectLibraries> <aspectLibrary> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </aspectLibrary> </aspectLibraries> </configuration> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>${aspectj.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${aspectj.version}</version> </dependency> </dependencies> </plugin> |
dependency on AspectJ libraries and Spring aspects is necessary (configuration from root pom.xml). We can also add dependency on own custom aspects.
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> </dependency> </dependencies> |
There is module wiseporter-logging (not from OpenHub framework) that contains aspect com.openwise.wiseporter.log.EntitySavingAspect - this aspect logs entity before saving:
/** * Aspect example. * * @author <a href="mailto:petr.juza@openwise.cz">Petr Juza</a> * @since 0.1 */ @Aspect @Configurable public class EntitySavingAspect { @Autowired private ApplicationContext ctx; public EntitySavingAspect() { System.out.println("EntitySavingAspect created ..."); } @Before("com.openwise.wiseporter.commons.aop.CommonPointcuts.preSavingEntity()") public void logBeforeSaving(JoinPoint jp) { System.out.println("AOP (" + (ctx != null) + "): " + jp.getSignature()); } } |
where is reference to CommonPointcuts class (module wiseporter-commons):
@Aspect public class CommonPointcuts { /** * Join point is pre-saving method in entities. */ @Pointcut(value = "execution(void com.openwise.wiseporter.coreapi.entity.Saveable+.preSave())") public void preSavingEntity() {} /** * Join point is post-saving method in entities. */ @Pointcut(value = "execution(void com.openwise.wiseporter.coreapi.entity.Saveable+.postSave())") public void postSavingEntity() {} /** * Join point is deleting method in entities. */ @Pointcut(value = "execution(void com.openwise.wiseporter.coreapi.entity.Deletable+.delete())") public void inDeletingEntity() {} } |
It's necessary to adjust AspectJ compilation to use this aspect in another modules. We need to add dependency to this module with aspect - see adding wiseporter-logging module into aspectLibraries below.
<build> <plugins> <!-- added dependency to wiseporter-logging --> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <configuration> <aspectLibraries> <aspectLibrary> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </aspectLibrary> <aspectLibrary> <groupId>${project.groupId}</groupId> <artifactId>wiseporter-logging</artifactId> </aspectLibrary> </aspectLibraries> </configuration> </plugin> </plugins> </build> |
If aspect itself should be Spring bean (e.g. I need to use auto-wiring to another beans) then aspect has to be marked by annotation @Configurable. |
Tips for troubleshooting:
Spring AOP - log levels configuration
logging.level.org.springframework.aop=TRACE logging.level.org.aspectj=TRACE |
See Getting started to know how set up IDE for AspectJ compilation. |