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