第1章 反射与代理

1.1 反射定义

一般情况下,需要一个功能的前提是遇到了某个问题,这里先列举一些问题,然后再通过反射是如何解决了这些问题,来引出反射的定义。

普通开发人员工作中最常见的问题:需要生成代理对象(不清楚代理模式的话,可以简单理解为需要将一个类,在不改变这个类的代码的基础上,要对这个类的功能添加新的逻辑)

解决方式:将需要加强的类,利用反射加载之后,与补充的逻辑进行融合,产生一个新的对象,这个对象就是代理对象,即具备原有类及新逻辑的“增强后的类”(比如 Man 类里面有个 eat() 方法,我们希望执行 eat() 方法前后分别执行洗手、洗碗逻辑,而我们又不能直接去修改eat()方法)

上面是用简洁的方式给出了关于反射的最直白的解释,下面给出较为专业、全面的解释:

反射是什么?

反射(Reflection)是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。

通过反射机制,可以在运行时访问 Java 对象的属性,方法,构造方法等

反射的应用场景:

开发通用框架 - 反射最重要的用途就是开发各种通用框架。很多框架(比如 Spring)都是配置化的(比如通过 XML 文件配置 JavaBean、Filter 等),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象

动态代理 - 在切面编程(AOP)中,需要拦截特定的方法,通常,会选择动态代理方式。这时,就需要反射技术来实现了

注解 - 注解本身仅仅是起到标记作用,它需要利用反射机制,根据注解标记去调用注解解释器,执行行为。如果没有反射机制,注解并不比注释更有用

可扩展性功能 - 应用程序可以通过使用完全限定名称创建可扩展性对象实例来使用外部的用户定义类

1.2 反射与代理中涉及术语

为了理解下一节反射与代理的关系,这里先介绍一下会涉及到的术语:

真实对象(被代理对象):就是最原始的类实例化产生的对象,未经过代理模式对其加工增强,比如上面所说的Man类的对象

代理对象:利用代理模式增强后的对象,比如SuperMan对象

动态代理类:可以理解为代理对象逻辑处理器,也可以理解为“增强”的逻辑所处的位置,需要传入真实对象产生关联的动态代理对象

InvocationHandler 接口:动态代理类需要实现这个接口,并且重写 invoke() 方法,“增强”的逻辑就写在invoke方法里,每个代理类的实例都关联到了一个 Handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由 InvocationHandler 这个接口的 invoke 方法来进行调用

Proxy:代理类,用以为将动态代理对象传入之后,产生真正代理对象

1.3 反射与代理的关系

如上所述,代理模式的主要作用产生代理对象从而实现增强后的方法,而反射作为 Java 所提供的一个特性,是实现代理模式的基础。换言之,利用反射技术获取和操作Java程序里面的类,从而可以对这些类进行包装及加工,产生出代理对象。

获得实现类对象的代理对象:

2.1 调用 Proxy.newProxyInstance 来获得一个动态的代理对象,其接收三个参数,三个参数所代表的含义分别是:

①一个 ClassLoader 对象,定义了由哪个 ClassLoader 对象来对生成的代理对象进行加载

②一个 Interface 对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

③ 一个 InvocationHandler 的实现类对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个 InvocationHandler 的实现类对象上

3.获得代理对象的类对象(这里我们可以打印一下代理类的类对象的类名)

4.获得代理类的所有方法(通过暴力反射 getDeclaredMethods()获得)(将所有获得的方法遍历,输出所有的方法名)

5.通过代理对象调用实现类的方法(并赋值),触发我们的重点步骤: InvocationHandler 接口的实现类中的invoked()方法,从而执行实现类的方法(sout输出结果即可)(这一步就是所谓的无侵入式编码规则)

5.1调用 InvocationHandler 接口具体步骤如下:

在触发了实现类的方法后,首先需要在 InvocationHandler 接口中传入三个参数,分别是

① proxy:  - 指代我们所代理的那个真实对象

② method: - 指代的是我们所要调用真实对象的某个方法的Method对象()

③ args:  - 指代的是调用真实对象某个方法时接受的参数

之后会执行接口独有的invoked()方法,传入两个参数,分别是真实的实现类对象和传入的参数args,最后返回方法。

1.4 JDK动态代理和CGLIB动态代理的区别

代理方式,其实都是通过继承真实对象(被代理对象)的类或者实现其所实现的接口之后,将增强的逻辑补充进去完成的。

JDK动态代理就是通过实现接口完成的,所以当一个类是通过实现接口产生的,就是用JDK动态代理

CGLIB动态代理是通过继承类完成的,所以当一个类没有实现接口,那只能使用JDK动态代理

1.5 Reflection框架

Java里面提供了反射获取类的各个属性及方法的类,但是前提是拿到该类之后才能获取并进行相应的操作,而反射框架Reflections不但能获取classpath下面的类,还能根据特定的注解进行获取。

Reflections通过扫描classpath,索引元数据,并且允许在运行时查询这些元数据。

使用Reflections可以很轻松的获取以下元数据信息:

  1. 获取某个类型的全部子类
  2. 只要类型、构造器、方法,字段上带有特定注解,便能获取带有这个注解的全部信息(类型、构造器、方法,字段)
  3. 获取所有能匹配某个正则表达式的资源
  4. 获取所有带有特定签名的方法,包括参数,参数注解,返回类型
  5. 获取所有方法的名字
  6. 获取代码里所有字段、方法名、构造器的使用

1.6 JsonCat里面对于的动态代理的使用

jsoncat项目链接:https://github.com/Snailclimb/jsoncat

1.7 参考

https://blog.csdn.net/yaomingyang/article/details/80981004

https://zhuanlan.zhihu.com/p/60805342

https://stackoverflow.com/questions/37628/what-is-reflection-and-why-is-it-useful

Java基础—反射与代理(新手向)的更多相关文章

  1. 黑马程序员:Java基础总结----静态代理模式&动态代理

    黑马程序员:Java基础总结 静态代理模式&动态代理   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 静态代理模式 public  class  Ts {   ...

  2. Java基础-反射(reflect)技术详解

    Java基础-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类加载器 1>.JVM 类加载机制  如下图所示,JVM类加载机制分为五个部分 ...

  3. Java的反射和代理以及注解

    最近接触到java的反射和代理(接触的有点迟了...),还是有必要总结下 1. Java的反射 有的时候我们需要在程序运行的时候获取类.方法等信息用于动态运行,这个时候反射就能够帮我们找到类.方法.成 ...

  4. 利用Java的反射与代理机制实现AOP

    在上一篇文章中,我们讲述了利用Java的反射机制中实现Spring中的IOC,在本文中,我们将更进一步,讲述用Java的反射和动态代理机制来实现Spring的AOP. 一.AOP概述 AOP(Aspe ...

  5. Java基础——反射

    今天学到Java基础中的反反射.依照我学习后的个人理解呢,反射就是一套获取类.属性.方法等的工具吧.(其实,感觉学完反射后,有点像喝凉水,解渴但确实我也没体会出它有什么味道,我可能没有学到精髓吧.自己 ...

  6. Java反射机制详解(3) -java的反射和代理实现IOC模式 模拟spring

    IOC(Inverse of Control) 可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”.在Spring中,通过IOC可以将实现类.参数信息等配置在其对应的配置文件中,那么当 需要更 ...

  7. Java基础反射(二)

    原文地址http://blog.csdn.net/sinat_38259539/article/details/71799078 反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Cla ...

  8. java基础(反射,注解,多线程,juc)

    JAVA基础 java反射 class对象 三种方式获取class加载时对象 1.class.forName("全类名"):将字节码文件加载进内存,返回class对象 2.类名.c ...

  9. [java 基础]反射入门

    原文 概况 使用java的反射,可以让我们检查(或者修改)类,接口,字段,方法的特性.当你在编译期不知道他们的名字的时候非常有用. 除此之外,可以使用反射来创建实例,调用方法或者get/set 字段值 ...

随机推荐

  1. Redis小记(一)

    1.redis的数据结构 (1)动态字符串(SDS) redis自身构建了一个简单动态字符串的抽象类型,SDS,在redis里,包含字符串的键值对在底层都是由SDS来实现的. 除了用来保存数据库的字符 ...

  2. SpringMVC参数返回给页面

    springMVC将后台参数返回给前台页面 方法一:利用ModelAndView返回值 1 @RequestMapping("/returnPage.do") 2 public M ...

  3. 【小白学PyTorch】18 TF2构建自定义模型

    [机器学习炼丹术]的炼丹总群已经快满了,要加入的快联系炼丹兄WX:cyx645016617 参考目录: 目录 1 创建自定义网络层 2 创建一个完整的CNN 2.1 keras.Model vs ke ...

  4. 如何确定芯片pin1的位置

    来源:https://www.raviyp.com/embedded/150-identifying-pin-no-1-on-an-ic Identifying pin no 1 on an IC R ...

  5. 《C++primerplus》第6章练习题

    本来前面五题都做完了,写博客时没保存好草稿= =,写了个整合版的程序,实现前五题的关键部分. 1.定义一个叫jojo的结构,存储姓名.替身和力量值,使用动态结构数组初始化二乔.承太郎和乔鲁诺乔巴纳等人 ...

  6. 9.13 考试 T2 区间

    删区间 题意: 给出一个长度为

  7. Inno Setup 5打包exe遇到的坑,做一个学习记录

    ; 脚本由 Inno Setup 脚本向导 生成!; 有关创建 Inno Setup 脚本文件的详细资料请查阅帮助文档! #define MyAppName "人员管理系统"#de ...

  8. 用ASP创建API。NET Core (Day2):在ASP中创建API。网络核心

    下载PDF article - 1.5 MB 下载source - 152.4 KB 下载source - 206.3 KB 下载source code from GitHub 表的内容 中间件路线图 ...

  9. 17.JAVA-常用总结

    for另一种写法 for(UserBean bean : list){ //for循环取出list中每个成员,并赋给bean变量 System.out.println(bean.getName()); ...

  10. JDBC的学习(一)

    JDBC的学习(一) 概念 所谓英文简写的意思是:Java DataBase Connectivity ,即 Java数据库的连接,用Java语言来操作数据库 本质 简单的来说,就是写这个JDBC的公 ...