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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

spring面向AOP之动态代理

發布時間:2024/8/23 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 spring面向AOP之动态代理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

動態代理中有兩個重要的接口,一個是InvocationHandle,另一個是Proxy。
分別來說明這兩個接口的作用吧!
InvocationHandle接口
java.lang.reflect.InvocationHandler

InvocationHandler 是代理實例的調用處理程序 實現的接口。每個代理實例都具有一個關聯的調用處理程序。對代理實例調用方法時,將對方法調用進行編碼并將其指派到它的調用處理程序的 invoke 方法。簡單來說invoke就是在在代理實例上處理方法調用并返回結果。

invoke方法介紹:

參數:
proxy - 在其上調用方法的代理實例也就是該參數是代理的真實對象
method - 對應于在代理實例上調用的接口方法的 Method 實例。Method 對象的聲明類將是在其中聲明方法的接口,該接口可以是代理類賴以繼承方法的代理接口的超接口。
args - 包含傳入代理實例上方法調用的參數值的對象數組,如果接口方法不使用參數,則為 null。基本類型的參數被包裝在適當基本包裝器類(如 java.lang.Integer 或 java.lang.Boolean)的實例中。
返回:
從代理實例的方法調用返回的值。如果接口方法的聲明返回類型是基本類型,則此方法返回的值一定是相應基本包裝對象類的實例;否則,它一定是可分配到聲明返回類型的類型。如果此方法返回的值為 null 并且接口方法的返回類型是基本類型,則代理實例上的方法調用將拋出 NullPointerException。否則,如果此方法返回的值與上述接口方法的聲明返回類型不兼容,則代理實例上的方法調用將拋出 ClassCastException。
拋出:
Throwable - 從代理實例上的方法調用拋出的異常。該異常的類型必須可以分配到在接口方法的 throws 子句中聲明的任一異常類型或未經檢查的異常類型 java.lang.RuntimeException 或 java.lang.Error。如果此方法拋出經過檢查的異常,該異常不可分配到在接口方法的 throws 子句中聲明的任一異常類型,代理實例的方法調用將拋出包含此方法曾拋出的異常的 UndeclaredThrowableException。

invoke代碼實例

} /* 1 proxy,該參數是代理的真實對象 2 method,該參數是代理的方法 3 代理方法中接受的參數 */public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("初始化");Object invoke = method.invoke(us, args);System.out.println("執行完畢");return invoke;}

Proxy接口
java.lang.reflect.Proxy

Proxy 提供用于創建動態代理類和實例的靜態方法,它還是由這些方法創建的所有動態代理類的超類。

Proxy.newProxyInstance方法: public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序。此方法相當于: Proxy.getProxyClass(loader, interfaces).getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { handler });Proxy.newProxyInstance 拋出 IllegalArgumentException,原因與 Proxy.getProxyClass 相同。 參數: loader - 定義代理類的類加載器 interfaces - 代理類要實現的接口列表 h - 指派方法調用的調用處理程序 返回: 一個帶有代理類的指定調用處理程序的代理實例,它由指定的類加載器定義,并實現指定的接口

代碼實例:

定義一個代理的接口和類: package com.proxy;public interface UserService {void Run(); } package com.proxy; 接口的實現類: public class UserServiceImpl implements UserService {public void Run() {System.out.println("運行啦!");}} 動態代理類: package com.proxy;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;public class UserServiceProxyFactory implements InvocationHandler{public UserService us;public UserServiceProxyFactory(UserService us){this.us=us;}public UserService getProxyUserServiceInstance(){UserService newProxyInstance = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), this);return newProxyInstance;} /* 1 proxy,該參數是代理的真實對象 2 method,該參數是代理的方法 3 代理方法中接受的參數 */public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("初始化");Object invoke = method.invoke(us, args);System.out.println("執行完畢");return invoke;} }測試類: package com.proxy;import org.junit.Test;public class UserServiceDemo {@Testpublic void run(){UserService us = new UserServiceImpl();us.Run();UserServiceProxyFactory proxy = new UserServiceProxyFactory(us);us = proxy.getProxyUserServiceInstance();us.Run();} }

但是在Spring中已容器已經幫我們封裝好了方法,只需要配置注解就可以實現如上動態代理

方法一、xml配置
1.導包 (4+2) spring的aop包有兩個需要用到:aop、aspect(lib目錄下的包) Spring需要第三方的AOP包(在依賴包目錄下)com.springsource.org.aopalliance、和com.springsource.org.aspectj.weaver目錄下的包
2.準備目標對象

接口和實現類

package cn.itcast.service;public interface UserService {void save();void delete();void update();void find(); } package cn.itcast.service;public class UserServiceImpl implements UserService {@Overridepublic void save() {System.out.println("保存用戶!");//int i = 1/0;}@Overridepublic void delete() {System.out.println("刪除用戶!");}@Overridepublic void update() {System.out.println("更新用戶!");}@Overridepublic void find() {System.out.println("查找用戶!");} }

3.準備通知

package cn.itcast.e_annotationaop;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut;//通知類 @Aspect //表示該類是一個通知類 public class MyAdvice {//如果我們不想每次@Around("execution(* cn.itcast.service.*ServiceImpl.*(..))")這樣引入方法,我們可以把方法放入切點,然后切點注解在自己新添加的一個方法上,這樣只需要@Arround(MyAdvice.pc())就會去加載方法@Pointcut("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void pc(){}//前置通知//指定該方法是前置通知,并制定切入點@Before("MyAdvice.pc()")public void before(){System.out.println("這是前置通知!!");}//后置通知@AfterReturning("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void afterReturning(){System.out.println("這是后置通知(如果出現異常不會調用)!!");}//環繞通知@Around("execution(* cn.itcast.service.*ServiceImpl.*(..))")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("這是環繞通知之前的部分!!");Object proceed = pjp.proceed();//調用目標方法System.out.println("這是環繞通知之后的部分!!");return proceed;}//異常通知@AfterThrowing("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void afterException(){System.out.println("出事啦!出現異常了!!");}//后置通知@After("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void after(){System.out.println("這是后置通知(出現異常也會調用)!!");} }

4.配置進行織入,將通知織入目標對象中

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd "><!-- 準備工作: 導入aop(約束)命名空間 --> <!-- 1.配置目標對象 --><bean name="userService" class="cn.itcast.service.UserServiceImpl" ></bean> <!-- 2.配置通知對象 --><bean name="myAdvice" class="cn.itcast.d_springaop.MyAdvice" ></bean> <!-- 3.配置將通知織入目標對象 --><aop:config><!-- 配置切入點:expression中的表達式表示目標對象userServiceImpl的save方法public void cn.itcast.service.UserServiceImpl.save() void cn.itcast.service.UserServiceImpl.save()* cn.itcast.service.UserServiceImpl.save()* cn.itcast.service.UserServiceImpl.*()* cn.itcast.service.*ServiceImpl.*(..)* cn.itcast.service..*ServiceImpl.*(..)--><aop:pointcut expression="execution(* cn.itcast.service.*ServiceImpl.*(..))" id="pc"/><aop:aspect ref="myAdvice" ><!-- 指定名為before方法作為前置通知 --><aop:before method="before" pointcut-ref="pc" /><!-- 后置 --><aop:after-returning method="afterReturning" pointcut-ref="pc" /><!-- 環繞通知 --><aop:around method="around" pointcut-ref="pc" /><!-- 異常攔截通知 --><aop:after-throwing method="afterException" pointcut-ref="pc"/><!-- 后置 --><aop:after method="after" pointcut-ref="pc"/></aop:aspect></aop:config> </beans>

5.測試類以及結果

package cn.itcast.e_annotationaop;import javax.annotation.Resource;import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import cn.itcast.bean.User; import cn.itcast.service.UserService; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:cn/itcast/e_annotationaop/applicationContext.xml") public class Demo {@Resource(name="userService")private UserService us;@Testpublic void fun1(){us.save();}}

Result:

這是環繞通知之前的部分!!
這是前置通知!!
保存用戶!
這是環繞通知之后的部分!!
這是后置通知(出現異常也會調用)!!
這是后置通知(如果出現異常不會調用)!!

方法二、注入配置
導包過程、目標對象和通知類如上一樣,只是不需要都在xml中手動配置,在java代碼中注入配置
通知類中的配置:

package cn.itcast.e_annotationaop;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut;//通知類 @Aspect //表示該類是一個通知類 public class MyAdvice {@Pointcut("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void pc(){}//前置通知//指定該方法是前置通知,并制定切入點@Before("MyAdvice.pc()")public void before(){System.out.println("這是前置通知!!");}//后置通知@AfterReturning("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void afterReturning(){System.out.println("這是后置通知(如果出現異常不會調用)!!");}//環繞通知@Around("execution(* cn.itcast.service.*ServiceImpl.*(..))")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("這是環繞通知之前的部分!!");Object proceed = pjp.proceed();//調用目標方法System.out.println("這是環繞通知之后的部分!!");return proceed;}//異常通知@AfterThrowing("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void afterException(){System.out.println("出事啦!出現異常了!!");}//后置通知@After("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void after(){System.out.println("這是后置通知(出現異常也會調用)!!");} }

xml文件中的配置:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd "><!-- 準備工作: 導入aop(約束)命名空間 --> <!-- 1.配置目標對象 --><bean name="userService" class="cn.itcast.service.UserServiceImpl" ></bean> <!-- 2.配置通知對象 --><bean name="myAdvice" class="cn.itcast.e_annotationaop.MyAdvice" ></bean> <!-- 3.開啟使用注解完成織入 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>

測試類如上所同!

總結

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

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