如何为抽象方法创建切入点

时间:2019-02-05 13:56:19

标签: java spring spring-aop

我试图为在子类中实现的抽象方法创建切入点,但是AOP从未被调用。

这是我的最小Java代码:

package com.example;

public class Service {
    private ParentAbstractClass clazz;

    public Service(ParentAbstractClass clazz) {
        this.clazz = clazz;
    }

    public void process() {
        clazz.method();
    }
}

这是服务类,它具有要注入的类的抽象,并调用方法。

我的抽象类具有一些通用的逻辑,而实现特定的代码则是一种抽象方法。

package com.example;

import java.util.List;

public abstract class ParentAbstractClass {
    public void method() {
        abstractMethod(List.of("test"));
    }

    public abstract void abstractMethod(List<String> names);
}

这是为抽象方法提供实现的类。

package com.example;

import java.util.List;

public class ConcreteClass extends ParentAbstractClass {
    @Override
    public void abstractMethod(List<String> names) {
        System.out.println("Look up! AOP should have executed");
    }
}

通过此设置,我正在使用spring XML来配置我的bean。

<bean id = "clazz" class="com.example.ConcreteClass"/>

<bean id="myservice" class="com.example.Service">
    <constructor-arg ref="clazz"/>
</bean>

<bean id = "aspect" class="com.exmple.TxAspect"/>

<aop:config>
    <aop:aspect id="mergeEnableAspect" ref="aspect">
        <aop:pointcut id="mergeServicePointCut"
                      expression="execution(* com.example.ConcreteClass.abstractMethod(..))"/>
        <aop:around pointcut-ref="mergeServicePointCut" method="test" arg-names="pjp"/>
    </aop:aspect>
</aop:config>

最后是AOP类:

import org.aspectj.lang.ProceedingJoinPoint;

public class TxAspect {
    public void test(ProceedingJoinPoint pjp) {

        System.out.println("I am not going to do anything");

    }
}

在我的abstractMethod中,我所做的事情本质上是事务性的,并且我需要手动控制事务,但是我的方面类从未被调用。有人可以帮我找出我犯了什么错误。

谢谢。

1 个答案:

答案 0 :(得分:1)

该问题是由Spring AOP实现的约束引起的。这是来自Spring documentation的引用:

  

由于Spring的AOP框架基于代理,因此在   根据定义,目标对象不会被拦截。对于JDK   代理,只能在代理上调用公共接口方法   被拦截。使用CGLIB,可在   代理被拦截(甚至包可见的方法,如果   必要)。但是,通过代理进行的常见互动应始终   通过公共签名进行设计。

     

请注意,切入点定义通常与任何   拦截方法。如果严格意义上切入点仅是公开的,   即使在具有潜在的非公开交互的CGLIB代理方案中   通过代理,需要进行相应的定义。

     

如果您的拦截需要包括方法调用甚至是构造函数   在目标类中,考虑使用Spring驱动的本机   AspectJ编织而不是Spring的基于代理的AOP框架。这个   构成了不同的AOP使用模式   特性,所以一定要使自己熟悉编织   在做出决定之前。

因此,您有两种可能的方法来解决该问题:

  1. 仅将您的方面用于其他bean调用的方法(无自调用)
  2. 使用AspectJ AOP实现。我使用AspectJ编译时编织编写了一个简单的示例,该代码托管在github

AspectJ方法简而言之:

修改交易方式如下:

package com.example;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TxAspect {

    @Around("methodsToBeProfiled()")
    public void test(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("I am not going to do anything");
        pjp.proceed();
    }

    @Pointcut("execution(* com.example.ConcreteClass.abstractMethod(..))")
    public void methodsToBeProfiled(){}
} 

减少XML配置如下:

  <bean id="clazz" class="com.example.ConcreteClass"/>

  <bean id="myservice" class="com.example.Service">
    <constructor-arg ref="clazz"/>
  </bean>

使用以下maven插件编译应用程序:

  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.11</version>
    <dependencies>
      <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjtools</artifactId>
        <version>${ascpectj.version}</version>
      </dependency>
    </dependencies>
    <configuration>
      <source>1.8</source>
      <target>1.8</target>
      <complianceLevel>1.8</complianceLevel>
    </configuration>
    <executions>
      <execution>
        <goals>
          <goal>compile</goal>
          <goal>test-compile</goal>
        </goals>
      </execution>
    </executions>
  </plugin>