Search code examples
springspring-bootaopaspectjspring-aop

AspectJ before spring boot starts


Suppose i have a spring boot application

@SpringBootApplication
public abstract class AbstractMicroServer {

    public static void main(final String[] args) {
        // here some asppect should start
        final SpringApplication app = new SpringApplication(AbstractMicroServer.class);
        app.run(args);
    }
}

My aspectJ class

@Aspect
public class AOP{

    @Pointcut("execution(* org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.ignoreResourceType(..)")
    public void intercept() {
    }

    @Around("intercept()")
    public Object intercept(final ProceedingJoinPoint joinPoint) throws Throwable {
        return joinPoint.getArgs();
    }
}

I want this Aspect to be ready before spring boot starts. Is this possible what i want to do ? The aspect is not getting intercepted for some reason which i dont know.

POM

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.12</version><!--$NO-MVN-MAN-VER$ -->
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.12</version><!--$NO-MVN-MAN-VER$-->
        </dependency>

      <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.10</version>
                    <configuration>
                        <complianceLevel>1.8</complianceLevel>
                        <source>1.8</source>
                        <target>1.8</target>
                        <showWeaveInfo>true</showWeaveInfo>
                        <verbose>true</verbose>
                        <Xlint>ignore</Xlint>
                        <encoding>UTF-8</encoding>
                        <includes>
                            <include>**/*.java</include>
                            <include>**/*.aj</include>
                        </includes>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <!-- use this goal to weave all your main classes -->
                                <goal>compile</goal>
                                <!-- use this goal to weave all your test classes -->
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

I am not using spring boot starter aop. Above are all the configuration and code i have for aop.


Solution

  • Spring AOP

    Runtime Weaving

    The Spring AOP is based on runtime weaving due to the proxy-based nature of the Spring framework. This means the target class is turned into a proxy during Spring runtime.

    In most cases, the Spring framework doesn't make a proxy of its frameworks classes. The class you are interested, CommonAnnotationBeanPostProcessor, is not proxied. Therefore, Spring AOP cannot intercept any calls to ignoreResourceType method of CommonAnnotationBeanPostProcessor.

    However, it doesn't mean you are out of luck. You can still take advantage of AspectJ's binary weaving.

    AspectJ

    Binary Weaving

    In binary weaving, the target and aspect source code (*.java) are compiled separately into binary classes (.class). The binary classes are then woven together with AspectJ compiler (ajc).

    In your case, the aspect source code (AOP.java) will be compiled with AspectJ compiler into a binary class (AOP.class). The AOP.class and the existing Spring class, CommonAnnotationBeanPostProcessor.class will be weaved to together into a new weaved CommonAnnotationBeanPostProcessor.class.

    Code Before Weaving

    Here is the code snippet of ignoreResourceType method of class CommonAnnotationBeanPostProcessor,

    public void ignoreResourceType(String resourceType) {
            Assert.notNull(resourceType, "Ignored resource type must not be null");
            this.ignoredResourceTypes.add(resourceType);
    }
    

    Code After Weaving

    Now, notice the changes after the method is woven by AspectJ.

    public void ignoreResourceType(String resourceType) {
            JoinPoint var3 = Factory.makeJP(ajc$tjp_0, this, this, resourceType);
            SpringFrameworkClassAspect var10000 = SpringFrameworkClassAspect.aspectOf();
            Object[] var4 = new Object[]{this, resourceType, var3};
            var10000.adviceAround((new CommonAnnotationBeanPostProcessor$AjcClosure1(var4)).linkClosureAndJoinPoint(69648));
    }
    

    How to achieve AspectJ Binary Weaving?

    • You can generate binary weaving with the help of Mojo's AspectJ Maven plugin.
    • You will still need your aspect class.
    • Make sure to include spring-context dependency under weaveDependencies.

    Below is an excerpt from the plugin section of your project's pom.xml. You can find a complete working example here.

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.10</version>
                <configuration>
                    <showWeaveInfo/>
                    <source>1.8</source>
                    <target>1.8</target>
                    <complianceLevel>${java.version}</complianceLevel>
                    <Xlint>ignore</Xlint>
                    <forceAjcCompile>true</forceAjcCompile>
                    <sources/>
                    <weaveDirectories>
                        <weaveDirectory>${project.build.directory}/classes</weaveDirectory>
                    </weaveDirectories>
                    <weaveDependencies>
                        <dependency>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring-context</artifactId>
                        </dependency>
                    </weaveDependencies>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring-aspects</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjrt</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>