Spring AOP + AspectJ maven 插件 - 内部方法调用不起作用

Posted

技术标签:

【中文标题】Spring AOP + AspectJ maven 插件 - 内部方法调用不起作用【英文标题】:Spring AOP + AspectJ maven plugin - Internal method call doesn't work 【发布时间】:2015-06-06 19:40:42 【问题描述】:

Java + Spring + Maven 应用程序。 无法从基于注释的公共方法进行内部调用。

先决条件

    Java 版本:1.7。 项目:AspectProject > 构建后它将创建 jar 文件。 客户端:AspectClient:具有“AspectProject”的依赖项。

AspectProject

    pom.xml
<properties>
        <java.version>1.7</java.version>    
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
        <springframework.version>4.1.2.RELEASE</springframework.version>        
        <org.aspectj-version>1.7.0</org.aspectj-version>
  </properties>

  <dependencies>

    <!-- Spring --> 
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>$springframework.version</version>
    </dependency>

     <!-- AspectJ dependencies -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>$org.aspectj-version</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjtools</artifactId>
        <version>$org.aspectj-version</version>
    </dependency>

  </dependencies>

   <build> 
    <sourceDirectory>src/main/java</sourceDirectory>
    <plugins>   
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
                <!-- compile for Java 1.7 -->
                <configuration>
                    <source>$maven.compiler.source</source>
                    <target>$maven.compiler.target</target>
                    <encoding>$project.build.sourceEncoding</encoding>
                </configuration>
        </plugin>
        <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.4</version>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjrt</artifactId>
                        <version>$org.aspectj-version</version>
                    </dependency>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>$org.aspectj-version</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <phase>process-sources</phase>
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                        <configuration>
                            <complianceLevel>$maven.compiler.source</complianceLevel>
                            <source>$maven.compiler.source</source>
                            <target>$maven.compiler.target</target>
                        </configuration>
                    </execution>
                </executions>
        </plugin>
    </plugins>
  </build>
    AspectProvider
@Aspect
public class AspectProvider    
    /**
     * This is the point cut for all get Method with @TestAnnotation annotation
     */
    @Pointcut("execution(* get*()) && @annotation(aTestAnnotation)")
    public void getMethodPointcut(TestAnnotation aTestAnnotation) 


    @Around("getMethodPointcut(aTestAnnotation)")
    public Object getConfiguration(ProceedingJoinPoint iJoinPoint, TestAnnotation aTestAnnotation) throws Throwable 
        return getValueFromISTCompositeConfiguration(iJoinPoint, aTestAnnotation);
    

    private Object getValueFromISTCompositeConfiguration(final ProceedingJoinPoint iProceedingJoinPoint, TestAnnotation aTestAnnotation) throws Throwable 

        Object aReturnValue = null;
        if (aTestAnnotation.value() != null) 
            System.out.println("ASPECT: Returning annotation value.");
            aReturnValue = aTestAnnotation.value();
         else 
            System.out.println("MISSING_GETTER_PROPERTY");
            
        if(aReturnValue == null)
             aReturnValue = iProceedingJoinPoint.proceed();
        
        return aReturnValue;
    

    注释“TestAnnotation”
@Component
@Target(ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation   
    String value();

AspectClient

    pom.xml
<properties>
        <java.version>1.7</java.version>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
        <aspectProject.version>0.0.1-SNAPSHOT</aspectProject.version>
        <spring-framework.version>4.1.2.RELEASE</spring-framework.version>
        <org.aspectj-version>1.7.0</org.aspectj-version>
    </properties>

    <dependencies>
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>$spring-framework.version</version>
        </dependency>

        <!-- AspectProject dependencies -->
        <dependency>
            <groupId>com.example.aop</groupId>
            <artifactId>AspectProject</artifactId>
            <version>$aspectProject.version</version>
        </dependency>
    </dependencies>

<build>
  <sourceDirectory>src/main/java/</sourceDirectory>
  <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <!-- compile for Java 1.7 -->
                <configuration>
                    <source>$maven.compiler.source</source>
                    <target>$maven.compiler.target</target>
                    <encoding>$project.build.sourceEncoding</encoding>
                </configuration>
           </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.4</version>
                <configuration>
                    <showWeaveInfo>true</showWeaveInfo>
                    <aspectLibraries>
                        <aspectLibrary>
                             <groupId>com.example.aop</groupId>
                             <artifactId>AspectProject</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                    <complianceLevel>$maven.compiler.source</complianceLevel>
                    <source>$maven.compiler.source</source>
                    <target>$maven.compiler.target</target>
                </configuration>
                <executions>
                    <execution>
                        <phase>process-sources</phase>
                        <goals>
                            <goal>compile</goal> 
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjrt</artifactId>
                        <version>$org.aspectj-version</version>
                    </dependency>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>$org.aspectj-version</version>
                    </dependency>
                </dependencies>
            </plugin> 
  </plugins>    
</build>
    服务类
@Component
public class TestService 

    private String value;

    public void internalCall() 
        System.out.println("INTERNAL_CALL :"+ getValue());
    

    @TestAnnotation("RETURNED_FROM_ASPECT_CALL") 
    public String getValue() 
        return value;
    

    public void setValue(String iValue) 
        this.value = iValue;
    


    Spring context.xml
<?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-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- Enable AspectJ style of Spring AOP -->
    <context:component-scan base-package="com.example.aop.client" />

    <aop:aspectj-autoproxy />

    <bean name="TestService" class="com.example.aop.client.service.TestService" />

    <!-- Configure Aspect Beans, without this Aspects advice wont execute -->
    <bean name="aspectProvider" class="com.example.aop.aspect.AspectProvider"/> 

</beans>
    主类
public class SpringMain 

    public static void main(String[] args) 
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
        TestService aTestService = ctx.getBean("TestService", TestService.class);

        System.out.println("EXTERNAL_CALL: "+aTestService.getValue());
        aTestService.internalCall();        
        ctx.close();
    


输出:

ASPECT: Returning annotation value. 
EXTERNAL_CALL:RETURNED_FROM_ASPECT_CALL 
INTERNAL_CALL: **null**

预期:

ASPECT: Returning annotation value.
EXTERNAL_CALL: RETURNED_FROM_ASPECT_CALL
INTERNAL_CALL: **RETURNED_FROM_ASPECT_CALL**

如果我遗漏任何条目或需要更改配置,请告知。提前感谢您的宝贵时间。

【问题讨论】:

【参考方案1】:

您所做的有点奇怪,因为一方面您将 Spring 配置为使用(自动)基于代理的 Spring AOP,另一方面您使用 AspectJ Maven 插件来使用本机 AspectJ 并进行编译时编织。请决定你想走哪条路:

对于 Spring AOP,您不需要 AspectJ 编译器,但随后您会坚持使用基于代理的“AOP lite”方法,其代价是内部调用不会被切面拦截,因为它们不通过代理,而是通过this(原始对象)。 对于成熟的 AspectJ,您可以配置 Spring 以使用 LTW(加载时编织),如手册章节 Using AspectJ with Spring applications 中所述。或者,您也可以使用编译时编织,但这不是必需的,除非您在应用程序启动期间遇到性能问题。

【讨论】:

感谢 Kriegaex。我是 aop 概念的新手。你是对的,我错误地弄乱了 Spring-aop 和 AspectJ 编译器。我想要 AspectJ 功能,以便内部调用被切面拦截。

以上是关于Spring AOP + AspectJ maven 插件 - 内部方法调用不起作用的主要内容,如果未能解决你的问题,请参考以下文章

[Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.

在Spring中使用AspectJ实现AOP

Spring的aop操作

Spring详解------AspectJ 实现AOP

Spring的AOP操作

Spring5学习笔记 — “AOP操作—AspectJ注解”