[英]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.