AspectJ:实现AOP的框架,Spring引入了它
AspectJ中常用的五種類型:
前置通知
後置通知
環繞通知
異常通知
最終通知:相當於try-catch中的finally
AspectJ的切入點表達式:加方括號表示可以省略,各部分用空格隔開
execution ( [ modifiers-pattern ] 訪問權限類型
ret-type-pattern 返回值類型
[declaring-type-pattern ] 全限定性類名
name-pattern(param-oattern) 方法名(參數名)
[throws-pattern] 拋出異常類型 )
在其中可以使用以下符號
符號 | 意義 |
* | 0至多個任意字符 |
.. | 用在方法參數中,表示任意多個參數;用在包名之後,表示當前包及其子包路徑 |
+ |
用在類名后,表示當前類及其子類
用在接口后,表示當前接口及其實現類
|
舉例:
execution(public**(..)) :public訪問權限 , *返回值任意 , *方法名任意 , ---->表示任public方法
execution(*set*(..)) : 任何一個以set開始的方法
execution(* *.service.*.*(..)) : 只有一級包下的service所有類(接口)中所有方法為切入點 com.service.myservice.doFirst()可以匹配 com.package.myservice.doFirst不能匹配
execution(* *..service.*.*(..)) : 表示service前面可以有多級包
AspectJ的开发环境 :
AspectJ jar
Spring整合AspectJ
引入AOP约束
AspectJ基于注解的AOP实现:
1)前置通知:
//表示当前类为切面
@Aspect
public class MyAspect {
//前置通知,AspectJ表达式
@Before("execution(* ISomeService.doFirst(..))")
public void before() {
System.out.println("前置通知方法");
}
@Before
public void before1(JoinPoint jp) { //jp表示执行过程中具体的切入点表达式
System.out.println("前置通知方法");
}
}
<bean id="someService" class="ISomeServiceImpl" />
<!-- 注册切面 -->
<bean id="myAspect" class="MyAspect"/>
<!-- AspectJ的自动代理 -->
<aop:aspectj-autoproxy/>
2)后置通知:
//后置通知
@AfterReturning("execution(* ISomeService.doSecond(..))")
public void After() {
System.out.println("后置通知");
}
//取得返回值
@AfterReturning(value="execution(* ISomeService.doSecond(..))", returning="result")
public void AfterReturning(String result) {
System.out.println("后置通知");
}
3)环绕通知:
@Around("execution(* ISomeService.doSecond(..))")
public Object surronding(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知before");
Object result = pjp.proceed();
System.out.println("环绕通知after");
return ((String)result).toUpperCase();
}
4)异常通知:
//异常通知
@AfterThrowing("execution(* ISomeService.doThird(..))")
public void afterThrowing() {
System.out.println("异常通知");
}
@AfterThrowing(value="execution(* ISomeService.doThird(..))",throwing="ex")
public void afterThrowing(Exception ex) {
System.out.println("异常通知");
System.out.println(ex.getMessage());
}
5)最终通知:
//最终通知
@org.aspectj.lang.annotation.After("execution(* ISomeService.doThird(..))")
public void after() {
System.out.println("最终通知方法");
}
定义切入点:
//定义切入点
@Pointcut("execution(* ISomeService.doThird(..))")
private void doThirdPointCut() {}
//异常通知,使用自定义切入点
@AfterThrowing("doThirdPointCut()")
public void afterThrowing1() {
System.out.println("异常通知");
}
AspectJ基于XML的AOP实现:
定义切入点:
<!-- AOP配置 -->
<aop:config>
<aop:pointcut expression="execution(* ISomeService.doFirst(..))" id="doFirstPointCut"/> //连接点表达式,配置连接点
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut-ref="doFirstPointCut"/> //myAspect类中的before方法 before织入到连接点中
</aop:aspect>
</aop:config>
1) 前置通知:
<!-- AOP配置 -->
<aop:config>
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut="execution(* ISomeService.doFirst(..))"/>
</aop:aspect>
</aop:config>
要想执行before重载方法,需要给出参数全限定性类名:
<aop:before method="before(org.aspectj.lang.JoinPoint)" pointcut="execution(* ISomeService.doFirst(..))"/>
2)后置通知:
<aop:after-returning method="After(java.lang.String)" pointcut-ref="doSecondPointCut" returning="result"/> //和方法的参数名一样
3)环绕通知:
<aop:around method="surronding" pointcut-ref="doSecondPointCut"/> //不需要添加ProceedingJoinPoint参数,因为参数是必须的
4)异常通知:
<aop:after-throwing method="afterThrowing(java.lang.Exception)" pointcut-ref="doThirdPointCut" throwing="ex"/>
5)最终通知:
<aop:after method="after" pointcut-ref="doThirdPointCut"/>