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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

spring面向AOP之动态代理

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

動(dòng)態(tài)代理中有兩個(gè)重要的接口,一個(gè)是InvocationHandle,另一個(gè)是Proxy。
分別來說明這兩個(gè)接口的作用吧!
InvocationHandle接口
java.lang.reflect.InvocationHandler

InvocationHandler 是代理實(shí)例的調(diào)用處理程序 實(shí)現(xiàn)的接口。每個(gè)代理實(shí)例都具有一個(gè)關(guān)聯(lián)的調(diào)用處理程序。對(duì)代理實(shí)例調(diào)用方法時(shí),將對(duì)方法調(diào)用進(jìn)行編碼并將其指派到它的調(diào)用處理程序的 invoke 方法。簡(jiǎn)單來說invoke就是在在代理實(shí)例上處理方法調(diào)用并返回結(jié)果。

invoke方法介紹:

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

invoke代碼實(shí)例

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

Proxy接口
java.lang.reflect.Proxy

Proxy 提供用于創(chuàng)建動(dòng)態(tài)代理類和實(shí)例的靜態(tài)方法,它還是由這些方法創(chuàng)建的所有動(dòng)態(tài)代理類的超類。

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

代碼實(shí)例:

定義一個(gè)代理的接口和類: package com.proxy;public interface UserService {void Run(); } package com.proxy; 接口的實(shí)現(xiàn)類: public class UserServiceImpl implements UserService {public void Run() {System.out.println("運(yùn)行啦!");}} 動(dòng)態(tài)代理類: 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,該參數(shù)是代理的真實(shí)對(duì)象 2 method,該參數(shù)是代理的方法 3 代理方法中接受的參數(shù) */public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("初始化");Object invoke = method.invoke(us, args);System.out.println("執(zhí)行完畢");return invoke;} }測(cè)試類: 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中已容器已經(jīng)幫我們封裝好了方法,只需要配置注解就可以實(shí)現(xiàn)如上動(dòng)態(tài)代理

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

接口和實(shí)現(xiàn)類

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.準(zhǔn)備通知

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

4.配置進(jìn)行織入,將通知織入目標(biāo)對(duì)象中

<?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 "><!-- 準(zhǔn)備工作: 導(dǎo)入aop(約束)命名空間 --> <!-- 1.配置目標(biāo)對(duì)象 --><bean name="userService" class="cn.itcast.service.UserServiceImpl" ></bean> <!-- 2.配置通知對(duì)象 --><bean name="myAdvice" class="cn.itcast.d_springaop.MyAdvice" ></bean> <!-- 3.配置將通知織入目標(biāo)對(duì)象 --><aop:config><!-- 配置切入點(diǎn):expression中的表達(dá)式表示目標(biāo)對(duì)象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" /><!-- 環(huán)繞通知 --><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.測(cè)試類以及結(jié)果

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:

這是環(huán)繞通知之前的部分!!
這是前置通知!!
保存用戶!
這是環(huán)繞通知之后的部分!!
這是后置通知(出現(xiàn)異常也會(huì)調(diào)用)!!
這是后置通知(如果出現(xiàn)異常不會(huì)調(diào)用)!!

方法二、注入配置
導(dǎo)包過程、目標(biāo)對(duì)象和通知類如上一樣,只是不需要都在xml中手動(dòng)配置,在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 //表示該類是一個(gè)通知類 public class MyAdvice {@Pointcut("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void pc(){}//前置通知//指定該方法是前置通知,并制定切入點(diǎn)@Before("MyAdvice.pc()")public void before(){System.out.println("這是前置通知!!");}//后置通知@AfterReturning("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void afterReturning(){System.out.println("這是后置通知(如果出現(xiàn)異常不會(huì)調(diào)用)!!");}//環(huán)繞通知@Around("execution(* cn.itcast.service.*ServiceImpl.*(..))")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("這是環(huán)繞通知之前的部分!!");Object proceed = pjp.proceed();//調(diào)用目標(biāo)方法System.out.println("這是環(huán)繞通知之后的部分!!");return proceed;}//異常通知@AfterThrowing("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void afterException(){System.out.println("出事啦!出現(xiàn)異常了!!");}//后置通知@After("execution(* cn.itcast.service.*ServiceImpl.*(..))")public void after(){System.out.println("這是后置通知(出現(xiàn)異常也會(huì)調(diào)用)!!");} }

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 "><!-- 準(zhǔn)備工作: 導(dǎo)入aop(約束)命名空間 --> <!-- 1.配置目標(biāo)對(duì)象 --><bean name="userService" class="cn.itcast.service.UserServiceImpl" ></bean> <!-- 2.配置通知對(duì)象 --><bean name="myAdvice" class="cn.itcast.e_annotationaop.MyAdvice" ></bean> <!-- 3.開啟使用注解完成織入 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>

測(cè)試類如上所同!

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。