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

问题描述 投票:1回答:1

我正在尝试为子类中实现的抽象方法创建切入点,但AOP永远不会被调用。

这是我的最小Java代码:

package com.example;

public class Service {
    private ParentAbstractClass clazz;

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

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

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

我的抽象类有一些共同的逻辑和一个实现特定的代码,它是一个抽象的方法。

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中,我正在做一些事务性的事情,我有业务需要手动控制事务但是,我的方面类永远不会被调用。有人可以帮我解决我做错了什么。

谢谢。

java spring spring-aop
1个回答
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>
© www.soinside.com 2019 - 2024. All rights reserved.