- 浏览: 216729 次
- 性别:
- 来自: 北京
文章分类
b]Introduction[/b]
AOP(面向且面的编程),是对传统的OOP的有力补充。
OOP中的核心部分是类。AOP中核心的部分是切面。
AOP是对IOC的有力补充。提供了许多声明式的企业服务。事务管理是最重要的一种服务。
AOP运行用户自定义切面,用切面去补充面向对象的编程。
AOP支持仅方法执行连接点。如果要执行属性执行或是修改可以考虑使用 AspectJ。
Spring的AOP是想提供一种AOP实现和IOC的整合以解决大部分企业应用中的问题。
AOP Proxy
Spring默认使用j2se的动态代理作为spring的aop代理。这使得任意一个接口都可以被代理。
spring也可以使用CGLIB proxies。这中代理方式对于类是必要的,而不是接口。
CGLIB默认是一个对象没有实现接口的情况下使用的。
@AspectJ support
@AspectJ refers to a style of declaring aspects as regular Java classes annotated with Java 5 annotations
@AspectJ是一种声明方法的形式,作为通常的java类,该java类使用java5的注释。
using a library supplied by AspectJ for pointcut parsing and matching
使用AspectJ提供的库对切点进行解析和匹配
@AspectJ Support
To use @AspectJ aspects in a Spring configuration you need to enable Spring support for configuring Spring AOP based on @AspectJ aspects
要想在spring配置文件中使用@AspectJ,你需要使得Spring支持基于@AspectJ的AOP配置。
autoproxying beans是基于他们是否被@AspectJ给advised。如果spring判断出一个bean是被一个或是多个@AspectJ注释,spring就会为该bean产生一个代理来拦截方法的调用。确保这个advice 按照所需要的那样去执行。
通过在配置文件中支持@AspectJ support :
<aop:aspectj-autoproxy/>
使用下面的方式也可以说是@AspectJ生效:
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
@AspectJ依赖的两个jar文件是:
aspectjweaver.jar and aspectjrt.jar
Declaring an aspect
配置文件中的定义形式
<bean id="myAspect" class="org.xyz.NotVeryUsefulAspect">
<!-- configure properties of aspect here as normal -->
</bean>
对应的类
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {
}
注:@Aspect可以有方法,成员变量想起他类一样,当然也可以含有切点,advice或是声明介绍等等。
Declaring a pointcut
@Pointcut("execution(* transfer(..))")// the pointcut expression
private void anyOldTransfer() {}// the pointcut signature
切点声明只支持方法的声明,包含两部分:一个由名字或是参数组成的签名和一个切点表达式决定在哪个方法执行。
the pointcut signature通常是由一个方法定义。
Spring的AOP支持AspectJ的切入点指示符。
execution:为了匹配方法执行的链接点,是aop最主要的指示符
within:限制匹配连接点
this:
target:
args:
Combining pointcut expressions
复杂的切入点表达式
Pointcut expressions can be combined using '&&', '||' and '!'. It is also possible to refer to pointcut expressions by name
切入点表达式可以使用&&或是||或是!,也可以通过名称引用一个切入点表达式。
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}
@Pointcut("within(com.xyz.someapp.trading..*)")
private void inTrading() {}
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {}
分享一下通常的切入点定义:
package com.xyz.someapp;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class SystemArchitecture {
/**
* A join point is in the web layer if the method is defined
* in a type in the com.xyz.someapp.web package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.web..*)")
public void inWebLayer() {}
/**
* A join point is in the service layer if the method is defined
* in a type in the com.xyz.someapp.service package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.service..*)")
public void inServiceLayer() {}
/**
* A join point is in the data access layer if the method is defined
* in a type in the com.xyz.someapp.dao package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.dao..*)")
public void inDataAccessLayer() {}
/**
* A business service is the execution of any method defined on a service
* interface. This definition assumes that interfaces are placed in the
* "service" package, and that implementation types are in sub-packages.
*
* If you group service interfaces by functional area (for example,
* in packages com.xyz.someapp.abc.service and com.xyz.def.service) then
* the pointcut expression "execution(* com.xyz.someapp..service.*.*(..))"
* could be used instead.
*
* Alternatively, you can write the expression using the 'bean'
* PCD, like so "bean(*Service)". (This assumes that you have
* named your Spring service beans in a consistent fashion.)
*/
@Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
public void businessService() {}
/**
* A data access operation is the execution of any method defined on a
* dao interface. This definition assumes that interfaces are placed in the
* "dao" package, and that implementation types are in sub-packages.
*/
@Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
public void dataAccessOperation() {}
}
也可以使用下面的这种方式:
<aop:config>
<aop:advisor
pointcut="com.xyz.someapp.SystemArchitecture.businessService()"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
spring的AOP的使用者更喜欢使用切入点表示,表达方式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
All parts except the returning type pattern (ret-type-pattern in the snippet above), name pattern, and parameters pattern are optional
除了返回类型,方法名称,参数名称,其余的部分都是可选的
ret-type-pattern:代表返回的类型,通常情况下你会拿*作为返回类型
name pattern:表示方法的名称,是匹配方法的名称。*表示任何方法名称
parameters pattern表示参数,..表示任意参数。0个或是多个。*匹配任意类型的一个参数。*,String匹配第一个参数是任意类型,第二个参数是String类型
实例:
执行任意public方法:
execution(public * *(..))//public对应modifiers-pattern是非必须的,第一个*表示方法可以是返回任何类型的。第二个*表示任意的方法名称,..表示任意的参数
执行任意以set开头的方法
execution(* set*(..))
执行指定接口下的任意方法
execution(* com.xyz.service.AccountService.*(..))
执行任意包下以及子包下的任意方法
execution(* com.xyz.service..*.*(..))
执行指定包下的任何类的任何方法
execution(* com.xyz.service.*.*(..))
执行指定包下的任何连接点
within(com.xyz.service.*)
执行指定包以及子包下的任意接入点
within(com.xyz.service..*)
代理实现AccountService接口的任意接入点
this(com.xyz.service.AccountService)
目标对象实现AccountService的任意接入点
target(com.xyz.service.AccountService)
Declaring advice
Adivce是和pointcut协作的。
在方法执行前,执行后,around method被切入点匹配。
Before advice
before advice在aspect 中使用 @Before
如:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
@before也可以配合切入点表达式使用,修改上面对应的代码为
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}
After returning advice
实例:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
一个Aspect中可以定义多个advice。
有时需要获取方法的返回值,并将该方法的返回值使用到@AfterReturning中,可以使用如下的形式。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
}
The name used in the returning attribute must correspond to the name of a parameter in the advice method
returning 属性使用的名称必须对应advice方法的参数名称。
After throwing advice
当advice作用的方法抛出异常时使用的。实例如下:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doRecoveryActions() {
// ...
}
}
获取抛出的异常:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
}
After (finally) advice
只要advice作用的方法被执行,最后会执行该advice下的方法,通常用于释放资源
实例如下:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@Aspect
public class AfterFinallyExample {
@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doReleaseLock() {
// ...
}
}
Around advice
Around advice有机会在方法的执行前或是执行后执行。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
}
注:@Around下的方法第一个参数必须是ProceedingJoinPoint ,调用ProceedingJoinPoint 的proceed();会让程序继续执行,因此才可以在方法的前面或是后面执行。
Access to the current JoinPoint
Any advice method may declare as its first parameter, a parameter of type org.aspectj.lang.JoinPoint (please note that around advice is required to declare a first parameter of type ProceedingJoinPoint, which is a subclass of JoinPoint. The JoinPoint interface provides a number of useful methods such as getArgs() (returns the method arguments), getThis() (returns the proxy object), getTarget() (returns the target object), getSignature() (returns a description of the method that is being advised) and toString() (prints a useful description of the method being advised). Please do consult the Javadocs for full details.
任意一个advice都可以声明一个参数,这个参数的类型是JoinPoint (请注意around advice需要被声明一个ProceedingJoinPoint类型的参数,该类型是JoinPoint的子类,JoinPoint 提供了一些有用的方法,如 getArgs()(返回方法的参数),getThis()(返回代理对象),getTarget() (返回目标对象),getSignature() (返回被签名的方法的描述))
Passing parameters to advice
实例:
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
"args(account,..)")
public void validateAccount(Account account) {
// ...
}
对应的另一种写法是:
@Pointcut("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
"args(account,..)")
private void accountDataAccessOperation(Account account) {}
@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {
// ...
}
Schema-based AOP support
基于schema的aop支持
Declaring an aspect
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
注:定义一个切面
Declaring a pointcut
<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
</aop:config>
对应的另一种写法,建议使用上面的这种
<aop:config>
<aop:pointcut id="businessService"
expression="com.xyz.myapp.SystemArchitecture.businessService()"/>
</aop:config>
在切面里声明切点:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
...
</aop:aspect>
</aop:config>
传递当前对象到advice方法中
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..)) && this(service)"/>
<aop:before pointcut-ref="businessService" method="monitor"/>
...
</aop:aspect>
</aop:config>
public void monitor(Object service) {
...
}
也可以不写&使用下面的方式:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..)) and this(service)"/>
<aop:before pointcut-ref="businessService" method="monitor"/>
...
</aop:aspect>
</aop:config>
Declaring advice
<aop:aspect id="beforeExample" ref="aBean">
<aop:before
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>
也可以不引用pointcut-ref,直接使用pointcut,如
<aop:aspect id="beforeExample" ref="aBean">
<aop:before
pointcut="execution(* com.xyz.myapp.dao.*.*(..))"
method="doAccessCheck"/>
...
</aop:aspect>
After returning advice
<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>
将对应的返回值传递到advice中
<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
returning="retVal"
method="doAccessCheck"/>
...
</aop:aspect>
public void doAccessCheck(Object retVal) {...
After throwing advice
<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
method="doRecoveryActions"/>
...
</aop:aspect>
传递异常信息到advice当中
<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
throwing="dataAccessEx"
method="doRecoveryActions"/>
...
</aop:aspect>
public void doRecoveryActions(DataAccessException dataAccessEx) {...
After (finally) advice
<aop:aspect id="afterFinallyExample" ref="aBean">
<aop:after
pointcut-ref="dataAccessOperation"
method="doReleaseLock"/>
...
</aop:aspect>
Around advice
<aop:aspect id="aroundExample" ref="aBean">
<aop:around
pointcut-ref="businessService"
method="doBasicProfiling"/>
...
</aop:aspect>
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
实例:
切面的定义:
package x.y;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
public class SimpleProfiler {
public Object profile(ProceedingJoinPoint call, String name, int age) throws Throwable {
StopWatch clock = new StopWatch(
"Profiling for '" + name + "' and '" + age + "'");
try {
clock.start(call.toShortString());
return call.proceed();
} finally {
clock.stop();
System.out.println(clock.prettyPrint());
}
}
}
配置文件的定义:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- this is the object that will be proxied by Spring's AOP infrastructure -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- this is the actual advice itself -->
<bean id="profiler" class="x.y.SimpleProfiler"/>
<aop:config>
<aop:aspect ref="profiler">
<aop:pointcut id="theExecutionOfSomeFooServiceMethod"
expression="execution(* x.y.service.FooService.getFoo(String,int))
and args(name, age)"/>
<aop:around pointcut-ref="theExecutionOfSomeFooServiceMethod"
method="profile"/>
</aop:aspect>
</aop:config>
</beans>
Advisors
<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<aop:advisor
pointcut-ref="businessService"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
完整实例:
public class ConcurrentOperationExecutor implements Ordered {
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
PessimisticLockingFailureException lockFailureException;
do {
numAttempts++;
try {
return pjp.proceed();
}
catch(PessimisticLockingFailureException ex) {
lockFailureException = ex;
}
}
while(numAttempts <= this.maxRetries);
throw lockFailureException;
}
}
<aop:config>
<aop:aspect id="concurrentOperationRetry" ref="concurrentOperationExecutor">
<aop:pointcut id="idempotentOperation"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<aop:around
pointcut-ref="idempotentOperation"
method="doConcurrentOperation"/>
</aop:aspect>
</aop:config>
<bean id="concurrentOperationExecutor"
class="com.xyz.myapp.service.impl.ConcurrentOperationExecutor">
<property name="maxRetries" value="3"/>
<property name="order" value="100"/>
</bean>
Notice that for the time being we assume that all business services are idempotent. If this is not the case we can refine the aspect so that it only retries genuinely idempotent operations, by introducing an Idempotent annotation:
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
// marker annotation
}
AOP(面向且面的编程),是对传统的OOP的有力补充。
OOP中的核心部分是类。AOP中核心的部分是切面。
AOP是对IOC的有力补充。提供了许多声明式的企业服务。事务管理是最重要的一种服务。
AOP运行用户自定义切面,用切面去补充面向对象的编程。
AOP支持仅方法执行连接点。如果要执行属性执行或是修改可以考虑使用 AspectJ。
Spring的AOP是想提供一种AOP实现和IOC的整合以解决大部分企业应用中的问题。
AOP Proxy
Spring默认使用j2se的动态代理作为spring的aop代理。这使得任意一个接口都可以被代理。
spring也可以使用CGLIB proxies。这中代理方式对于类是必要的,而不是接口。
CGLIB默认是一个对象没有实现接口的情况下使用的。
@AspectJ support
@AspectJ refers to a style of declaring aspects as regular Java classes annotated with Java 5 annotations
@AspectJ是一种声明方法的形式,作为通常的java类,该java类使用java5的注释。
using a library supplied by AspectJ for pointcut parsing and matching
使用AspectJ提供的库对切点进行解析和匹配
@AspectJ Support
To use @AspectJ aspects in a Spring configuration you need to enable Spring support for configuring Spring AOP based on @AspectJ aspects
要想在spring配置文件中使用@AspectJ,你需要使得Spring支持基于@AspectJ的AOP配置。
autoproxying beans是基于他们是否被@AspectJ给advised。如果spring判断出一个bean是被一个或是多个@AspectJ注释,spring就会为该bean产生一个代理来拦截方法的调用。确保这个advice 按照所需要的那样去执行。
通过在配置文件中支持@AspectJ support :
<aop:aspectj-autoproxy/>
使用下面的方式也可以说是@AspectJ生效:
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
@AspectJ依赖的两个jar文件是:
aspectjweaver.jar and aspectjrt.jar
Declaring an aspect
配置文件中的定义形式
<bean id="myAspect" class="org.xyz.NotVeryUsefulAspect">
<!-- configure properties of aspect here as normal -->
</bean>
对应的类
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {
}
注:@Aspect可以有方法,成员变量想起他类一样,当然也可以含有切点,advice或是声明介绍等等。
Declaring a pointcut
@Pointcut("execution(* transfer(..))")// the pointcut expression
private void anyOldTransfer() {}// the pointcut signature
切点声明只支持方法的声明,包含两部分:一个由名字或是参数组成的签名和一个切点表达式决定在哪个方法执行。
the pointcut signature通常是由一个方法定义。
Spring的AOP支持AspectJ的切入点指示符。
execution:为了匹配方法执行的链接点,是aop最主要的指示符
within:限制匹配连接点
this:
target:
args:
Combining pointcut expressions
复杂的切入点表达式
Pointcut expressions can be combined using '&&', '||' and '!'. It is also possible to refer to pointcut expressions by name
切入点表达式可以使用&&或是||或是!,也可以通过名称引用一个切入点表达式。
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}
@Pointcut("within(com.xyz.someapp.trading..*)")
private void inTrading() {}
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {}
分享一下通常的切入点定义:
package com.xyz.someapp;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class SystemArchitecture {
/**
* A join point is in the web layer if the method is defined
* in a type in the com.xyz.someapp.web package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.web..*)")
public void inWebLayer() {}
/**
* A join point is in the service layer if the method is defined
* in a type in the com.xyz.someapp.service package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.service..*)")
public void inServiceLayer() {}
/**
* A join point is in the data access layer if the method is defined
* in a type in the com.xyz.someapp.dao package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.dao..*)")
public void inDataAccessLayer() {}
/**
* A business service is the execution of any method defined on a service
* interface. This definition assumes that interfaces are placed in the
* "service" package, and that implementation types are in sub-packages.
*
* If you group service interfaces by functional area (for example,
* in packages com.xyz.someapp.abc.service and com.xyz.def.service) then
* the pointcut expression "execution(* com.xyz.someapp..service.*.*(..))"
* could be used instead.
*
* Alternatively, you can write the expression using the 'bean'
* PCD, like so "bean(*Service)". (This assumes that you have
* named your Spring service beans in a consistent fashion.)
*/
@Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
public void businessService() {}
/**
* A data access operation is the execution of any method defined on a
* dao interface. This definition assumes that interfaces are placed in the
* "dao" package, and that implementation types are in sub-packages.
*/
@Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
public void dataAccessOperation() {}
}
也可以使用下面的这种方式:
<aop:config>
<aop:advisor
pointcut="com.xyz.someapp.SystemArchitecture.businessService()"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
spring的AOP的使用者更喜欢使用切入点表示,表达方式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
All parts except the returning type pattern (ret-type-pattern in the snippet above), name pattern, and parameters pattern are optional
除了返回类型,方法名称,参数名称,其余的部分都是可选的
ret-type-pattern:代表返回的类型,通常情况下你会拿*作为返回类型
name pattern:表示方法的名称,是匹配方法的名称。*表示任何方法名称
parameters pattern表示参数,..表示任意参数。0个或是多个。*匹配任意类型的一个参数。*,String匹配第一个参数是任意类型,第二个参数是String类型
实例:
执行任意public方法:
execution(public * *(..))//public对应modifiers-pattern是非必须的,第一个*表示方法可以是返回任何类型的。第二个*表示任意的方法名称,..表示任意的参数
执行任意以set开头的方法
execution(* set*(..))
执行指定接口下的任意方法
execution(* com.xyz.service.AccountService.*(..))
执行任意包下以及子包下的任意方法
execution(* com.xyz.service..*.*(..))
执行指定包下的任何类的任何方法
execution(* com.xyz.service.*.*(..))
执行指定包下的任何连接点
within(com.xyz.service.*)
执行指定包以及子包下的任意接入点
within(com.xyz.service..*)
代理实现AccountService接口的任意接入点
this(com.xyz.service.AccountService)
目标对象实现AccountService的任意接入点
target(com.xyz.service.AccountService)
Declaring advice
Adivce是和pointcut协作的。
在方法执行前,执行后,around method被切入点匹配。
Before advice
before advice在aspect 中使用 @Before
如:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
@before也可以配合切入点表达式使用,修改上面对应的代码为
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}
After returning advice
实例:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
一个Aspect中可以定义多个advice。
有时需要获取方法的返回值,并将该方法的返回值使用到@AfterReturning中,可以使用如下的形式。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
}
The name used in the returning attribute must correspond to the name of a parameter in the advice method
returning 属性使用的名称必须对应advice方法的参数名称。
After throwing advice
当advice作用的方法抛出异常时使用的。实例如下:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doRecoveryActions() {
// ...
}
}
获取抛出的异常:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
}
After (finally) advice
只要advice作用的方法被执行,最后会执行该advice下的方法,通常用于释放资源
实例如下:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@Aspect
public class AfterFinallyExample {
@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doReleaseLock() {
// ...
}
}
Around advice
Around advice有机会在方法的执行前或是执行后执行。
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
}
注:@Around下的方法第一个参数必须是ProceedingJoinPoint ,调用ProceedingJoinPoint 的proceed();会让程序继续执行,因此才可以在方法的前面或是后面执行。
Access to the current JoinPoint
Any advice method may declare as its first parameter, a parameter of type org.aspectj.lang.JoinPoint (please note that around advice is required to declare a first parameter of type ProceedingJoinPoint, which is a subclass of JoinPoint. The JoinPoint interface provides a number of useful methods such as getArgs() (returns the method arguments), getThis() (returns the proxy object), getTarget() (returns the target object), getSignature() (returns a description of the method that is being advised) and toString() (prints a useful description of the method being advised). Please do consult the Javadocs for full details.
任意一个advice都可以声明一个参数,这个参数的类型是JoinPoint (请注意around advice需要被声明一个ProceedingJoinPoint类型的参数,该类型是JoinPoint的子类,JoinPoint 提供了一些有用的方法,如 getArgs()(返回方法的参数),getThis()(返回代理对象),getTarget() (返回目标对象),getSignature() (返回被签名的方法的描述))
Passing parameters to advice
实例:
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
"args(account,..)")
public void validateAccount(Account account) {
// ...
}
对应的另一种写法是:
@Pointcut("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
"args(account,..)")
private void accountDataAccessOperation(Account account) {}
@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {
// ...
}
Schema-based AOP support
基于schema的aop支持
Declaring an aspect
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
注:定义一个切面
Declaring a pointcut
<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
</aop:config>
对应的另一种写法,建议使用上面的这种
<aop:config>
<aop:pointcut id="businessService"
expression="com.xyz.myapp.SystemArchitecture.businessService()"/>
</aop:config>
在切面里声明切点:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
...
</aop:aspect>
</aop:config>
传递当前对象到advice方法中
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..)) && this(service)"/>
<aop:before pointcut-ref="businessService" method="monitor"/>
...
</aop:aspect>
</aop:config>
public void monitor(Object service) {
...
}
也可以不写&使用下面的方式:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..)) and this(service)"/>
<aop:before pointcut-ref="businessService" method="monitor"/>
...
</aop:aspect>
</aop:config>
Declaring advice
<aop:aspect id="beforeExample" ref="aBean">
<aop:before
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>
也可以不引用pointcut-ref,直接使用pointcut,如
<aop:aspect id="beforeExample" ref="aBean">
<aop:before
pointcut="execution(* com.xyz.myapp.dao.*.*(..))"
method="doAccessCheck"/>
...
</aop:aspect>
After returning advice
<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>
将对应的返回值传递到advice中
<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
returning="retVal"
method="doAccessCheck"/>
...
</aop:aspect>
public void doAccessCheck(Object retVal) {...
After throwing advice
<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
method="doRecoveryActions"/>
...
</aop:aspect>
传递异常信息到advice当中
<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
throwing="dataAccessEx"
method="doRecoveryActions"/>
...
</aop:aspect>
public void doRecoveryActions(DataAccessException dataAccessEx) {...
After (finally) advice
<aop:aspect id="afterFinallyExample" ref="aBean">
<aop:after
pointcut-ref="dataAccessOperation"
method="doReleaseLock"/>
...
</aop:aspect>
Around advice
<aop:aspect id="aroundExample" ref="aBean">
<aop:around
pointcut-ref="businessService"
method="doBasicProfiling"/>
...
</aop:aspect>
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
实例:
切面的定义:
package x.y;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
public class SimpleProfiler {
public Object profile(ProceedingJoinPoint call, String name, int age) throws Throwable {
StopWatch clock = new StopWatch(
"Profiling for '" + name + "' and '" + age + "'");
try {
clock.start(call.toShortString());
return call.proceed();
} finally {
clock.stop();
System.out.println(clock.prettyPrint());
}
}
}
配置文件的定义:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- this is the object that will be proxied by Spring's AOP infrastructure -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- this is the actual advice itself -->
<bean id="profiler" class="x.y.SimpleProfiler"/>
<aop:config>
<aop:aspect ref="profiler">
<aop:pointcut id="theExecutionOfSomeFooServiceMethod"
expression="execution(* x.y.service.FooService.getFoo(String,int))
and args(name, age)"/>
<aop:around pointcut-ref="theExecutionOfSomeFooServiceMethod"
method="profile"/>
</aop:aspect>
</aop:config>
</beans>
Advisors
<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<aop:advisor
pointcut-ref="businessService"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
完整实例:
public class ConcurrentOperationExecutor implements Ordered {
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
PessimisticLockingFailureException lockFailureException;
do {
numAttempts++;
try {
return pjp.proceed();
}
catch(PessimisticLockingFailureException ex) {
lockFailureException = ex;
}
}
while(numAttempts <= this.maxRetries);
throw lockFailureException;
}
}
<aop:config>
<aop:aspect id="concurrentOperationRetry" ref="concurrentOperationExecutor">
<aop:pointcut id="idempotentOperation"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<aop:around
pointcut-ref="idempotentOperation"
method="doConcurrentOperation"/>
</aop:aspect>
</aop:config>
<bean id="concurrentOperationExecutor"
class="com.xyz.myapp.service.impl.ConcurrentOperationExecutor">
<property name="maxRetries" value="3"/>
<property name="order" value="100"/>
</bean>
Notice that for the time being we assume that all business services are idempotent. If this is not the case we can refine the aspect so that it only retries genuinely idempotent operations, by introducing an Idempotent annotation:
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
// marker annotation
}
发表评论
-
spring事物注意事项
2012-02-27 17:57 1770------------------------------- ... -
利用spring实现Hession
2012-02-02 14:46 2930hession是一种轻量级的远程服务,hession是借助二进 ... -
利用spring实现RMI
2012-02-01 17:09 1239RMI是实现将服务暴露给 ... -
spring之定时调度
2012-01-30 18:20 1159在java2中完成定时调度是基于Timer(启动定时器)和Ti ... -
Spring集成hibernate
2011-12-23 18:12 894方式一:使用hibernate.cfg ... -
实现简单spring的IOC
2011-12-14 08:48 966Spring的IOC让被调用者从调用者中实例化解脱出来。而是通 ... -
Spring 杂文
2011-11-29 10:51 8791.配置文件转换成对应的注解形式 <bean id=&q ... -
Spring注解
2011-11-28 10:21 1525注解是一种元数据(描述数据的数据),本身并不具备任何功能,sp ... -
Spring事物
2011-11-24 18:00 1837Spring事物提供的好处: 1.Provides a con ... -
spring时间表达式
2011-11-10 10:27 1169Cron 表达式包括以下 7 个字段: 秒 ...
相关推荐
Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。这个"spring aop jar 包"包含了实现这一功能所需的类和接口,...
Spring AOP,全称为Aspect Oriented Programming,是面向切面编程的一种编程范式,它是对传统的面向对象编程(OOP)的一种补充。在OOP中,核心是对象,而在AOP中,核心则是切面。切面是关注点的模块化,即程序中的...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点问题,如日志、事务管理、安全性等。本示例将简要介绍如何在Spring应用中实现AOP,通过实际的...
3、对spring aop认识模糊的,不清楚如何实现Java 自定义注解的 4、想看spring aop 注解实现记录系统日志并入库等 二、能学到什么 1、收获可用源码 2、能够清楚的知道如何用spring aop实现自定义注解以及注解的逻辑...
Spring AOP 是一种面向切面编程的技术,它允许我们在不修改源代码的情况下,对应用程序的特定部分(如方法调用)进行增强。在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态...
Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许开发者在不修改源代码的情况下,通过插入切面来增强或改变程序的行为。在本教程中,我们将深入探讨Spring AOP的不同使用方法,包括定义切点、通知类型...
Spring AOP,全称Aspect-Oriented Programming(面向切面编程),是Spring框架的一个重要模块,它通过提供声明式的方式来实现面向切面编程,从而简化了应用程序的开发和维护。在Spring AOP中,我们无需深入到每个...
现在,我们回到主题——"springaop依赖的jar包"。在Spring 2.5.6版本中,使用Spring AOP通常需要以下核心jar包: - `spring-aop.jar`:这是Spring AOP的核心库,包含了AOP相关的类和接口。 - `spring-beans.jar`:...
Spring AOP 和 Spring IOC 是 Spring 框架的两个核心组件,它们对于任何基于 Java 的企业级应用开发都至关重要。Spring AOP(面向切面编程)允许开发者在不修改源代码的情况下,通过“切面”来插入新的行为或增强已...
面向切面编程(AOP)是一种编程范式,旨在将横切关注点(如日志、安全等)与业务逻辑分离,从而提高模块化。...利用Java反射机制和Spring AOP框架,开发者可以方便地实现AOP,从而提升代码的模块化和可维护性。
**Spring AOP 实现机制详解** Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许程序员在不修改源代码的情况下,通过“切面”来插入额外的业务逻辑,如日志、事务管理等。AOP的引入极大地提高了代码的...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它允许程序员在不修改源代码的情况下,通过在运行时插入额外的行为(如日志记录、性能监控等)来增强对象的功能。动态代理则是Spring AOP实现的核心技术之一...
### Spring AOP面向方面编程原理:AOP概念详解 #### 一、引言 随着软件系统的日益复杂,传统的面向对象编程(OOP)逐渐暴露出难以应对某些横切关注点(cross-cutting concerns)的问题。为了解决这一挑战,面向方面编程...
在讨论Spring AOP(面向切面编程)时,首先需要理解几个核心概念。Spring AOP 是Spring框架提供的一个功能模块,它允许开发者将横切关注点(cross-cutting concerns)从业务逻辑中解耦出来,通过在方法调用前后进行...
### Spring AOP 实现流程日志跟踪 #### 一、背景与目的 在现代软件开发过程中,为了确保系统的稳定性和可维护性,通常会引入非功能性的需求来增强应用程序的功能,比如日志记录、安全控制等。这些需求往往不是业务...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点,如日志、事务管理等。在Java应用中,AOP通过代理模式实现了切面编程,使得我们可以将业务逻辑...
### Spring AOP 入门详解 #### 一、Spring AOP 概述 Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的一个关键特性,它为开发者提供了在运行时动态添加代码(即横切关注点或切面)到已有...
Spring源码最难问题:当Spring AOP遇上循环依赖 Spring源码中最难的问题之一是循环依赖问题,当Spring AOP遇上循环依赖时,该如何解决? Spring通过三级缓存机制解决循环依赖的问题。 在Spring中,bean的实例化...
Spring AOP,即Spring的面向切面编程模块,是Spring框架的重要组成部分,它允许开发者在不修改源代码的情况下,对程序进行横切关注点的处理,如日志、事务管理等。实现这一功能,主要依赖于三个核心的jar包:aop...
在`springAop1`这个压缩包中,可能包含了一个简单的应用示例,展示了如何定义一个切面类,以及如何在该类中定义通知方法。例如,我们可能会看到一个名为`LoggingAspect`的类,其中包含了`@Before`注解的方法,用于在...