动态代理-AOP
1 什么是AOP?
- Aspect Oriented Programming的縮寫,面向切面編程,切面指定就是動態代理的方法,作用是在不改變業務層方法源代碼的基礎上對方法進行增強,底層使用的是動態代理技術,面向切面編程也可以理解成面向動態代理編程。
2 AOP相關概念
- Target(目標對象):被代理的對象就是目標對象
- Proxy(代理對象):被增強后的對象就是代理對象
- Joinpoint(連接點):就是目標對象中所有被攔截到的方法
- Pointcut(切入點):就是目標對象中被增強的方法
- Advice(通知):執行目標方法之前或者之后調用的方法就是通知
- Aspect(切面):通知方法和切入點方法結合所在的位置叫做切面
- Weaving(織入):通知方法和切入點方法結合的過程,織入之后的結果就是切面
總結一下:
連接點是所有被攔截到的方法,切入點是所有被增強的方法,連接點不一定是切入點,但是切入點一定是連接點。在執行目標對象方法之前或者之后要做的事叫做通知,通知中有增強的業務。將切入點和通知組織到一起叫織入,織入形成的結果就是切面。
3 AOP配置實現步驟
<1>【第一步】導入相關依賴:spring-context、aspectjweaver
<!--spring核心依賴--> <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.9.RELEASE</version> </dependency> <!--切入點表達式依賴,作用:通過表達式找到哪些方法需要增強,也就是找到切入點--> <dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version> </dependency><2>【第二步】定義通知類和目標對象
- AOP目標接口:
- AOP目標實現類:
注:代理的為接口對象,接口中沒有的方法,實現類自己的方法不會被增強
- 通知類:
<3>xml文件配置AOP
1 配置目標對象,添加到spring容器中2 配置通知對象,添加到spring容器中3 配置切入點方法和通知方法織入過程,也就配置切面- 純XML配置:
- 注解配置:
注:
使用注解配置AOP,后置通知和異常通知會在最終通知之后調用,
在spring-context的5.1.9版本中是這樣的,在更高的版本中可能得到了解決,
(5.2.6及以上版本解決了)。
但是我們可以使用環繞通知解決這個問題,推薦使用環繞通知
- 核心配置類代替XML
4.底層動態代理類似原理[studentService動態代理工廠]
package com.itheima.proxy; import com.itheima.aop.Advice; import com.itheima.service.StudentService; import com.itheima.service.impl.StudentServiceImpl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;public class StudentServiceProxyFactory {public static StudentService createStudentServiceProxy() {Advice advice = new Advice();//1.創建真實對象StudentService studentService = new StudentServiceImpl();//可采用set注入//2.創建代理對象/**ClassLoader loader,創建代理對象的class對象Class<?>[] interfaces,告訴代理對象要和目標對象實現相同的接口,就具有相同的功能。InvocationHandler h,處理增強的邏輯*/ClassLoader classLoader = studentService.getClass().getClassLoader();Class<?>[] interfaces = studentService.getClass().getInterfaces();//獲取所有的直接實現的接口StudentService service = (StudentService) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {/*** @param proxy 代理對象* @param method 調用代理對象的方法,findAll、findById、transfer、update。。。* @param args 調用代理對象方法傳遞進來的參數們* @return 此處的返回值將返回給調用處* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;if (method.getName().equals("transfer") || method.getName().equals("delete")) {try {//1.開啟事務advice.before();//2.執行操作,調用目標方法result = method.invoke(studentService, args);//3.提交事務advice.afterReturn();} catch (Exception e) {e.printStackTrace();//4.如果有異常則回滾事務advice.afterThrowable();} finally {//5.釋放資源advice.after();}} else {//執行操作,調用目標方法result = method.invoke(studentService, args);}return result;}});return service;} }注:只可對單一實現類對象進行增強
總結
- 上一篇: 自定义通配器导入bean对象
- 下一篇: AOP切点表达式及通知类参数传递方式