应用程序 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 项目。
就像我在评论中说的那样:
为什么你的方面模块中有整个 Spring 应用程序的依赖项?是不是有点过分了?每个其他想要使用你的方面库的模块都会得到大量的传递依赖。您应该隔离方面库并在两个应用程序中使用它。
但是如果我们暂时忽略这一点,你的相位应用应该没有问题。也许你在项目 B 中的主类是
com.akpanda.springmain.SpringmainApplication
,但你的方面在另一个基础包中,比如 com.akpanda.aop.LogAspect
。在这种情况下,它不会被组件扫描拾取。通过将其添加到您的应用程序类中很容易解决这个问题:
@ComponentScan(basePackages = { "com.akpanda.aop", "com.akpanda.springmain" })
然后该方面将立即工作。但是看你的建议方法,有问题:
@Around
的void
建议,也就是说,只有将它应用于也返回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() {}