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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

final类是否可以被代理_浅谈Java【代理设计模式】——看这篇文章就懂了

發布時間:2023/12/4 java 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 final类是否可以被代理_浅谈Java【代理设计模式】——看这篇文章就懂了 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是代理模式

為其他對象提供一種代理以控制對這個對象的訪問。

為什么使用代理模式

中介隔離:在某些情況下,一個客戶類不想或者不能直接引用一個委托對象,而代理類對象可以在客戶類和委托對象之間起到中介的作用,其特征是代理類和委托類實現相同的接口。開閉原則,增加功能:代理類除了是客戶類和委托類的中介之外,我們還可以通過給代理類增加額外的功能來擴展委托類的功能,這樣做我們只需要修改代理類而不需要再修改委托類,符合代碼設計的開閉原則。代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事后對返回結果的處理等。代理類本身并不真正實現服務,而是同過調用委托類的相關方法,來提供特定的服務。真正的業務功能還是由委托類來實現,但是可以在業務功能執行的前后加入一些公共的服務。例如我們想給項目加入緩存、日志這些功能,我們就可以使用代理類來完成,而沒必要打開已經封裝好的委托類。

代理模式實現原理

代理模式主要包含三個角色,即抽象主題角色(Subject)、委托類角色(被代理角色,Proxied)以及代理類角色(Proxy)

抽象主題角色(Subject):可以是接口,也可以是抽象類委托類角色(proxied):真實主題角色,業務邏輯的具體執行者代理類角色(Proxy):內部含有對真實對象RealSubject的引用,負責對真實主題角色的調用,并在真實主題角色處理前后做預處理和后處理

代理模式應用場景

SpringAop、日志收集、權限控制、過濾器、RPC遠程調用

代理模式創建的方式

靜態代理 和 動態代理靜態代理
靜態代理是由程序員創建或工具生成代理類的源碼,再編譯代理類。
所謂靜態也就是在程序運行前就已經存在代理類的字節碼文件,代理類和委托類的關系在運行前就確定了。
一句話,自己手寫代理類就是靜態代理。

基于接口實現方式:

//主題(Subject) public interface OrderService {void order(); } //實現接口 public class OrderServiceImpl implements OrderService {public void order() {System.out.println("用戶下單操作..");} } //代理類 public class OrderServiceProxy implements OrderService {/*** 代理對象*/private OrderService proxiedOrderService;public OrderServiceProxy( OrderService orderService) {this.proxiedOrderService=orderService;}public void order() {System.out.println("日志收集開始..");proxiedOrderService.order();System.out.println("日志收集結束..");} } //測試 public class ClientTest {public static void main(String[] args) {OrderService orderService = new OrderServiceProxy(new OrderServiceImpl());orderService.order();} }

接口繼承方式實現

//繼承接口實現類 public class OrderServiceProxy extends OrderServiceImpl {public void order() {System.out.println("日志收集開始..");super.order();System.out.println("日志收集結束..");} } //測試 public class ClientTest {public static void main(String[] args) {OrderService orderService = new OrderServiceProxy();orderService.order();} }

動態代理

動態代理是在實現階段不用關心代理類,而在運行階段才指定哪一個對象。
動態代理類的源碼是在程序運行期間由JVM根據反射等機制動態的生成 。

JDK動態代理

JDK動態代理的一般步驟如下:
1.創建被代理的接口和類;

2.實現InvocationHandler接口,對目標接口中聲明的所有方法進行統一處理;

3.調用Proxy的靜態方法,創建代理類并生成相應的代理對象;

//主題()Subject public interface OrderService {void order(); } //實現接口 public class OrderServiceImpl implements OrderService {public void order() {System.out.println("修改數據庫訂單操作..");} } //代理類 public class JdkInvocationHandler implements InvocationHandler {/*** 目標代理對象*/public Object target;public JdkInvocationHandler(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(">>>日志收集開始>>>>");// 執行代理對象方法Object reuslt = method.invoke(target, args);System.out.println(">>>日志收集結束>>>>");return reuslt;}/*** 獲取代理對象接口** @param <T>* @return*/public <T> T getProxy() {return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}} JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(new OrderServiceImpl()); OrderService proxy = jdkInvocationHandler.getProxy(); proxy.order();

原理分析

1.獲取代理的生成的class文件

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");


2.使用反編譯工具該Proxy0.class


注意:繼承了Proxy類,實現了代理的接口,由于java不能多繼承,這里已經繼承了Proxy類了,不能再繼承其他的類,所以JDK的動態代理不支持對實現類的代理,只支持接口的代理。

CGLIB動態代理

Cglib是一個強大的,高性能,高質量的代碼生成類庫。它可以在運行期擴展JAVA類與實現JAVA接口。其底層實現是通過ASM字節碼處理框架來轉換字節碼并生成新的類。大部分功能實際上是ASM所提供的,Cglib只是封裝了ASM,簡化了ASM操作,實現了運行期生成新的class。

CGLIB原理

運行時動態的生成一個被代理類的子類(通過ASM字節碼處理框架實現),子類重寫了被代理類中所有非final的方法。在子類中采用方法攔截的技術攔截所有父類方法的調用,順勢植入橫切邏輯。

Cglib優缺點

優點:JDK動態代理要求被代理的類必須實現接口,當需要代理的類沒有實現接口時Cglib代理是一個很好的選擇。另一個優點是Cglib動態代理比使用java反射的JDK動態代理要快
缺點:對于被代理類中的final方法,無法進行代理,因為子類中無法重寫final函數

CGLIB代理實現

實現MethodInterceptor接口的intercept方法后,所有生成的代理方法都調用這個方法。

intercept方法的具體參數有

obj 目標類的實例

1.method 目標方法實例(通過反射獲取的目標方法實例)

2.args 目標方法的參數

3.proxy 代理類的實例

該方法的返回值就是目標方法的返回值。

public class OrderServiceImpl {public void order() {System.out.println("用戶下單操作..");} } public class CglibMethodInterceptor implements MethodInterceptor {public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("<<<<<日志收集開始...>>>>>>>");Object reuslt = proxy.invokeSuper(obj, args);System.out.println("<<<<<日志收集結束...>>>>>>>");return reuslt;} }System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:code"); CglibMethodInterceptor cglibMethodInterceptor = new CglibMethodInterceptor(); Enhancer enhancer = new Enhancer(); // 設置代理類的付類 enhancer.setSuperclass(OrderServiceImpl.class); // 設置回調對象 enhancer.setCallback(cglibMethodInterceptor); // 創建代理對象 OrderServiceImpl orderServiceImpl = (OrderServiceImpl) enhancer.create(); orderServiceImpl.order();

Maven依賴

<dependencies><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.12</version></dependency> </dependencies>

結果

>>>>cglib日志收集開始....
執行訂單業務邏輯代碼
>>>>cglib日志收集結束....

靜態代理與動態代理區別

靜態代理需要自己寫代理類,而動態代理不需要寫代理類。

JDK動態代理與CGLIB實現區別

JDK動態代理底層實現:
JDK的動態代理使用Java的反射技術生成動態代理類,只能代理實現了接口的類, 沒有實現接口的類不能實現動態代理。CGLIB動態代理底層實現:
運行時動態的生成一個被代理類的子類(通過ASM字節碼處理框架實現),子類重寫了被代理類中所有非final的方法,在子類中采用方法攔截的技術攔截所有父類方法的調用,不需要被代理類對象實現接口,從而CGLIB動態代理效率比Jdk動態代理反射技術效率要高。

案例:使用AOP攔截Controller所有請求日志

@Aspect @Component @Slf4j public class AopLogAspect {// 申明一個切點 里面是 execution表達式@Pointcut("execution(* com.xuyu.controller.*.*(..))")private void serviceAspect() {}// 請求method前打印內容@Before(value = "serviceAspect()")public void methodBefore(JoinPoint joinPoint) {ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = requestAttributes.getRequest();// 打印請求內容log.info("===============請求內容===============");log.info("請求地址:" + request.getRequestURL().toString());log.info("請求方式:" + request.getMethod());log.info("請求類方法:" + joinPoint.getSignature());log.info("請求類方法參數:" + Arrays.toString(joinPoint.getArgs()));log.info("===============請求內容===============");}// 在方法執行完結后打印返回內容@AfterReturning(returning = "o", pointcut = "serviceAspect()")public void methodAfterReturing(Object o) {log.info("--------------返回內容----------------");log.info("Response內容:" + o.toString());log.info("--------------返回內容----------------");} }

Maven依賴信息

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.1.RELEASE</version> </parent> <dependencies><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.12</version></dependency><!-- sprinboot web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.10</version></dependency><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency> </dependencies>

結果

===============請求內容===============
: 請求地址:http://127.0.0.1:8080/getUser
: 請求方式:GET
: 請求類方法:String com.xuyu.service.controller.IndexController.getUser(String,Integer)
: 請求類方法參數:[xuyu, 2]
: ===============請求內容===============
: >>>userName:{},xuyu
: --------------返回內容----------------
: Response內容:success_getUser
: --------------返回內容----------------

作者:須臾之余

來源:開源中國

原文:https://my.oschina.net/u/3995125/blog/3051269

福利專區:

動態代理及應用深度解析|Java SE視頻課程 - 蛙課視頻?www.wkcto.com

總結

以上是生活随笔為你收集整理的final类是否可以被代理_浅谈Java【代理设计模式】——看这篇文章就懂了的全部內容,希望文章能夠幫你解決所遇到的問題。

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