日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

动态代理-AOP

發布時間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 动态代理-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目標接口:
public interface StudentService {//查詢全部public abstract List<Student> findAll() throws IOException;public void transfer(Integer outId, Integer inId, double money); }
  • AOP目標實現類:
@Service("studentService") public class StudentServiceImpl implements StudentService {@Overridepublic List<Student> findAll() throws IOException {System.out.println("查詢所有學生信息findAll...");return null;}@Overridepublic void transfer(Integer outId,Integer inId,double money){//1 張三的賬戶-1000元System.out.println("調用dao:張三("+outId+")的賬戶"+(-money)+"元");//2 李四的賬戶+1000元System.out.println("調用dao:李四("+inId+")的賬戶"+money+"元");}//接口中沒有該方法,不會被攔截public void show(){System.out.println("----------------");} }

注:代理的為接口對象,接口中沒有的方法,實現類自己的方法不會被增強

  • 通知類:
import org.aspectj.lang.ProceedingJoinPoint;//通知類,告訴spring在增強的前后需要做什么事 public class Advice {public void before(){//前置通知:開啟事務System.out.println("前置通知:開啟事務");}public void afterReturn(){//后置通知:提交事務System.out.println("后置通知:提交事務");}public void afterThrowable(){//異常通知:回滾事務System.out.println("異常通知:回滾事務");}public void after(){//最終通知:釋放資源System.out.println("最終通知:釋放資源");}// 環繞通知:是Spring給我們提供的一種手動調用目標對象方法或者其他通知方法的方式// spring在調用環繞通知方法時會傳遞一個封裝了目標方法的對象,叫做ProceedingJoinPointpublic Object around(ProceedingJoinPoint pjp){Object result =null;try {//前置通知before();//執行目標方法,相當于動態代理中的 result=method.invoke(...)result = pjp.proceed();//后置通知afterReturn();} catch (Throwable throwable) {//異常通知afterThrowable();throwable.printStackTrace();} finally {//最終通知after();}return result;} }

<3>xml文件配置AOP

1 配置目標對象,添加到spring容器中2 配置通知對象,添加到spring容器中3 配置切入點方法和通知方法織入過程,也就配置切面
  • 純XML配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><!--1.配置service--><bean id="studentService" class="com.itheima.service.impl.StudentServiceImpl"/><!--2.配置通知對象--><bean id="myAdvice" class="com.itheima.aop.Advice"/><!--3.配置AOP--><aop:config><!--3.1配置AOP切入點表達式[可放在任意位置]--><!--*空格代表void 方法名.*:.StudentServiceImpl.*:.方法名(..)方法參數, ..代表參數任意--><aop:pointcut id="pt" expression="execution(* com.itheima.service.impl.*.*(..))"/><!--<aop:pointcut id="pt" expression="execution(* com.itheima.service.impl.StudentServiceImpl.*(..))"/>--><!--3.2配置切面--><aop:aspect ref="myAdvice"><!--前置通知--><aop:before method="before" pointcut-ref="pt"/><!--后置通知--><aop:after-returning method="afterReturn" pointcut-ref="pt"/><!--異常通知--><aop:after-throwing method="afterThrowable" pointcut-ref="pt"/><!--最終通知--><aop:after method="after" pointcut-ref="pt"/><!--使用環繞通知--><!--<aop:around method="around" pointcut-ref="pt"/>--></aop:aspect></aop:config> </beans>
  • 注解配置:
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component;//通知類,告訴spring在增強的前后需要做什么事 @Component("advice") @Aspect//告知是一個切面類,掃描時會掃描它的注解//代替:<aop:aspect ref="advice"> public class Advice {@Pointcut("execution(* com.itheima.service.impl.*.*(..))")//id為方法名[首字母小寫]public void pt() {}//==注意:使用注解配置AOP,后置通知和異常通知會在最終通知之后調用, // 在spring-context的5.1.9版本中是這樣的,在更高的版本中可能得到了解決, // (5.2.6及以上版本解決了)。 // 但是我們可以使用環繞通知解決這個問題,推薦使用環繞通知。==**/* @Before("pt()")public void before(JoinPoint joinPoint) {Object[] args = joinPoint.getArgs();//前置通知:開啟事務System.out.println("前置通知:開啟事務"+args[0]);}*/ //兩種得到傳遞參數的方法 如果目標方法沒有傳參,則不執行@Before("execution(* com.itheima.service.impl.*.*(..))&&args(x)")public void before(int x) {//前置通知:開啟事務System.out.println("前置通知:開啟事務" + x);}@AfterReturning("pt()")public void afterReturn() {//后置通知:提交事務System.out.println("后置通知:提交事務");}@AfterThrowing("pt()")public void afterThrowable() {//異常通知:回滾事務System.out.println("異常通知:回滾事務");}@After("pt()")public void after() {//最終通知:釋放資源System.out.println("最終通知:釋放資源");}// 環繞通知:是Spring給我們提供的一種手動調用目標對象方法或者其他通知方法的方式// spring在調用環繞通知方法時會傳遞一個封裝了目標方法的對象,叫做ProceedingJoinPoint//@Around("pt()")public Object around(ProceedingJoinPoint pjp) {Object result = null;try {//前置通知//Object[] args = pjp.getArgs();//before();//執行目標方法,相當于動態代理中的 result=method.invoke(...)result = pjp.proceed();//后置通知afterReturn();} catch (Throwable throwable) {//異常通知afterThrowable();throwable.printStackTrace();} finally {//最終通知after();}return result;} }

注:
使用注解配置AOP,后置通知和異常通知會在最終通知之后調用,
在spring-context的5.1.9版本中是這樣的,在更高的版本中可能得到了解決,
(5.2.6及以上版本解決了)。
但是我們可以使用環繞通知解決這個問題,推薦使用環繞通知

  • 核心配置類代替XML
import org.springframework.context.annotation.*;@Configuration//表示代表替換applicationContext.xml的標識[可以不寫] @ComponentScan("com.itheima")//開啟Spring注解掃描 @EnableAspectJAutoProxy//開啟Spring的AOP注解支持 public class SpringConfig { }

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;} }

注:只可對單一實現類對象進行增強

總結

以上是生活随笔為你收集整理的动态代理-AOP的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。