【问题标题】:pointcut for method in parent abstract class父抽象类中方法的切入点
【发布时间】:2018-06-15 12:33:50
【问题描述】:

我有一个场景,我的方法被拦截在父类中,并且在切入点类中没有被覆盖。 以下是示例类:

public abstract class A{
@RequestMapping(value = "/data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String getData(@RequestBody String request) throws Exception {
    return "dummy";
}
}

@RestController
public class B extends A {
}

我的方面被定义为:

@Aspect
@Component
public class RestCallLogger {
    @Pointcut("within(com.test..*) && within(@org.springframework.web.bind.annotation.RestController *)")
    public void restControllers() {
    }

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void requestMappingAnnotations() {
    }

    @Around("restControllers() && requestMappingAnnotations()")
    public Object onExecute(ProceedingJoinPoint jp) throws Throwable {
        Object result = null;
        try {
            result = jp.proceed();
        } catch (Exception ex) {
            throw ex;
        }
        return result;
    }
}

但它不起作用。如果我用 Annotation @RestController 标记 A 类并使其具体化,那么它就可以工作。 问题是如何创建“父抽象类中方法的切入点”? PS:我无法将代码的层次结构更改为现有代码。

【问题讨论】:

  • 我认为它不适用于抽象类,作为拦截方法调用的 aop。我们不能创建抽象类的对象。所以你应该为具体的切入点定义。
  • 对于切入点,您需要声明抽象的底层实现。 Aspect 将在...周围/之前创建一个切入点,然后它将首先创建一个代理对象。每个代理实例都有一个关联的调用处理程序对象,该对象实现了接口InvocationHandler.,该接口将用于调用实例调用处理程序的方法。更多关于这个docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html

标签: java spring aspectj spring-aop pointcut


【解决方案1】:

对我来说这是可行的。这是MCVE

package de.scrum_master.app;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

public abstract class A {
  @RequestMapping(value = "/data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
  public String getData(@RequestBody String request) throws Exception {
    return request;
  }
}
package de.scrum_master.app;

import org.springframework.web.bind.annotation.RestController;

@RestController
public class B extends A {}
package de.scrum_master.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ComponentScan(basePackages = { "de.scrum_master" })
public class Application2 {
  public static void main(String[] args) throws Exception {
    ApplicationContext appContext = new AnnotationConfigApplicationContext(Application2.class);
    B b = (B) appContext.getBean("b");
    System.out.println(b.getData("bbb"));
    A a = (A) appContext.getBean("b");
    System.out.println(a.getData("aaa"));
  }
}
package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class RestCallLogger {
  @Pointcut("within(de.scrum_master..*) && @target(org.springframework.web.bind.annotation.RestController)")
  public void restControllers() {}

  @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
  public void requestMappingAnnotations() {
  }

  @Around("restControllers() && requestMappingAnnotations()")
  public Object onExecute(ProceedingJoinPoint jp) throws Throwable {
    System.out.println(jp);
    Object result = null;
    try {
      result = jp.proceed();
    } catch (Exception ex) {
      throw ex;
    }
    return result;
  }
}

控制台日志显示:

execution(String de.scrum_master.app.A.getData(String))
bbb
execution(String de.scrum_master.app.A.getData(String))
aaa

你的情况有什么不同?

【讨论】:

  • 我错过了在 Around 建议中添加“restControllers()”。因此,Around 建议是 @Around("restControllers() && requestMappingAnnotations()"),它不起作用。现在更新了这个问题。谢谢
  • 在回答完问题后添加关键信息有点不理想,但我再次查看并更新了方面。如果您使用@target() 切入点指示符,它就可以工作。顺便说一句,我的驱动程序应用程序中还有一个小错字:System.out.println(b.getData("aaa")); 当然应该改为System.out.println(a.getData("aaa"));。对于无意义的类名,有时会发生这样的事情。
  • @kriegaex 您是否忘记在@Around 规范中包含restControllers() 切入点?在当前示例中,restControllers() 切入点已定义但从未使用过。
  • 感谢@RuslanStelmachenko 的反馈。接得好!这个问题有 2 年以上的历史了,我必须先在我的硬盘上找到它,奇怪的是,在我的示例项目中,切入点是正确的。我不知道为什么这里没有。我更新了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-16
  • 2012-09-21
  • 1970-01-01
相关资源
最近更新 更多