Search code examples
aopaspectj

can ajc omit a specified @Aspect class and let spring aop handle it?


My application need to use both Aspectj and Spring AOP , Spring AOP is convenient sometimes , but when i use ajc compiler , it compiles all files annotated with @Aspectj.

my question is : can i tell ajc to ignore a specific Aspectj file and let Spring AOP handle the aop job ? tried my best but failed to figure it out , so help needed ... tks advance !


i use gradle to manage my application , and i wrote a gradle plugin with integrate ajc in it .

weaveClasses.dependsOn compileJava classes.dependsOn weaveClasses

i use post compile method .

here is my gradle config , i only post the structure .

group 'com.test.api'
apply plugin: 'base'
apply plugin: 'maven-publish'
apply plugin: 'findbugs'

apply plugin: 'java'

sourceCompatibility = 1.8


ext {
    springBootVersion = '1.5.4.RELEASE'
    springVersion = '4.3.9.RELEASE'




    env = System.getProperty("env") == null ? "development" : System.getProperty("env")
}

buildscript {
    ext {
        springBootVersion = '1.5.3.RELEASE'
    }

    repositories {
        mavenLocal()
        jcenter()
    }

    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion")
        classpath "com.test.tools:aspectj-post-compile:1.1.5"
    }
}

allprojects {
    apply plugin: 'java'

    sourceCompatibility = 1.8
    targetCompatibility = 1.8

    version '0.1.7'
    group 'com.test.api'

    apply plugin: 'maven-publish'
    publishing {
        publications {
            mavenJava(MavenPublication) {
                from components.java
            }
        }
    }
}


subprojects {
    apply plugin: 'idea'
    apply plugin: 'java'
    apply plugin: "aspectj.post.compile"

    version = parent.version
    group = parent.group

    sourceCompatibility = 1.8
    targetCompatibility = 1.8

    configurations {
        all*.exclude group: "org.springframework.boot", module: "spring-boot-starter-logging"
        all*.exclude group: "org.slf4j", module: "slf4j-log4j12"
    }

    apply plugin: 'checkstyle'
    checkstyle {
        toolVersion = "7.6"
        ignoreFailures = true
        configFile file("${project.rootDir}/checkstyle/test-java.xml")
    }

    tasks.withType(Checkstyle) {
        reports {
            xml.enabled = false
            html.enabled = false
        }
    }

    repositories {
        mavenLocal()
        maven { url "http://maven-test.corp.yiran.com:8081/repository/maven-public/" }
        jcenter()
    }

    sourceSets {
        main {
            resources {
                srcDirs = ["src/main/resources/base", "src/main/resources/$env"]
            }
        }
        test {
            resources {
                srcDirs = ["src/test/resources/base", "src/test/resources/$env"]
            }
        }
    }



    [compileJava, compileTestJava]*.options.collect { options ->
        options.compilerArgs.add '-parameters'
    }
    weaveClasses.dependsOn compileJava
    classes.dependsOn weaveClasses
}



project(":geneva-contract") {
    jar.archiveName = "test-contract.jar"

    dependencies {
        compile "com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion"
        compile "org.projectlombok:lombok:$lombokVersion"
        compile "com.test.service:farmer-base:$farmerVersion"
        compile "com.test.api:daily-open-base:$dailyOpenVersion"

    }
}

Solution

  • The easiest way would be to put AspectJ and Spring AOP aspects into different Maven/Gradle modules and only build the AspectJ module with the AspectJ compiler, then put that module on the aspect path for the application module(s) it is to be woven into.

    A more complicated way is to use an undocumented feature for compile-time weaving:

    -xmlConfigured /path/to/my/aop-ctw.xml
    

    Update: AJC option -xmlConfigured is now documented here.

    See also my AspectJ ticket 455014 and follow the links from my comments there for further information.

    A little example:

    package de.scrum_master.app;
    
    public class Application {
      public static void main(String[] args) {}
    }
    
    package de.scrum_master.aspect;
    
    public aspect FirstAspect {
      before() : execution(* *(..)) {
        System.out.println(this.getClass().getSimpleName() + ": " + thisJoinPoint);
      }
    }
    
    package de.scrum_master.aspect;
    
    public aspect SecondAspect {
      before() : execution(* *(..)) {
        System.out.println(this.getClass().getSimpleName() + ": " + thisJoinPoint);
      }
    }
    

    If you compile and run this normally, the console log says:

    FirstAspect: execution(void de.scrum_master.app.Application.main(String[]))
    SecondAspect: execution(void de.scrum_master.app.Application.main(String[]))
    

    But if you add a configuration file like this...

    <aspectj>
      <aspects>
        <aspect name="de.scrum_master.aspect.FirstAspect" />
      </aspects>
    </aspectj>
    

    ... and then reference it from your compiler command line, e.g. like this from Eclipse with AJDT installed, ...

    XML configuration for AspectJ compiler

    ... the console log changes to:

    FirstAspect: execution(void de.scrum_master.app.Application.main(String[]))