AspectJ编程指南。
语言语义的部分。
下面给出一些通用切入点表达式的例子。
任何公共方法的执行:
execution(public * *(..))
任何一个名字以set
开始的方法的执行:
execution(* set*(..))
AccountService
接口定义的任意方法的执行
execution(* com.xyz.service.AccountService.*(..))
service
包中定义的任何方法的执行:
execution(* com.xyz.service.*.*(..))
在service
包或其子包中定义的任意方法的执行:
execution(* com.xyz.service..*.*(..))
在service
包中的任意连接点(在Spring AOP
中只是方法执行):
within(com.xyz.service.*)
在service
包或其子包中的任意连接点(在Spring AOP
中只是方法执行):
within(com.xyz.service..*)
实现了AccountService
接口的代理对象的任意连接点 (在Spring AOP中只是方法执行):
this(com.xyz.service.AccountService)
实现AccountService
接口的目标对象的任意连接点 (在Spring AOP中只是方法执行)
target(com.xyz.service.AccountService)
任何一个只接受一个参数,并且运行时所传入的参数是Serializable
接口的连接点(在Spring AOP中只是方法执行)
args(java.io.Serializable)
请注意在例子中给出的切入点不同于 execution(* *(java.io.Serializable))
: args
版本只有在动态运行时候传入参数是Serializable
时才匹配,而execution
版本在方法签名中声明只有一个 Serializable
类型的参数时候匹配。
目标对象中有一个 @Transactional
注解的任意连接点 (在Spring AOP中只是方法执行):
@target(org.springframework.transaction.annotation.Transactional)
任何一个目标对象声明的类型有一个 @Transactional
注解的连接点 (在Spring AOP中只是方法执行):
@within(org.springframework.transaction.annotation.Transactional)
执行方法带有@Transactional
注解的任何连接点(仅在Spring AOP中为方法执行) :
@annotation(org.springframework.transaction.annotation.Transactional)
任何一个只接受一个参数,并且运行时所传入的参数类型具有@Classified
注解的连接点(在Spring AOP中只是方法执行)
@args(com.xyz.security.Classified)
名为tradeService
:的Spring bean上的任何连接点(仅在Spring AOP中执行方法)
bean(tradeService)
任何一个在名字匹配通配符表达式*Service
的Spring bean之上的连接点 (在Spring AOP中只是方法执行):
bean(*Service)
javadoc。
在Spring中使用AspectJ进行domain object的依赖注入和Spring中其他的AspectJ切面注入域对象讨论了该库的内容以及如何使用它。使用Spring IoC来配置AspectJ的切面讨论了如何对通过AspectJ compiler织入的AspectJ切面进行依赖注入。最后, 在Spring应用中使用AspectJ加载时织入(LTW)介绍了使用AspectJ的Spring应用程序如何进行加载期织入(load-time weaving)。
readResolve()方法)。
在上一段中一个关键的阶段就是“inessence”。多数情况下,“ 当从一个新对象初始化返回之后”的精确语义很不错…这种语境下, “初始化之后”的意思是依赖将在对象被构造之后注入 - 这意味着在类的构造器块中依赖将不可用。如果你希望它能在构造器代码块执行 之前被注入,并从而在构造器中使用它, 那么你需要在@Configurable
接口声明上做类似的定义:
@Configurable(preConstruction = true)
为此,必须将带注释的类型与AspectJ编织器编织在一起。您可以使用构建时的Ant或Maven任务来执行此操作(例如,请参阅《 AspectJ开发环境指南》),也可以使用加载时编织(请参阅Spring Framework中的使用AspectJ进行加载时编织)。类AnnotationBeanConfigurerAspect
本身也需要Spring来配置(获得bean factory的引用,使用bean factory配置新的对象)。如果使用基于Java的配置,则可以将其添加@EnableSpringConfigured
到任何 @Configuration
类,如下所示:
@Configuration
@EnableSpringConfigured
public class AppConfig {
如果您更喜欢基于XML的配置,Spring context
名称空间 定义了一个方便的context:spring-configured
元素,您可以按如下方式使用它:
<context:spring-configured/>
在切面配置完成之前创建的@Configurable
对象实例会导致在log中留下一个warning,并且任何对于该对象的配置都不会生效。 举一个例子,一个Spring管理配置的bean在被Spring初始化的时候创建了一个domain object。 对于这样的情况,你需要定义bean属性中的”depends-on”属性来手动指定该bean依赖于configuration切面。
<bean id="myService"
class="com.xzy.myapp.service.MyService"
depends-on="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect">
</bean>
除非您真的想在运行时依赖它的语义,否则不要通过bean配置器方面来激活@Configurable处理。特别是,请确保不要在通过容器注册为常规Spring bean的bean类上使用@Configurable。这样做会导致两次初始化,一次是通过容器,一次是通过切面
JAVA注解的继承性。
类之上的一个@Transactional
注解为该类中任何 public操作的执行指定了默认的事务语义。
类内部方法上的一个@Transactional
注解会覆盖类注解(如果存在) 所给定的默认的事务语义。可以标注任何可见性的方法,包括私有方法。直接标注非公共方法是执行此类方法而获得事务划分的唯一方法。
从Spring Framework 4.2开始,spring-aspects
提供了类似的切面,为标准javax.transaction.Transactional
注释提供了完全相同的功能。检查 JtaAnnotationTransactionAspect
更多细节。
对于希望使用Spring配置和事务管理支持但又不想(或不能)使用注解的AspectJ程序员,spring-aspects.jar还包含抽象方面,您可以扩展这些抽象方面以提供自己的切入点定义。有关更多信息,请参见AbstractBeanConfigurerAspect
和 AbstractTransactionAspect
方面的资源。作为示例,以下摘录显示了如何编写切面来使用与完全限定的类名匹配的原型Bean定义来配置域模型中定义的对象的所有实例:
public aspect DomainObjectConfiguration extends AbstractBeanConfigurerAspect {
public DomainObjectConfiguration() {
setBeanWiringInfoResolver(new ClassNameBeanWiringInfoResolver());
protected pointcut beanCreation(Object beanInstance) :
initialization(new(..)) &&
CommonPointcuts.inDomainModel() &&
this(beanInstance);
LTW section of the AspectJ Development Environment Guide.
Spring框架为AspectJ LTW带来的价值在于能够对编织过程进行更精细的控制。“ Vanilla” AspectJ LTW是通过使用Java(5+)代理来实现的,该代理在启动JVM时通过指定VM参数来打开。 这种JVM范围的设置在一些情况下或许不错,但通常情况下显得有些粗颗粒。而用Spring的LTW能让你在per-ClassLoader
的基础上打开LTW, 这显然更加细粒度并且对“单JVM多应用”的环境更具意义(例如在一个典型应用服务器环境中一样)。
此外,在某些环境中,加载时编织,不需要对应⽤程序服务器的启动脚本进⾏任何修改,这些脚本需要添加javaagent:path/to/aspectjweaver.jar或(如本节后⾯所述)javaagent:path/to/spring-instrument.jar。开发⼈员配置应⽤ 程序上下⽂以启⽤加载时编织,⽽不是依赖通常负责部署配置(如启动脚本)的管理员。
AspectJ参考文档的LTW部分中进行了详细 说明。由于该aop.xml
文件是100%AspectJ,因此在此不再赘述
Spring提供的代理来启用检测(),则还需要:
spring-instrument.jar
Apache Tomcat
TomcatLoadTimeWeaver
Running in GlassFish (limited to EAR deployments)
GlassFishLoadTimeWeaver
Running in Red Hat’s JBoss AS or WildFly
JBossLoadTimeWeaver
Running in IBM’s WebSphere
WebSphereLoadTimeWeaver
Running in Oracle’s WebLogic
WebLogicLoadTimeWeaver
JVM started with Spring InstrumentationSavingAgent
(java -javaagent:path/to/spring-instrument.jar
)
InstrumentationLoadTimeWeaver
Fallback, expecting the underlying ClassLoader to follow common conventions (namely addTransformer
and optionally a getThrowawayClassLoader
method)
ReflectiveLoadTimeWeaver
请注意,该表仅列出LoadTimeWeavers
使用时自动检测到的DefaultContextLoadTimeWeaver
。您可以确切指定LoadTimeWeaver
要使用的实现。
要使用Java配置指定特定的LoadTimeWeaver,请实现该 LoadTimeWeavingConfigurer
接口并覆盖该getLoadTimeWeaver()
方法。以下示例指定一个ReflectiveLoadTimeWeaver
:
@Configuration
@EnableLoadTimeWeaving
public class AppConfig implements LoadTimeWeavingConfigurer {
@Override
public LoadTimeWeaver getLoadTimeWeaver() {
return new ReflectiveLoadTimeWeaver();
如果使用基于XML的配置,则可以将完全限定的类名指定为元素weaver-class
上属性的值<context:load-time-weaver/>
。同样,以下示例指定了ReflectiveLoadTimeWeaver
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:load-time-weaver
weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
</beans>
稍后可以使用众所周知的名称loadTimeWeaver从Spring容器中检索由配置定义和注册的LoadTimeWeaver。请记住,LoadTimeWeaver仅作为Spring的LTW基础结构添加一个或多个ClassFileTransformers
的机制而存在。实际 ClassFileTransformer
执行LTW的是ClassPreProcessorAgentAdapter
(从org.aspectj.weaver.loadtime
包中)类。有关更多详细信息,请参见ClassPreProcessorAgentAdapter
类的类级javadoc,因为实际上如何实现编织的细节不在本文档的讨论范围之内。
剩下要讨论的配置的最后一个属性:AspectjWeaving属性(如果使用XML,则为Aspectj-weaving)。此属性控制是否启用LTW。它接受三个可能值之一,如果属性不存在,则默认值为自动检测。下表总结了三个可能的值:
Annotation Value
XML Value
Explanation
ENABLED
AspectJ织入功能开启,切面将会在加载时适当时机被织入。
DISABLED
LTW功能关闭,不会在加载时织入切面。
AUTODETECT
autodetect
如果Spring LTW基础设施能找到至少一个META-INF/aop.xml
文件,那么AspectJ织入将会开启,否则关闭。此为默认值。
如前所述。具体而言,您无需修改JVM启动脚本即可添加 -javaagent:path/to/spring-instrument.jar
。
请注意,在JBoss上,您可能需要禁用应用程序服务器扫描,以防止它在应用程序实际启动之前加载类。一个快速的解决方法是将一个WEB-INF/jboss-scanning.xml
具有以下内容的文件添加到您的工件中:
<scanning xmlns="urn:jboss:scanning:1.0"/>