gpt4 book ai didi

java - 方面建议其他方面

转载 作者:行者123 更新时间:2023-12-01 19:55:00 27 4
gpt4 key购买 nike

我目前正在开发两个使用 Spring-AOP 的 Spring 应用程序。我有一个方面允许简单的性能日志记录,其定义如下:

@Aspect
final class PerformanceAdvice {
private Logger logger = LoggerFactory.getLogger("perfLogger");

public Object log(final ProceedingJoinPoint call) throws Throwable {
logger.info("Logging statistics.");
}
}

然后可以使用以下 XML 通过 Spring AOP 配置创建此建议:

<bean id="performanceAdvice" class="com.acme.PerformanceAdvice" />

<aop:config>
<aop:aspect ref="performanceAdvice">
<aop:around pointcut="execution(* com.acme..*(..))" method="log"/>
</aop:aspect>
</aop:config>

这对于 Spring 创建的类(例如用 @Service 注释的类)来说效果很好。但我希望这方面也能为辅助项目中的其他方面提供建议。我知道 Spring 不支持此功能,如 their docs 中所述。 :

In Spring AOP, it is not possible to have aspects themselves be the target of advice from other aspects. The @Aspect annotation on a class marks it as an aspect, and hence excludes it from auto-proxying.

因此我可能需要更强大的东西,例如AspectJ。或者是否有可能让 Spring 意识到这一点并仍然允许提供建议?从 StackOverflow 上的许多其他问题(与这个特定问题没有直接关系)中,我尝试制作方面 @Configurable,通过将它们定义为 @Component 使它们具有 Spring 感知能力。 code> 并尝试了各种 XML 和插件设置,例如:

<context:spring-configured />
<context:annotation-config/>
<context:load-time-weaver/>
<aop:aspectj-autoproxy/>

我现在没有主意了。我是否需要编写成熟的 AspectJ 方面?如果是这样,它是否可以使用相同的配置(例如 Spring),引用现有切面并定义新的切入点?这很有用,这样我就不必为 Project 1 重新编写 PerformanceAdvice,但仍然可以在 Project 2 中引用和使用它。

编辑关于 this comment :为了让自己更清楚,我有以下示例。

我在项目 2 中有一个服务。

@Service
public class TargetSpringServiceImpl implements TargetSpringService {
@Override
public String doSomeComplexThings(String parameter) {
return "Complex stuff";
}
}

当调用此方法时,我有一个方面进行一些验证。

@Aspect
public class ValidationAdvice {
@Autowired
ValidationService validationService

public void validate(JoinPoint jp) throws Throwable {
//Calls the validationService to validate the parameters
}
}

使用以下切入点作为执行:

<bean id="validationAdvice" class="com.acme.advice.ValidationAdvice" />

<aop:config>
<aop:aspect ref="validationAdvice">
<aop:before pointcut="execution(* com.acme.service..*(..))" method="validate"/>
</aop:aspect>
</aop:config>

我希望在 ValidationAdvicevalidate 上调用我的 PerformanceAdvicelog() 方法() 方法。 NOT 位于 TargetSpringService 类的 doSomeComplexThings() 方法上。因为这只是一个额外的切入点。问题出在建议另一个方面的方法上。

最佳答案

我已经找到了两种可能的解决方案来解决我的问题。一个实际上是在建议方面,另一个可以解决问题,但实际上更优雅。

解决方案 1:建议方面

AspectJ中,几乎可以编织任何东西。借助 AspectJ LTW documentation 中所述的 META-INF/aop.xml 文件,我可以通过以下方式引用切面并定义新的切入点。

对项目 1 的更改

性能建议

为了允许AspectJ定义一个新的切入点,建议必须是抽象并且有一个可以挂接到的抽象pointcut方法.

@Aspect
final class PerformanceAdvice extends AbstractPerformanceAdvice {
@Override
void externalPointcut(){}
}

@Aspect
public abstract class AbstractPerformanceAdvice {
private Logger logger = LoggerFactory.getLogger("perfLogger");

@Pointcut
abstract void externalPointcut();

@Around("externalPointcut()")
public Object log(final ProceedingJoinPoint call) throws Throwable {
logger.info("Logging statistics.");
}
}

对项目 2 的更改

META-INF/aop.xml

aop.xml 文件定义了一个名为 ConcretePerformanceAdvice 的新方面。它也扩展了 AbstractPerformanceAdvice,但定义了一个新的切入点。然后,在 AspectJ 中,IS 可以(与 Spring-AOP 不同) 定义另一个方面的切入点。

<aspectj>
<aspects>
<concrete-aspect name="com.example.project2.ConcretePerformanceAdvice" extends="com.example.project1.AbstractPerformanceAdvice">
<pointcut name="externalPointcut" expression="execution(* com.example.project2.ValidationAdvice.validate(..))"/>
</concrete-aspect>
</aspects>
<weaver options="-verbose"/>
</aspectj>

pom.xml

编织方面需要一些仪器。这需要依赖项和插件来执行它。至于依赖关系,如下:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>${org.springframework.version}</version>
</dependency>

目前,在测试过程中,我通过 surefire-plugin 进行检测。这需要以下部分:

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.8</version>
<configuration>
<forkMode>once</forkMode>
<argLine>
-javaagent:"${settings.localRepository}/org/springframework/spring-instrument/${org.springframework.version}/spring-instrument-${org.springframework.version}.jar"
</argLine>
<useSystemClassloader>true</useSystemClassloader>
</configuration>
</plugin>
</plugins>
</build>

Spring 上下文

要启用加载时编织,还需要激活编织。因此必须将以下内容添加到 Spring 上下文中。

<context:load-time-weaver/>

解决方案 2:委托(delegate)给 Spring bean

Spring-AOP 不允许方面向其他方面提供建议。但它确实允许在 Spring @Component 上运行建议。因此,另一个解决方案是将建议中完成的验证移至另一个 Spring bean。然后,这个 Spring bean 会 Autowiring 到通知中并执行,但是 PerformanceAdvice 的切入点位于验证组件上,而不是位于验证方面上。所以它看起来像下面这样:

对项目 1 的更改

没有!

对项目 2 的更改

该建议 Autowiring Spring @Component 并将其逻辑委托(delegate)给组件。

@Aspect
public class ValidationAdvice {
@Autowired
private ValidatorDefault validatorDefault;

public void validate(JoinPoint jp) throws Throwable {
validatorDefault.validate(jp);
}
}

@Component
public class ValidatorDefault {
@Autowired
ValidationService validationService

public void validate(JoinPoint jp) throws Throwable {
//Calls the validationService to validate the parameters
}
}

然后,在 Spring 上下文中,可以在 @Component 上定义切入点,同时 ValidationAdvice Autowiring @Component

<!-- Scan the package to find the ValidatorDefault component for autowiring -->
<context:component-scan base-package="com.example.project2" />

<bean id="validationAdvice" class="com.example.project2.ValidationAdvice" />
<bean id="performanceAdvice" class="com.example.project1.PerformanceAdvice" />

<aop:config>
<aop:aspect ref="validationAdvice">
<aop:before pointcut="execution(* com.acme.service..*.*(..))" method="validate"/>
</aop:aspect>
<aop:aspect ref="performanceAdvice">
<aop:around pointcut="execution(* com.example.project2.ValidatorDefault.validate(..))" method="log"/>
</aop:aspect>
</aop:config>

关于java - 方面建议其他方面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36030608/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com