一篇博客读懂设计模式之---动态代理与反射

先来讲一下反射:

1 关于反射
反射最大的作用之一就在于我们可以不用在编译时就知道某个对象的类型,而在运行时通过提供完整的”包名+类名.class”得到。注意:不是在编译时,而是在运行时

功能:
•在运行时能判断任意一个对象所属的类。
•在运行时能构造任意一个类的对象。
•在运行时判断任意一个类所具有的成员变量和方法。
•在运行时调用任意一个对象的方法。
说大白话就是,利用Java反射机制我们可以加载一个运行时才得知名称的class,获悉其构造方法,并生成其对象实体,能对其fields设值并唤起其methods。

应用场景:
反射技术常用在各类通用框架开发中。因为为了保证框架的通用性,需要根据配置文件加载不同的对象或类,并调用不同的方法,这个时候就会用到反射——运行时动态加载需要加载的对象。

缺点:
由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

2 动态代理
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在两者之间起到中介的作用(可类比房屋中介,房东委托中介销售房屋、签订合同等)。
所谓动态代理,就是实现阶段不用关心代理谁,而是在运行阶段才指定代理哪个一个对象(不确定性)。如果是自己写代理类的方式就是静态代理(确定性)。

组成要素:
(动态)代理模式主要涉及三个要素:
其一:抽象类接口
其二:被代理类(具体实现抽象接口的类)
其三:动态代理类:实际调用被代理类的方法和属性的类

动态代理有三个必要条件:

1. 要有两个角色(代理对象和被代理对象)

2. 代理对象要持有被代理对象的引用(要有被代理对象的信息)

3. 注重过程,必须要做的事情,被代理对象没时间或者不想做

实现方式:
实现动态代理的方式很多,比如 JDK 自身提供的动态代理,就是主要利用了反射机制。还有其他的实现方式,比如利用字节码操作机制,类似 ASM、CGLIB(基于 ASM)、Javassist 等。

举例,常可采用的JDK提供的动态代理接口InvocationHandler来实现动态代理类。其中invoke方法是该接口定义必须实现的,它完成对真实方法的调用。通过InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由InvocationHandler接管实际的处理任务。此外,我们常可以在invoke方法实现中增加自定义的逻辑实现,实现对被代理类的业务逻辑无侵入。

代理模式在我们生活中其实都有很多形象的例子:比如媒婆,租房中介等等,都是典型的动态代理模式,下面我们就以大家比较熟悉的媒婆来举例,更加生动形象的来介绍动态代理:

首先先用JDK来实现动态代理,必要条件:被代理对象要实现一个接口:

public interface Person {void findGF();
}
public class James implements Person{@Overridepublic void findGF() {System.out.println("高富帅");System.out.println("有房有车的");System.out.println("身高要求180cm以上,体重70kg");}
}
public class Meipo implements InvocationHandler {private Object target; //被代理对象的引用作为一个成员变量保存下来了//获取被代理人的个人资料public Object getInstance(Object target) throws Exception{this.target = target;Class clazz = target.getClass();System.out.println("被代理对象的class是:"+clazz);return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("我是媒婆:" + "得给你找个异性才行");System.out.println("开始进行海选...");System.out.println("------------");//调用被代理类的方法,这里就会调用James的方法method.invoke(this.target, args);System.out.println("------------");System.out.println("如果合适的话,就准备办事");return null;}
}

测试类:

public class TestJDKProxy {public static void main(String[] args) {try{Person person = (Person) new JDKMeiPo().getInstance(new XiaoJie());//下面调用findGF()就会调用invoke()方法person.findGF();}catch (Exception e){e.printStackTrace();}}
}

下面用CGLIB方式来实现动态代理:CGLIB相比JDK的方式优势是:被代理类不一定要去实现接口,它是通过CGLIB来生成被代理类的子类,继承父类的方法和属性,从而达到代理的效果:

public class James {public void findLove(){System.out.println("肤白貌美大长腿");}
}

代理类需要实现MethodInterceptor接口


public class Meipo implements MethodInterceptor{//好像并没有持有被代理对象的引用?public Object getInstance(Class clazz) throws Exception{Enhancer enhancer = new Enhancer();//把父类设置为谁?//这一步就是告诉cglib,生成的子类需要继承哪个类enhancer.setSuperclass(clazz);//设置回调enhancer.setCallback(this);//第一步、生成源代码//第二步、编译成class文件//第三步、加载到JVM中,并返回被代理对象return enhancer.create();}//同样是做了字节码重组这样一件事情//对于使用API的用户来说,是无感知@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("我是媒婆:" + "得给你找个异性才行");System.out.println("开始进行海选...");System.out.println("------------");//这个obj的引用是由CGLib给我们new出来的//cglib new出来以后的对象,是被代理对象的子类(继承了我们自己写的那个类)//OOP, 在new子类之前,实际上默认先调用了我们super()方法的,//new了子类的同时,必须先new出来父类,这就相当于是间接的持有了我们父类的引用//子类重写了父类的所有的方法//我们改变子类对象的某些属性,是可以间接的操作父类的属性的proxy.invokeSuper(obj, args);System.out.println("------------");System.out.println("如果合适的话,就准备办事");return null;}
}
public class TestGglibProxy {public static void main(String[] args) {//JDK的动态代理是通过接口来进行强制转换的//生成以后的代理对象,可以强制转换为接口//CGLib的动态代理是通过生成一个被代理对象的子类,然后重写父类的方法//生成以后的对象,可以强制转换为被代理对象(也就是用自己写的类)//子类引用赋值给父类try {James obj = (James)new Meipo().getInstance(James.class);obj.findLove();} catch (Exception e) {e.printStackTrace();}}
}

额外:

静态代理:事先写好代理类,可以手工编写,也可以用工具生成。缺点是每个业务类都要对应一个代理类,非常不灵活。
   动态代理:运行时自动生成代理对象。缺点是生成代理代理对象和调用代理方法都要额外花费时间。
  JDK动态代理:基于Java反射机制实现,必须要实现了接口的业务类才能用这种办法生成代理对象。新版本也开始结合ASM机制。
   cglib动态代理:基于ASM机制实现,通过生成业务类的子类作为代理类。
Java 发射机制的常见应用:动态代理(AOP、RPC)、提供第三方开发者扩展能力(Servlet容器,JDBC连接)、第三方组件创建对象(DI)……

一篇博客读懂设计模式之---动态代理与反射相关推荐

  1. 教你如何一篇博客读懂设计模式之—--原型模式

    教你如何一篇博客读懂设计模式之----原型模式 what:是什么 原型模式: 用于创建重复的对象,既不用一个属性一个属性去set和get,又不影响性能,原型模式产生的对象和原有的对象不是同一个实例,他 ...

  2. 教你如何一篇博客读懂设计模式之—--工厂模式

    一篇博客读懂设计模式之-工厂模式 工厂模式在我们日常开发的时候经常用到,相信大家都有了一定的了解,工厂模式是一种创建对象的设计模式,它提供一种创建对象的最佳方式. 主要过程是: 定义一个创建对象的接口 ...

  3. 一篇博客读懂设计模式之---委派模式

    一篇博客读懂设计模式之-委派模式 委派模式可能大家听起来不太熟悉,但是在代码开发的时候却很好用,下面从几个方面来介绍一下 what:是什么? 委派模式:顾名思义,委托其他对象或者实例来帮我们完成任务, ...

  4. 一篇博客读懂设计模式之---单例模式

    一篇博客读懂设计模式之---单例模式 一.  单例模式 单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处 ...

  5. 一篇博客读懂设计模式之---模板方法模式

    设计模式之模板方法模式: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 简而言之就是:父类定义了骨架(调用哪些方法及其 ...

  6. 一篇博客读懂设计模式之-----策略模式

    设计模式之策略模式 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的对象 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换. 主要解决:在有多种算法相似的情况下 ...

  7. 一篇博客读懂设计模式之---工厂模式

    设计模式之-工厂模式 工厂模式: 创建过程: 创建Shape接口 public interface Shape {void draw(); } 创建实现类: public class Circle i ...

  8. [入门篇]用史上最生动的方式让你一篇博客搞懂Linux进程地址空间,包看包懂!

    目录 0.前言 1.初始程序的地址空间划分 1.1程序地址空间图解 1.2程序地址空间区域划分验证 1.3 程序地址空间小补充 1.4 引入进程地址空间 *2. 两个生动的例子理解进程地址空间 2.1 ...

  9. 2022年从零开始,用一篇博客掌握 nginx 的初级配置

    本篇博客主要用于记录 nginx.conf 这一个文件如何修改的相关问题. 当 nginx 安装之后,默认的配置如下所示(数据来源为宝塔自动生成),本篇博客重点介绍的是配置虚拟机相关内容,即 serv ...

最新文章

  1. 机器学习(1)机器学习基础 鸢尾花数据集
  2. Multi-task Learning(Review)多任务学习概述
  3. 卷积神经网络Convolutional Neural Network (CNN)
  4. JZOJ 5473. 【NOIP2017提高组正式赛】小凯的疑惑
  5. 搭建 Hadoop2.7.2 + Spark1.6环境
  6. LiveVideoStackCon 2018展现多媒体技术生态多样性
  7. 算法竞赛入门经典(第二版) | 程序3-6 WERTYU (UVa 10082)(常量数组)
  8. html基础元素案例笔记(1)
  9. php strchr 截断,PHP strchr() 函数
  10. Keil综合(03)map文件全解析
  11. Android 系统性能优化(72)-----App启动优化
  12. 顺丰控股:2月速运物流业务营业收入98.49亿元,同比下降3.36%
  13. 爬取两万多条租房数据,算算在广州你能「活到」第几集?
  14. NSURLCache详解和使用
  15. 卢卡奇总体性原则_重识青年卢卡奇的“历史”概念问题
  16. HackTools———10、使用Python编写TCP客户端、服务器端
  17. Max Script 入门教程
  18. 原创分享 | 如何从非技术层面实现数据驱动
  19. Dingo + Laravel + JWT + Entrust + memcache 实现API设计
  20. 网页贴便签, Chrome特色网页便签纸 OurStickys

热门文章

  1. Java SecurityManager getThreadGroup()方法与示例
  2. Net处理html页面元素工具类(HtmlAgilityPack.dll)的使用
  3. Matlab仿真PID控制(带M文件、simulink截图和参数分析)
  4. ORACLE中使用递归查询
  5. 【Jetson-Nano】2.Tensorflow和Pytorch的安装
  6. 蓝桥杯试题 算法提高 数组求和
  7. android 换行乱_Android自动换行布局
  8. java win10 通知,如何使用Java AWT创建和显示Windows 10通知
  9. java获取年的第一天和最后一天_java中如何获取当前年份的第一天和最后一天
  10. mysql info commit_mysql show processlist 发现大量的commit