将 Spring AOP 作为 maven 依赖项集成到 spring boot 应用程序中

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

应用程序 1:(包含 AOP 代码。一个 Spring boot 应用程序)

LogAspect.Java

@Aspect
@Component
public class LogAspect {
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Pointcut("within(@org.springframework.stereotype.Repository *)"
            + " || within(@org.springframework.stereotype.Service *)"
            + " || within(@org.springframework.web.bind.annotation.RestController *)")
    public void springBeanPointcut() {}

    @Pointcut("within(com.akpanda.springmain..*)")
    public void applicationPackagePointcut() {}

    @Around("applicationPackagePointcut() && springBeanPointcut()")
    public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        CodeSignature c = (CodeSignature) joinPoint.getSignature();
        log.info("Enter: {}.{}() with ParameterName[s]= {} and argumentValue[s]= {}",
                joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(),
                Arrays.toString(c.getParameterNames()), Arrays.toString(joinPoint.getArgs()));
    }
}

pom.xml(应用一)

<groupId>com.akpanda</groupId>
  <artifactId>aop</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>aop</name>
  <description>Demo project for Spring Boot</description>
  <properties>
    <java.version>11</java.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

  </dependencies>

应用 2:(另一个 spring boot 应用) 它依赖于上面的应用程序 1,添加为 maven 依赖项

pom.xml(应用二)

<dependency>
    <groupId>com.akpanda</groupId>
    <artifactId>aop</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

应用程序的主要类 2

@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringmainApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringmainApplication.class, args);
    }
}

Application 2的控制器类

@RestController
public class FeesController {
    @Autowired
    private FeesCalculator feesCalculator;

    @RequestMapping(value = "/fees/caclulate", method = RequestMethod.GET)
    public Fees calculateFees() {
        return feesCalculator.calculateFees();
    }
}

现在当我运行应用程序 2 并命中端点

/费用/计算

,我希望在 maven 中添加的 aop 依赖项能够启动。 以及每当调用应用程序 2 的任何方法时调用的方法 logAround()。

如果我不将应用程序 1 添加为依赖项,而只是在应用程序 2 中创建包含方面和建议的类,它就可以工作。但在那种情况下,我有 10 个不同的项目需要复制。 我想将 AOP 代码分离为一个模块(另一个 spring boot 应用程序),并将其作为 maven 依赖项用于许多不同的 spring boot 项目。

java spring-boot aop spring-aop aspectj-maven-plugin
1个回答
2
投票

就像我在评论中说的那样:

为什么你的方面模块中有整个 Spring 应用程序的依赖项?是不是有点过分了?每个其他想要使用你的方面库的模块都会得到大量的传递依赖。您应该隔离方面库并在两个应用程序中使用它。

但是如果我们暂时忽略这一点,你的相位应用应该没有问题。也许你在项目 B 中的主类是

com.akpanda.springmain.SpringmainApplication
,但你的方面在另一个基础包中,比如
com.akpanda.aop.LogAspect
。在这种情况下,它不会被组件扫描拾取。通过将其添加到您的应用程序类中很容易解决这个问题:

@ComponentScan(basePackages = { "com.akpanda.aop", "com.akpanda.springmain" })

然后该方面将立即工作。但是看你的建议方法,有问题:

  1. 您正在使用一个返回
    @Around
    void
    建议,也就是说,只有将它应用于也返回
    void
    的方法才有意义。然而,您的目标方法返回
    Fees
    。为了适应环绕通知中的任何返回类型,将返回类型更改为
    Object
  2. around-advice 不返回任何东西,它也不
    proceed()
    到原始目标方法,返回它的结果。

你可以这样修复它:

  @Around("applicationPackagePointcut() && springBeanPointcut()")
  public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
    CodeSignature signature = (CodeSignature) joinPoint.getSignature();
    log.info("Enter: {}.{}() with ParameterName[s]= {} and argumentValue[s]= {}",
      signature.getDeclaringTypeName(), signature.getName(),
      Arrays.toString(signature.getParameterNames()), Arrays.toString(joinPoint.getArgs()));
    return joinPoint.proceed();
  }

或者,如果你的建议只记录,不修改方法参数或返回值,也不做任何异常处理,只需使用

@Before
通知,那么你又回到了
void
方法没有需要
proceed()
或声明
Throwable

  @Before("applicationPackagePointcut() && springBeanPointcut()")
  public void logBefore(JoinPoint joinPoint) {
    CodeSignature signature = (CodeSignature) joinPoint.getSignature();
    log.info("Enter: {}.{}() with ParameterName[s]= {} and argumentValue[s]= {}",
      signature.getDeclaringTypeName(), signature.getName(),
      Arrays.toString(signature.getParameterNames()), Arrays.toString(joinPoint.getArgs()));
  }

顺便说一句,您还可以使用

@within
而不是
within
来更简单地编写切入点:

  @Pointcut(
    "@within(org.springframework.stereotype.Repository)" +
    " || @within(org.springframework.stereotype.Service)" +
    " || @within(org.springframework.web.bind.annotation.RestController)"
  )
  public void springBeanPointcut() {}
© www.soinside.com 2019 - 2024. All rights reserved.