首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    JVM 《八 JVM JDK代理&CGLib 代理解析》

    前言&背景 现在Spring 什么的好火。 Spring 很经典的一个特性是AOP AOP 的基础是代理。 代理分为静态代理、动态代理。 静态代理,不好处挺明显的,工程中各式各样的代理代码,过于冗余。 动态代理显得就简洁多了。 动态代理在java中现在大约有这么两种技术。JDK 原生反射,字节码操作增强反射(我第一次学到这个的时候感觉特别特别高大上,虽然现在也这么感觉 然后字节码操作技术 比较火的就是ASM了,也就是CGLib所使用的技术。 至于啥是代理,就不多解释了。就是产生一个代理操作来替代原核心操作并且增加一些便利的具有各个场景特性的附加操作。 然后JDK&CGLib表象上或者语法上的区别,一个面向接口、一个面向类、Spring 根据情况使用也可强制。然后单独使用的时候写法儿上的不同。 那在JVM层面去看待这个问题是怎样的呢? 其实本质要讨论的就是Java 反射、字节码操作具体是怎么样的,有什么区别。 先说一个反射的总体概念 反射,顾名思义 反着射,跟常规编写、编译、解释执行不同。我当时看反射的时候挺蒙蔽的,反射?反?射?到系统的看编程思想的RTTI那一块,对于反射的定义还有这个名字多少有点认可了。 下面是百度的解释,感觉挺糟糕的 也就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。 一个比较可取的解释 Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions The primitive Java types (boolean, byte, char, short, int, long, float, anddouble), and the keyword void are also represented as Class objects. 综合起来看,也就是运行期间根据名称去动态的加载及使用一个编译期未知的类,然后根据加载进来的Class对象,来调用该类具体的方法的行为。(静态加载、根据已知信息直接使用) 为什么是反着呢,因为我们常规写程序都是既定使用的类&方法然后import、然后加载产生Class对象&使用类的具体信息 驱动执行。(已知信息使用) 而反射是在运行时除了名称完全未知,通过名称获取&加载进来,然后产生Class对象,通过Class 对象的信息来获取调用这个类具体的内容。(动态加载、透过 Class 获取信息去调用) 当然,这个类通常是远程调用或者别的什么方式来获取使用的。 Java反射也就是上面说的常规过程,来加载&使用一个完全未知的类。 而且JDK代理有个特点,是针对接口来实现的,也就是面向接口来编程,这也就导致了 接口一致而非对象一致。并且Java 反射效率总体来说是比较低下。 为了解决这些个问题,ASM之类的字节码操作技术出现了。

    01

    Class.forName()用法详解

    主要功能 Class.forName(xxx.xx.xx)返回的是一个类 Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类, 也就是说JVM会执行该类的静态代码段 下面,通过解答以下三个问题的来详细讲解下Class.forName()的用法。 一.什么时候用Class.forName()? 先来个热身,给你一个字符串变量,它代表一个类的包名和类名,你怎么实例化它?你第一想到的肯定是new,但是注意一点: A a = (A)Class.forName(“pacage.A”).newInstance(); 这和你 A a = new A(); 是一样的效果。 现在言归正传。 动态加载和创建Class 对象,比如想根据用户输入的字符串来创建对象时需要用到: String str = “用户输入的字符串” ; Class t = Class.forName(str); t.newInstance(); 在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,最主要有什么区别?它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。那么为什么会有两种创建对象方式?这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。 Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。 例如: class c = Class.forName(“Example”); factory = (ExampleInterface)c.newInstance(); 其中ExampleInterface是Example的接口,可以写成如下形式: String className = “Example”; class c = Class.forName(className); factory = (ExampleInterface)c.newInstance(); 进一步可以写成如下形式: String className = readfromXMlConfig;//从xml 配置文件中获得字符串 class c = Class.forName(className); factory = (ExampleInterface)c.newInstance(); 上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。 从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证: 1、这个类已经加载; 2、这个类已经连接了。 而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。 现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。 这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。 二.new 和Class.forName()有什么区别? 其实上面已经说到一些了,这里来做个总结: 首先,newInstance( )是一个方法,而new是一个关键字; 其次,Class下的newInstance()的使用有局限,因为它生成对象只能调用无参的构造函数,而使用 new关键字生成对象没有这个限制。 简言之: newInstance(): 弱类型,低效率,只能调用无参构造。 new: 强类型,相对高效,能调用任何public构造。 Class.forName(“”)返回的是类。 Class.forName(“”).newInstance()返回的是object 。 三.为什么在加载数据库驱动包的时候有用的是Class.forName( ),却没有调用newInstance( )? 在Java开发特别是数据库开发中,经常会用到Class.forName( )这个方法。 通过查询Java Documentation我们会发现使用Class.forName( )静态方法的目的是为了动态加载类。 通常编码过程中,在加载完成后,一般还要调用Class下的newInstance( )静态方法来实例化对象以便操作。因此,单单使用Class.forName( )是动态加载类是没有用的,其最终目的是为了实例化对象。 有数据库开发经验朋友会发现,为什么在我们加载数据库驱动包的时候有的却没有调用newIn

    01
    领券