有没有一种方法可以在使用 spring AOP 执行某行代码后调用建议方法

Is there a way of calling an advice method after execution of certain line of code using spring AOP

为了日志目的,我一直在写 Aspect。现在我可以使用之前和之后的建议了。但是是否可以在执行某些业务逻辑后调用建议。这是我当前的代码,我想用建议替换我的代码。怎么做?

@ComponentScan
@EnableCaching
@EnableAutoConfiguration(exclude = {MetricFilterAutoConfiguration.class, MetricRepositoryAutoConfiguration.class})
public class Application {

    private final Logger log = LoggerFactory.getLogger(Application.class);

    @Inject
    private Environment env;

    @Inject
    private AppConfig appConfig;
    public void myBusinessLogicMethod(){
    if (myVariable == 0) {
                log.info("No Spring profile configured, running with default configuration");
                //rest of the business logic here
            } else {
                log.info("Running with number profile(s) : {}",myVariable);
    //           //rest of the business logic here
    
    }

我的看点class

@Aspect
@Order(0)
public class LoggingAspect {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Inject
    private HttpServletRequest request;

    @Inject
    private HttpServletResponse response;

    @Inject
    private Environment env;

    @Pointcut("(within(com.repository.*) || within(com.service.*) || "
            + "within(com.web.rest.*)) && "
            + "!@annotation(com.aop.logging.NoLogging)")
    public void loggingPoincut() {

    }

    @Before("within(com.web.rest.*) && "
            + "!@annotation(com.aop.logging.NoLogging)")
    public void beforeRest(JoinPoint point) throws UnknownHostException {
        String ipAddress = getIpAddress();
        if (log.isDebugEnabled()) {
            log.debug(">>>>>> From IP {}", isIpAvailble(ipAddress));
            log.debug("Enter: {}.{}() with argument[s] = {}", point.getSignature().getDeclaringTypeName(),
                    point.getSignature().getName(), Arrays.toString(point.getArgs()));
        }
    }

    @After("within(com.web.rest.*) && "
            + "!@annotation(com.aop.logging.NoLogging)")
    public void afterRest(JoinPoint point) throws UnknownHostException {
        if (log.isDebugEnabled()) {
            log.debug("Exit: {}.{}()", point.getSignature().getDeclaringTypeName(), point.getSignature()
                    .getName());
            log.debug("<<<<<< Rest Call Finished {} ", response.getStatus());
        }
    }
    
    }

如何用我方面的建议替换紧密耦合的日志 class。

简单的答案是:使用 Spring AOP,您可以拦截方法调用,而不是单行代码。即使可以,这也将是一场维护噩梦,因为方法中的代码经常更改。即使您有稳定的 API 个 public 方法,它们也是黑盒子,您(或您的一位同事)可以随时更改它们的内部实现。

但解决方案很简单:应用“清洁代码”原则(我希望你已经读过这本书或已经从其他来源了解软件工艺运动),即使用简短的方法,将更复杂的代码分解成更小的代码,可重用,命名良好且可维护的部件,复杂性低。将方法分解到日志记录所需的粒度级别,例如

public void myBusinessLogicMethod() {
  if (myVariable == 0)
    smallerBusinessLogicA(myVariable, someParameter);
  else
    smallerBusinessLogicB(myVariable);
}

然后使用您的日志切入点定位那些分解出的方法并记录它们的名称、参数 and/or 结果(无论您需要什么)。为了使其与 Spring AOP 一起使用,您需要注意

  • 将辅助方法分解为其他 Spring 组件 classes 因为 Spring AOP 不支持自调用拦截
  • 或者自我注入 bean,这样你就可以使用注入的 bean 调用辅助方法(即你使用 AOP 代理而不是真正的实现 class 下面对 AOP 一无所知)
  • 或从 Spring AOP 切换到完整的 AspectJ,它不使用代理并使用自调用。

SpringAOP和AspectJ的另一个区别是前者只能针对非私有方法,而AspectJ没有这种限制。