java代理的原理及应用

什么是代理模式?

  定义

    为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

                                                                  ——百度百科

  代理模式的角色

  抽象角色:代理对象和真实对象的共同接口

  代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能够代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

  真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

  示意图

    

代理模式的分类及使用

  • 静态代理

1 package staticProxy;
2 
3 // 抽象角色,真是对象与代理对象的共同接口
4 public interface Subject {
5     public void request();
6 }
抽象角色
 1 package staticProxy;
 2 
 3 //代理对象,用来被客户端直接调用的类,内部被注入真实对象,可以在调用真是对象的方法前后做预处理和后处理
 4 public class ProxyClass implements Subject {
 5     
 6     Subject subject;
 7     
 8     ProxyClass (Subject subject) {
 9         this.subject = subject;
10     }
11 
12     @Override
13     public void request() {
14         System.out.println("prefix-process!");
15         subject.request();
16         System.out.println("suffix-process!");
17     }
18 
19 }
代理角色
 1 package staticProxy;
 2 
 3 //真实对象,委托类
 4 public class RealClass implements Subject {
 5 
 6     @Override
 7     public void request() {
 8         System.out.println("I'm realClass!");
 9     }
10 
11 }
真实角色
 1 package staticProxy;
 2 
 3 //客户端
 4 public class StaticProxy {
 5     public static void main(String[] args) {
 6         Subject subject = new ProxyClass(new RealClass());
 7         
 8         subject.request();
 9     }
10 }
客户端

    静态代理的缺点很显著,对每一个委托类都需要创建一个代理类,为了解决这个问题,java提供了动态代理。

  • 动态代理

    抽象角色与真实角色的定义和静态代理完全一致,这里不再重复定义

    动态代理类需要继承自InvocationHandler接口,并实现其中的invoke方法。

 1 package dynamicProxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 
 6 public class ProxyClass implements InvocationHandler {
 7 
 8     Object subject;
 9     
10     public ProxyClass(Object subject) {
11         this.subject = subject;
12     }
13     
14     @Override
15     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
16         System.out.println("prefix-process!");
17         method.invoke(subject, args);
18         System.out.println("suffix-process!");
19         return null;
20     }
21 
22 }
动态代理类
 1 package dynamicProxy;
 2 
 3 import java.lang.reflect.Proxy;
 4 
 5 public class DynamicProxy {
 6     public static void main(String[] args) {
 7         
 8         Subject subject = (Subject) Proxy.newProxyInstance(RealClass.class.getClassLoader(),
 9                 new Class[] {Subject.class}, new ProxyClass(new RealClass()));
10         
11         subject.request();
12     }
13 }
客户端

动态代理的实现原理

动态代理的实现主要依赖于java.lang.reflect.InvocationHandler接口与java.lang.reflect.Proxy类,其实现原理是基于java的反射技术。

InvocationHandler接口

    动态代理类需要继承自InvocationHandler接口,此接口中只包含一个方法invoke方法,接口原型如下:

 1 package java.lang.reflect;
 2 
 3 public interface InvocationHandler {
 4 
 5     /**
 6      * proxy:代表代理对象本身,用于调用本代理对象的其他方法
 7      * method:代表正在被调用的委托类的方法
 8      * args:代表调用方法的参数
 9      */
10     public Object invoke(Object proxy, Method method, Object[] args)
11         throws Throwable;
12 }
InvocationHandler

Proxy类

    Proxy类中定义了很多的方法,但根据上面动态代理的应用我们看到,最重要的一个方法就是newProxyInstance方法,该方法的作用就是动态创建一个代理类对象:

 1     /**
 2      * loader代表了委托类的类加载器
 3      * interfaces代表了委托类的接口数组
 4      * h代表委托类的实例
 5      */
 6     @CallerSensitive
 7     public static Object newProxyInstance(ClassLoader loader,
 8                                           Class<?>[] interfaces,
 9                                           InvocationHandler h)
10         throws IllegalArgumentException
11     {
12         // 判断委托类实例是否为空,如果未空抛异常
13         Objects.requireNonNull(h);
14 
15         final Class<?>[] intfs = interfaces.clone();
16         final SecurityManager sm = System.getSecurityManager();
17         if (sm != null) {
18             checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
19         }
20 
21         /*
22          * 获取获取代理类的Class实例
23          */
24         Class<?> cl = getProxyClass0(loader, intfs);
25 
26         /*
27          * Invoke its constructor with the designated invocation handler.
28          */
29         try {
30             if (sm != null) {
31                 checkNewProxyPermission(Reflection.getCallerClass(), cl);
32             }
33 
34             //获取代理类的Constructor对象
35             final Constructor<?> cons = cl.getConstructor(constructorParams);
36             final InvocationHandler ih = h;
37             if (!Modifier.isPublic(cl.getModifiers())) {
38                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
39                     public Void run() {
40                         cons.setAccessible(true);
41                         return null;
42                     }
43                 });
44             }
45 
46             //利用反射原理中使用constructor动态创建动态代理类型
47             return cons.newInstance(new Object[]{h});
48         } catch (IllegalAccessException|InstantiationException e) {
49             throw new InternalError(e.toString(), e);
50         } catch (InvocationTargetException e) {
51             Throwable t = e.getCause();
52             if (t instanceof RuntimeException) {
53                 throw (RuntimeException) t;
54             } else {
55                 throw new InternalError(t.toString(), t);
56             }
57         } catch (NoSuchMethodException e) {
58             throw new InternalError(e.toString(), e);
59         }
60     }
newProxyInstance

动态代理的应用场景

  动态代理最著名的应用场景就是spring中的aop

  

转载于:https://www.cnblogs.com/qq455988971/p/8242946.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/251162.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue --- 过滤器、计算、方法、观察属性

过滤器属性:filters: <div id "app">{{num}}<br>{{num | toInt}}<br>{{num | toFloor}}<br>{{num | toCeil}}<br> </div> <script>let vm new Vue({el: #app,data:{num:3.45,},// 过滤器filters:{toInt(value){return …

《你不知道的JavaScript(上卷)》读书笔记

第一次尝试用思维导图记笔记&#xff0c;感觉还不错~~~不过还是改不了我读书笔记写成抄书笔记的毛病 。 因为开始学JS的时候&#xff0c;一般浏览器就已经支持ES6了&#xff0c;所以比较喜欢使用ES6语法&#xff0c;let&#xff0c;>等&#xff0c;文中代码不是抄书的&#…

ES5-15 数组基础、数组方法、数组排序

创建数组 字面量 var arr []构造函数 var arr new Array()不使用new var arr Array() 所有数组都继承于Array.prototype&#xff0c;能使用其中的数组方法 数组是另一种形式的对象&#xff0c;访问机制相同数组的empty项打印出来是undefined&#xff0c;empty不是值只是一个…

Centos 7 配置 NFS

安装NFS包 yum install nfs-utils.x86_64 启动NFS服务需要首先启动rpcbind服务&#xff0c;这个rpcbind包已经在上面安装好了 先配置 /etc/exports 文件 vi /etc/exports /etc/exports文件内容格式&#xff1a; <输出目录> [客户端1 选项&#xff08;访问权限,用户映射,其…

数学期望笔记

基础知识点 首先明确期望公式:\[E(X)∑_ip_i*x_i\] 其中 \(p\) 代表概率 , \(x\) 代表发生贡献。 然后期望的几点性质: 对于数学期望&#xff0c;我们还应该明确一些知识点&#xff1a; (1) 期望的“线性”性质 对于所有满足条件的离散型的随机变量\(X,Y\)和常量\(a,b\)有: \[E…

vue --- vue中的几个钩子属性

1.创建前:beforeCreate <div id"app">{{name}}</div><script>let app new Vue({el:#app,data:{name:31231312},beforeCreate(){console.log(挂在前);console.log(this.$data);console.log(this.$el);}})</script>// beforeCreate()是在Vue挂…

ES5-16【utils】数组方法、类数组

数组方法 concat 返回值是拼接后的数组 toString 将数组转成字符串&#xff0c;用逗号隔开 slice(a&#xff0c;b) [a&#xff0c;b) 不传值&#xff0c;拷贝了一份不传b&#xff0c;截取到最后一位传b&#xff0c;截取到b之前的那位a/b是负数&#xff08;和splice一样&a…

Catalan卡塔兰数

卡塔兰数 卡塔兰数是组合数学中一个常出现在各种计数问题中出现的数列。由以比利时的数学家欧仁查理卡塔兰 (1814–1894)命名。 卡塔兰数的一般项公式为 另类递归式&#xff1a; h(n)((4*n-2)/(n1))*h(n-1); 前几项为: 1, 1, 2, 5, 14, 42, 132, 429, …

vue --- v-html、v-bind

v-html // 有时候,我们需要展示<strong>,但直接使用下面的语法并不会显示 <div id "app">{{name}}</div><script>let app new Vue({el:#app,data:{name:<strong>啦啦啦</strong>}}); </scritp> // 结果当然没让人失望此…

在树莓派是安装并配置NTP服务

我们都知道树莓派的小巧和省电节省空间等太多的优势&#xff0c;这里就不一一列举了&#xff0c;那么树莓派就需要长时间的运行&#xff0c;可以724的方式运行&#xff0c;那么我们就把树莓派当作一个小的服务器来运行&#xff0c;可以跑一些小的应用&#xff0c;例如可以在局域…

Oracle使用总结

1. 在ORACLE中Service Name即为数据库名称&#xff1b; 2. 在做删除操作时&#xff0c;需要加Commit进行操作提交&#xff1b; 3. 使用sqlldr将数据进行批量导入到ORACLE中&#xff1a; 3.1 Sqlldr命令的用法&#xff1a; sqlldr useridLoginName/PasswordTNSName controlC:\U…

ES5-17/18 错误信息、try_catch、严格模式

错误信息 语法错误 标识符名称&#xff08;变量、函数名&#xff09;不规范对关键字赋值基本语法错误&#xff0c;如分号打错 引用错误 变量、函数未声明给无法赋值的对象赋值var a 1 2 范围错误 数组长度为负数方法参数超出可行范围toFixed(-1) 类型错误 调用不存在…

vue --- v-text、v-show、v-if、v-else

v-text: <div id "app"><p v-text"msg"></p> </div> <script>let app new Vue({el:#app,data:{msg:Hello Vue}}) </script>// 可见v-text在某种程度上等价于 {{}}v-show: <div id "app"><div…

查找mac下腾讯视频下载地址

mac 腾讯视频下载的视频是不可见的&#xff0c;也许是因为版权原因吧。使用以下方法可以在文件中找到缓存的视频&#xff08;不过都是被断开的很多短视频&#xff09;。 在terminal输入&#xff1a; cd Library/Containers/ 然后ls查看。查看当前的所有文件夹&#xff0c;你会看…

JS 新建web sql 数据表

//新建web sql数据库数据表var tbName"tableName";var strSQL"create table if not exists tableName (id unique,th1,th2,th3)";function creatBDTable(strSQL,tbName){db openDB();db.transaction(function(tr) {tr.executeSql(strSQL,[],//SQL语句出成…

vue --- v-for、v-on、v-model、v-once

v-for: <div id "app"><ul><li v-for"item in list">{{item}}</li></ul> </div> <script>let app new Vue({el:#app,data:{list:[B,A,T]}}) </script>拿到索引index: <div id"app">&…

ES5-19 变量声命周期、垃圾回收原理、arguments

变量声命周期 垃圾回收 找出不再使用的变量释放其占用内存固定的时间间隔运行 解除由于闭包产生的对fn AO的引用 标记清除 排除全局变量、排除闭包引用的AO中的变量进入环境 → 离开环境常用 引用计数 引用计数为0时清除对循环引用的情况&#xff0c;如果不手动接触引用…

bzoj 1801: [Ahoi2009]chess 中国象棋【dp】

注意到一行只能放012个炮&#xff0c;我们只需要知道列的状态&#xff0c;不用状压行 所以设f[i][j][k]表示前i行有j列有1个炮&#xff0c;有k列有2个炮的方案数 然后分情况讨论转移就行了 #include<cstdio> #include<iostream> using namespace std; const int N1…

vue --- compoent妙用

首先利用写一个静态模板的组件 <div id "app"><my-arti></my-arti> </div> <script>Vue.component(my-arti,{template:<div style"border:1px solid black"><span>date:2019年06月14日</span><br>…

ES5-20 复习

3-1 变量单一声明方式String Boolean undefined Number nullundefined nulltypeof(null) ‘object’typeof(方法) ‘function’typeof() 是运算符&#xff0c;不是数据类型 报错0 -0 trueInfinity -Infinity falseNaN和谁都不等原始值没有属性 要打印属性、调用方法得经过基…