簡體   English   中英

在 spring 啟動應用程序中集成 Spring AOP 作為 maven 依賴項

[英]Integrate Spring AOP as a maven dependency in a spring boot application

應用程序1:(包含AOP代碼。一個Spring啟動應用程序)

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>

Application 2: (Another spring boot application) 它對上面的Application 1有依賴,添加為maven依賴

pom.xml(應用2)

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

申請2主class

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

申請2的Controller class

@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 中創建 class,它就可以工作。 但在那種情況下,我有 10 個不同的項目需要復制。 我想將 AOP 代碼分離為一個模塊(另一個 spring 引導應用程序),並將其作為 maven 依賴項用於許多不同的 spring 引導項目。

就像我在評論中說的:

為什么你的方面模塊中有整個 Spring 應用程序的依賴項? 是不是有點過分了? 每個其他想要使用你的方面庫的模塊都會得到大量的傳遞依賴。 您應該隔離方面庫並在兩個應用程序中使用它。

但是,如果我們暫時忽略這一點,那么應用您的方面應該沒有任何問題。 也許您在項目 B 中的主要 class 是com.akpanda.springmain.SpringmainApplication ,但您的方面在另一個基礎 package 中,比如com.akpanda.aop.LogAspect 在這種情況下,它不會被組件掃描拾取。 通過將其添加到您的應用程序 class 中很容易解決這個問題:

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

然后該方面將立即工作。 但是看看你的建議方法,它有問題:

  1. 您正在使用返回void@Around建議,即只有將它應用於也返回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() {}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM