我目前正在开发两个使用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不支持他们的文档中所指出的:
在Spring AOP中,不可能使方面本身成为其他方面的建议目标。类上的@Aspect注释将其标记为一个方面,因此将其从自动代理中排除。
因此,我可能需要更强大的功能,例如AspectJ
。还是有可能使Spring意识到这一方面并仍然允许建议?从StackOverflow上的许多其他问题(与该特定问题没有直接关系)中,我尝试了制作方面@Configurable
,通过将它们定义为a并使它们具有Spring意识,@Component
并使用了各种XML和插件设置,例如:
<context:spring-configured />
<context:annotation-config/>
<context:load-time-weaver/>
<aop:aspectj-autoproxy/>
我的想法已经用完了。我是否需要写出完整的AspectJ
方面?如果是这样,它是否可以使用相同的配置(例如Spring),引用现有方面并定义新切入点?这将很有用,因此我不必重新编写PerformanceAdvice
for,Project 1
但仍可以参考并在中使用它Project 2
。
编辑此评论:为了使自己更清楚,我有以下示例。
我有一个服务Project 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>
我想在PerformanceAdvice
的log()
方法上调用ValidationAdvice
的validate()
方法。不在类的doSomeComplexThings()
方法上TargetSpringService
。因为这只是一个附加切入点。问题在于建议另一个方面的方法。
我已经找到了解决我的问题的两种可能的解决方案。一个实际上是在建议方面,另一个实际上是在解决问题,但实际上更优雅。
在AspectJ
有可能编织任何事情。借助于AspectJ LTW文档META-INF/aop.xml
中所述的文件,我可以通过以下方式引用该方面并定义一个新的切入点。
PerformanceAdvice
为了允许AspectJ
定义新的切入点,建议必须是abstract
并且具有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.");
}
}
META-INF/aop.xml
该aop.xml
文件定义了一个名为的新方面ConcretePerformanceAdvice
。它也扩展了AbstractPerformanceAdvice
,但定义了一个新的切入点。然后,在AspectJ
它IS可能(不像在弹簧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上下文中添加以下内容。
<context:load-time-weaver/>
Spring-AOP
不允许方面建议其他方面。但是它的确允许在春季运行建议@Component
。因此,另一种解决方案是将建议中完成的验证转移到另一个Spring bean。然后将这个Spring bean自动连接到通知中并执行,但是PerformanceAdvice
它在验证组件上而不是在验证方面具有切入点。因此,它看起来如下所示:
没有!
该建议会自动装配Spring@Component
并将其逻辑委托给组件。
@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
自动装配的同时定义切入点@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>
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句