Spring AspectJ

x33g5p2x  于2021-03-14 发布在 其他  
字(4.1k)|赞(0)|评价(0)|浏览(71)

AspectJ
@AspectJ切面使用@Aspect注解配置,拥有@Aspect的任何bean将被Spring自动识别并运用的风格类似纯java注解的普通java类
Spring可以使用AspectJ来做切入点解析
AOP的运行仍旧是纯Spring AOP,对AspectJ的编辑器或者植入无依赖性
注解方式:

@Configuration
@EnableAspectJAutoProxy
public class AppConfig{
}

配置文件方式:
<aop:aspectj-autoproxy/>
@AspectJ切面使用@Aspect注解配置,拥有@Aspect的任何bean将被Spring自动识别并运用
用@Aspect注解的类可以有方法和字段,他们也可能包含切入点(pointcut),通知(Advice)和引入(introduction)声明
@Aspect注解是不能通过类路径自动检测发现的,所以要配合使用@Component注解或者在xml配置bean
eg:
xml配置bean

<bean id="myAspect" class="org.xyz.NotVeryUsefulAspect">
</bean>
@Aspect
public class NotVeryUsefulAspect{
}

@Component注解

@Aspect
@Component
public class NotVeryUsefulAspect{
}

pointcut(切入点)
一个切入点通过一个普通的方法定义来提供,并且切入点表达式使用@Pointcut注解,方法返回类型必须为void
定义一个名为‘anyOldTransfer’,这个切入点将匹配任何名为“transfer”的方法的执行

@Pointcut("execution(* transfer(..))")
private void anyOldTransfer(){
}


组合pointcut
切入点表达式可以通过&&、||和!进行组合,也可以通过名字引用切入点表达式
通过组合,可以建立更加复杂的切入点表达式

@Pointcut("execution(punlic * (..))")
private void anyPublicOperation(){
}
@Pointcut("within(com.xyz.someapp.trading..)")
private void inTrading(){
}
@Pointcut("anyPublicOperation() && inTrading() ")
private void tradingOperation(){
}

一个好多切入点应该要:
1.选择特定类型的连接点:execution,get,set,call,handler
2.确定连接点范围:within,withincode
3.匹配上下文:this,target,@annotation
Before advice

@Component
@Aspect
public class MoocAspect{
	@Before(execution(* com.imooc.aop.aspectj.biz.* Biz.* (..))")
    public void before(){
	}
}

PS:
com.imooc.aop.aspectj.biz.* Biz.* (..))
是在执行com.imooc.aop.aspectj包下以Biz结尾的类所有方法是匹配Advice
After returning advice

@Aspect
public class AfterReturningExample{
			@AfterReturning("com.xyz.SystemArchitecture.dataAccessOperation()")
    public void daAccessCheck(){
    }
}

有时需要在通知体内得到返回的实际值,可以使用@AfterReturning绑定返回值形式

@Aspect
public class AfterReturningExample{
	@AfterReturning(
    	pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
        returning="retVal")
    public void daAccessCheck(Object retVal){
    }
}

PS:
public void daAccessCheck(Object retVal)
Object为返回值,根据实际返回值类型填写

After throwing advice

@Aspect
public class AfterReturningExample{
			@AfterThrowing("com.xyz.SystemArchitecture.dataAccessOperation()")
    public void doRecoveryActions(){
    }
}

有时需要在通知体内得到返回的实际值,可以使用@AfterReturning绑定返回值形势

@Aspect
public class AfterThrowingExample{
	@AfterThrowing(
    	pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
        throwing="ex")
    public void doRecoveryActions(DataAccessException ex){
    }
}

After (finally) advice
最终通知必须准备处理正常和异常两种异常返回情况,它通常用于释放资源

@Aspect
public class AfterFinallyExample{
			@After("com.xyz.SystemArchitecture.dataAccessOperation()")
    public void doRecoveryLock(){
    }
}

Around advice
环绕通知使用@Around注释声明,通知方法的第一个参数必须是ProceedingJoinPoint类型
在通知内部调用ProceedingJoinPoint的proceedings()方法会导致执行真正的方法,传入一个Object[]对象,数组中的值将被作为参数传递给方法

@Aspect
public class AroundExample{
	@Around("com.xyz.SystemArchitecture.businessService()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{
    	Object retVal = pjp.proceed();
        return retVal;
    }
}

给advice传递参数
方法一:

@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() && args(account,..)")
public void validateAccount(Account account){
	//...
}

方法二:

@Poincyt("com.xyz.myapp.SystemArchitecture.dataAccessOperation() && args(account,..)")
private void accountDataAccessOperation(Account account){
}
@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account){
	//...
}

方法三:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable{
	AuditCode value();
}

方法四:
用于记录用了什么方法
或者判断方法加什么注解
或者获取方法的参数

@Before("com.xyz.lib.Pointcuts.anyPublicMethod() && @annotation(auditable)")
public void audit(Auditable auditable){
	AuditCode code  = auditable.value();
    //....
}

advice的参数以及泛型

public interface Sample<T>{
	void sampleGenericMethod(T param);
    void sampleGenericCollectionMethod(Collection<T> param);
}
@Before("execution(* ..Sample+.sampleGenericMethod(* )) && args (param)")
public void beforeSampleMethod(MyType param){
	//..
}
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(* )) && args (param)")
public void beforeSampleMethod(Collection<MyType> param){
	//....
}
上一篇:Spring AOP API
下一篇:Spring事务管理

相关文章