spring02-10.16-AOP
2.AOP:面向方面程式設計
一個普通的類 -> 有特定功能的類
a.繼承類 b.實現介面 c.註解 d.配置
類 -> “通知” :實現介面
前置通知實現步驟:
a.jar
aopaliance.jar
aspectjweaver.jar
b.配置
c.編寫
aop:每當之前add()之前自動執行一個方法log();
addStudent(); 業務方法(IStudentService.java中的addStudent())
before(); 自動執行的通知,即aop前置通知
<bean id="studentDao" class="org.lanqiao.dao.impl.StudentDaoImpl">
</bean>
<!-- 配置前置通知 -->
<!-- addStudent()所在方法 -->
<bean id="studentService" class="org.lanqiao.service.impl.StudentServiceImpl">
<property name="studentDao" ref="studentDao"></property>
</bean>
<!-- “前置通知”類 -->
<!-- =========連線線的一方========= -->
<bean id="logBefore" class="org.lanqiao.aop.LogBefore">
</bean>
<!-- 將addStudent()和通知進行關聯 -->
<aop:config>
<!-- 配置切入點(在哪裡執行通知 ) -->
<!-- =========連線線的另一方========= -->
<aop:pointcut expression="execution(public void org.lanqiao.service.impl.StudentServiceImpl.deleteStudentByNo(int)) or execution(public * org.lanqiao.service.impl.StudentServiceImpl.addStudent(..))" id="poioncut"/>
<!-- advisor:相當於連結切入點和切面的線 -->
<!-- =========連線線========= -->
<aop:advisor advice-ref="logBefore" pointcut-ref="poioncut"/>
</aop:config>
如果出現異常:類似java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool,則說明缺少jar
public static void testAop() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml") ;
IStudentService studentService = (IStudentService)context.getBean("studentService") ;
Student student = new Student();
student.setStuAge(23);
student.setStuName("zs");
studentService.addStudent(student);
studentService.deleteStudentByNo(1);
}
後置通知:
a.通知類 -> 普通實現介面
b.業務類、業務方法
StudentServiceImpl中的addStudent()
c.配置:
將業務類、通知納入springIOC容器
定義切入點(一端)、定義通知類(另一端),通過pointcut-ref將兩端連線起來
public class LogAfter implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("**********後置通知:目標物件:"+target+",呼叫的方法名:"+method.getName()+",方法的引數個數:"+args.length+",方法的返回值:"+returnValue);
}
}
<!-- 將通知納入springIOC容器 -->
<bean id="logAfter" class="org.lanqiao.aop.LogAfter"></bean>
<aop:config>
<!-- 切入點(連線線的一端:業務類的具體方法) -->
<aop:pointcut expression="execution(public * org.lanqiao.service.impl.StudentServiceImpl.addStudent(..))" id="poioncut2"/>
<!-- (連線線的另一端:通知類) -->
<aop:advisor advice-ref="logAfter" pointcut-ref="poioncut2" />
</aop:config>
異常通知:
根據異常通知介面的定義可以發現,異常通知的實現類必須編寫以下方法:
public void afterThrowing([Method, args, target], ThrowableSubclass):
a.public void afterThrowing(Method, args, target, ThrowableSubclass)
b.public void afterThrowing( ThrowableSubclass)
<bean id="logException" class="org.lanqiao.aop.LogException"></bean>
<aop:config>
<!-- 切入點(連線線的一端:業務類的具體方法) -->
<aop:pointcut expression="execution(public * org.lanqiao.service.impl.StudentServiceImpl.addStudent(..))" id="poioncut3"/>
<!-- (連線線的另一端:通知 類) -->
<aop:advisor advice-ref="logException" pointcut-ref="poioncut3" />
</aop:config>
環繞通知:
在目標方法的前後、異常發生時、最終等各個地方都可以進行的通知,最強大的一個通知;
可以獲取目標方法的全部控制權(目標方法是否執行、執行之前、執行之後、引數、返回值等)
在使用環繞通知時,目標方法的一切資訊都可以通過invocation引數獲取到
環繞通知底層是通過攔截器實現的。
public class LogAround implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result = null ;
//方法體1...
try {
//方法體2...
System.out.println("用環繞通知實現的[前置通知]...");
// invocation.proceed() 之前的程式碼:前置通知
result = invocation.proceed() ;//控制著目標方法的執行,addStudent()
//result就是目標方法addStudent()方法的返回值
//invocation.proceed() 之後的程式碼:後置通知
System.out.println("用環繞通知實現的[後置通知]...:");
System.out.println("-----------------目標物件target"+invocation.getThis()+",呼叫的方法名:"+invocation.getMethod().getName()+",方法的引數個數:"+invocation.getArguments().length+",返回值:"+result);
}catch(Exception e) {
//方法體3...
//異常通知
System.out.println("用環繞通知實現的[異常通知]...");
}
return result;//目標方法的返回值
}
}
<!-- 將環繞通知加入ioc容器 -->
<bean id="logAround" class="org.lanqiao.aop.LogAround">
</bean>
<aop:config>
<!-- 切入點(連線線的一端:業務類的具體方法) -->
<aop:pointcut expression="execution(public * org.lanqiao.service.impl.StudentServiceImpl.addStudent(..))" id="poioncut4"/>
<!-- (連線線的另一端:通知 類)-->
<aop:advisor advice-ref="logAround" pointcut-ref="poioncut4" />
</aop:config>
二、實現註解實現通知
a.jar
與實現介面的方式相同
b.配置
將業務類、通知納入springIOC容器
開啟註解對AOP的支援<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
業務類addStudent - 通知
c.編寫
通知:
@Aspect //宣告該類是一個通知
public class LogBeforeAnnotation {
}
注意:通過註解形式將物件增加到ioc容器時,需要設定掃描器
<context:component-scan base-package="org.lanqiao.aop"></context:component-scan>
掃描器會將指定的包中的@Componet @Service @Respository @Controller修飾的類產生的物件增加到IOC容器中
@Aspect不需要加入掃描器,只需要開啟即可:
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
通過註解形式實現的aop,如果想獲取目標物件的一些引數,則需要使用一個物件:JointPoint
註解形式的返回值:
a.宣告返回值的引數名:
@AfterReturning( pointcut= “execution(public * addStudent(…))” ,returning=“returningValue” )
public void myAfter(JoinPoint jp,Object returningValue) {//returningValue是返回值,但需要告訴spring
System.out.println(“返回值:”+returningValue );
註解形式實現aop時,通知的方法的引數不能多、少
實現介面形式、註解形式只捕獲宣告的特定型別的異常,而其他型別異常不捕獲。
cath()
三、通過配置將類->通知
基於Schema配置
類似與實現介面的方式
介面方式通知:public class LogAfter implements AfterReturningAdvice
Schema方式通知:
a.編寫一個普通類 public class LogAfter {}
b.將該類通過配置,轉為一個“通知”
如果要獲取目標物件資訊:
註解、schema:JoinPoint
介面:Method method, Object[] args, Object target
schema形式和註解形式相似,不同之處:註解形式使用了註冊@After,schmema形式進行了多餘的配置