- spring對AOP的實現(只有配置式)
前置通知(MethodBeforeAdvice)
後置通知(AfterReturingAdvice)
環繞通知(MethodInteceptor)
異常通知(ThrowsAdvice)
首先要導入支持AOP的兩個jar包
定義目標類
public class SomeServiceImpl implements IsomeService {
@Override
public void doSome() {
System.out.println("-----doSome方法執行!------"+1/0);
}
@Override
public String doOther() {
System.out.println("-----doOther方法執行!------");
return "xioabai";
}
}
主業務接口
public interface IsomeService {
//目標方法
public void doSome();
public String doOther();
}
定義切面類(通知類,這裏以後置通知爲例)
public class MyAfterReturingAdvice implements AfterReturningAdvice {
@Override
public void **afterReturning**(Object **returnValue**, Method method, Object[] args, Object target) throws Throwable {
if(returnValue!=null){
returnValue=returnValue.toString().toUpperCase();
}
System.out.println("-----後置通知-------"+returnValue);
}
}
在配置文件中註冊目標類
<!--註冊目標類 -->
<bean id="someServiceImpl" class="com.hxh.service.impl.SomeServiceImpl"></bean>
註冊切面:後置通知
<bean id="myMethodBeforeAdvice" class="com.hxh.aspect.MyMethodBeforeAdvice"></bean>
<!--後置通知-->
<bean id="myAfterReturingAdvice" class="com.hxh.aspect.MyAfterReturingAdvice"></bean>
註冊動態代理工廠ProxyFactoryBean(建立目標類和切面類的聯繫)
<bean id="proxyFactoryBean" class="**org.springframework.aop.framework.ProxyFactoryBean**">
<property name="**target**" ref="someServiceImpl"></property>
<property name="**interfaces**" value="com.hxh.service.IsomeService"></property>//可以不寫
<property name="**interceptorNames**" value="myThrowsAdvice"></property>
</bean>
客戶端訪問動態代理對象
public class TestStar {
@Test
public void testSpring(){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
IsomeService proxy = ac.getBean("**proxyFactoryBean**", IsomeService.class);
proxy.doSome();
String s=proxy.doOther();
System.out.println(s);
}
}
- AspectJ對AOP的實現(既支持配置式開發也支持註解式開發,可以指定時間點、切入點)
前置通知
後置通知
環繞通知
異常通知
最終通知(無論程序是否執行該通知都會執行,同try-catch-finally中finally的功能,常用於關閉資源)
在實現的過程中用到切入點表達式在此簡單介紹:
exection([modifiers-pattern]訪問權限
ret-type-pattern 返回值類型
[declaring-type-pattern] 全限定性類名
name-pattern(param-pattern)
[throws-pattern] 拋出異常類型)
切入點表達式要匹配的對象就是目標方法的方法名。所以,execution表達式中明顯就是方法的簽名。注意,表達式中加[ ]的部分表示可省略部分,各部分間用空格分開。在其中可以使用以下符號:
:0至多個任意字符
…:用在方法參數中,表示任意多個參數;用在包名後,表示當前包及其子包路徑
+:用在類名後,表示當前類及其子類;用在接口後,表示當前接口及其實現類
舉例:
execution(public * (…))
指定切入點爲:任意公共方法。
execution( set (…))
指定切入點爲:任何一個以"set"開始的方法。
execution( com.xyz.service..(…))
指定切入點爲:定義在service包裏的任意類的任意方法。
execution( com.xyz.service….(…))
指定切入點爲:定義在service包或者子包裏的任意類的任意方法。"…“出現在類名中時, 後面必須跟”",表示包、子包下的所有類。
execution( .service..(…))
指定只有一級包下的serivce子包下所有類(接口)中的所有方法爲切入點
execution( …service..*(…))
指定所有包下的serivce子包下所有類(接口)中的所有方法爲切入點
註解式
1.導入相應的jar包,引入AOP約束
2.編寫切面類MyAspect(用到@Aspect–類體上表明當前類是一個切面)
***@Aspect***
public class MyAspect {
//前置通知
***@Before("execution(* *..service.*.doSome(..))")***
public void before(){
System.out.println("-----前置通知-------");
}
//後置通知
**@AfterReturning(value="execution(* *..service.*.doOther(..))",*returning = "result"*)**
public void afterReturing(Object result){
if(result!=null){
result=result.toString().toUpperCase();
}
System.out.println("-----後置通知----"+result);
}
//環繞通知
***@Around("execution(* *..service.*.doOther(..))")***
public void aroud(ProceedingJoinPoint pjp){
try {
System.out.println("-----環繞通知--目標方法執行前---");
Object result = pjp.proceed();
System.out.println("-----環繞通知--目標方法執行後---"+result);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
//異常通知
**@AfterThrowing(value="execution(* *..service.*.doSome(..))",throwing ="ex")**
public void throwing(Exception ex){
System.out.println("----異常通知-------"+ex);
}
//最終通知
***@After("execution(* *..service.*.doSome(..))")***
public void after(){
System.out.println("-----最終通知------");
}
}```
3.配置文件中註冊切面
<bean id="myAspect" class="com.hxh.aspect.MyAspect"></bean>
4.註冊AOP自動代理
```
<aop:aspectj-autoproxy/>
```
5.測試類測試
public class TestStar {
@Test
public void testSpring(){
ApplicationContext ac = new ClassPathXmlApplicationContext(“spring.xml”);
IsomeService proxy = ac.getBean(“someServiceImpl”, IsomeService.class);
proxy.doSome();
String s=proxy.doOther();
System.out.println(s);
}
}
**配置式**
1.在配置文件中進行AOP配置
<aop:config>
<aop:aspect ref="切面類">
前置通知
<aop:before method="方法名" pointcut-ref=id>
<aop:pointcut id="唯一" expression="切入點表達式"
帶返回值的加一個
returning="方法中的參數">
<bean id="someServiceImpl" class="com.hxh.service.impl.SomeServiceImpl"></bean>
<bean id="myAspect" class="com.hxh.aspect.MyAspect"></bean>
<!--註冊AOP配置-->
<aop:config>
<aop:pointcut id="doSomePc" expression="execution(* *..service.*.doSome(..))"></aop:pointcut>
<aop:pointcut id="doOtherPc" expression="execution(* *..service.*.doOther(..))"></aop:pointcut>
<aop:aspect ref="myAspect">
<!--前置通知-->
<aop:before method="before" pointcut-ref="doSomePc"></aop:before>
<!--後置通知-->
<aop:after-returning method="afterReturing" pointcut-ref="doOtherPc" returning="result"></aop:after-returning>
<!--環繞通知-->
<aop:around method="around" pointcut-ref="doOtherPc"></aop:around>
<!--異常通知-->
<aop:after-throwing method="throwing" pointcut-ref="doSomePc" throwing="ex"></aop:after-throwing>
<!--最終通知-->
<aop:before method="after" pointcut-ref="doSomePc"></aop:before>
</aop:aspect>
</aop:config>
Spring、AspectJ和AOP的關係:
對於AOP這種編程思想,很多框架都進行了實現,Spring就是其中之一,可以完成面向切面編程。然而,AspectJ也實現了AOP的功能,且實現方式更爲便捷,使用更爲方便,而且還支持註解式開發。所以,spring又將AspectJ對於AOP的實現也引入到自己的框架中。
在Spring中使用AOP開發時,一般使用AspectJ的實現方式。