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不是值只是一个…

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> // 结果当然没让人失望此…

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…

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;如果不手动接触引用…

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和谁都不等原始值没有属性 要打印属性、调用方法得经过基…

eclipse中去掉警告提示

有时候我们要去掉这些不必要的提示 下面我们来设置去掉这些警告提示 转载于:https://www.cnblogs.com/xiaostudy/p/9370016.html

vue --- vue-router

vue-router的CDN <script src "https://unpkg.com/vue-router2.5.3/dist/vue-router.js"></script>// 当然还需要导入vue的cdn <script src"https://cdn.jsdelivr.net/vue/2.1.3/vue.js"></script>使用router-link(to)添加点击链…

django-restframework使用

安装restframework: pip install djangorestframework 修改项目settings.py: INSTALLED_APPS [django.contrib.admin,django.contrib.auth,django.contrib.contenttypes,django.contrib.sessions,django.contrib.messages,django.contrib.staticfiles,rest_framework, ]修改项…

JSON基础与数据解析、JSON方法、AJAX初识

JSON JavaScript Object Notation js对象标记是对象&#xff0c;是轻量级数据交互的格式&#xff0c;不能有方法它基于 JavaScript 语法&#xff0c;但与之不同&#xff1a;JavaScript不是JSON&#xff0c;JSON也不是JavaScript映射用:隔开并列数据用,隔开映射的集合用{}包裹键…

iOS开发经验总结

在iOS开发中经常需要使用的或不常用的知识点的总结&#xff0c;几年的收藏和积累&#xff08;踩过的坑&#xff09;。 一、 iPhone Size 二、 给navigation Bar 设置 title 颜色 123UIColor *whiteColor [UIColor whiteColor];NSDictionary *dic [NSDictionary dictionaryWit…

ES5 数组扩展方法 forEach/filter/map的使用与重写

ES3 splice slice join sort &#xff08;IE5、IE6&#xff09; 数组扩展方法 ES5&#xff08;在ES3的基础上增加、修正&#xff09; forEach 可能会改变原数组(直接操作了arr[i]&#xff0c;没有使用深拷贝)参数1&#xff1a;回调函数&#xff08;如果不使用箭头函数&#xf…

187. Repeated DNA Sequences重复的DNA子串序列

&#xff3b;抄题&#xff3d;&#xff1a; All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACGAATTCCG". When studying DNA, it is sometimes useful to identify repeated sequences within the DNA. Write a fun…