[英]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" })
然后該方面將立即工作。 但是看看你的建議方法,它有問題:
void
的@Around
建議,即只有將它應用於也返回void
的方法才有意義。 但是,您的目標方法會返回Fees
。 為了適應環繞通知中的任何返回類型,請將返回類型更改為Object
。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.