深入浅出MyBatis:反射和动态代理

前三篇详细总结了Mybatis的基本特性、常用配置、映射器,相对于Hibernate,映射器的配置相对复杂,但有很好的灵活性和扩展性,可以应对各种业务场景。熟练掌握这些内容,可以流畅的使用MyBatis进行开发了。

后面准备介绍MyBatis的解析和运行原理以及自定义插件,今天看了书籍的这部分,都会涉及到反射和动态代理这些基础,本篇文章总结下这些,便于理解原理。

通过本篇的介绍,你会了解到:

  • 反射和动态代理是解决什么问题的
  • Class对象
  • 反射能做什么
  • 动态代理的实现方式:JDK动态代理、CGLIB

理解反射和动态代理

反射

首先看看官网对反射的定义:

可以通过java代码,获取当前加载类的字段、方法、构造函数等信息,并在安全限制内,使用反射字段、方法、构造函数进行操作。

简单来说,可以在运行时获得程序中每一个类型的成员信息。程序中定义的对象,其类型都是在编译期确定的,而反射可以动态地创建对象,并访问或调用其成员。

动态代理

所谓代理,是一个人或组织代替另一个人或组织做事,主要有3个角色:访问者、代理人、被代理人,访问者经由代理人,与被代理人交互,中间会加入一些自己的处理。

所谓的动态代理,是说在编译时不需要定义代理类,而是在运行时创建,这个是关键:在运行时创建代理类。

Class对象

Class类是一个实实在在的类,存在于java.lang包中,用来表示运行时类型信息。Class对象表示自定义类的类型信息,比如创建一个User类,JVM就会创建一个User对应的Class对象,保存User类相关的类型信息,该对象保存在jvm堆中,作为访问方法区中User类型信息的接口。

在使用自定义类时,会首先检查这个类的Class对象是否已经加载,如果没有加载,默认的类加载器就会先根据类名查找.class文件,Class对象就会被加载到内存。

可以通过下面3种方法获取Class对象:

  • 使用Class类的forName静态方法;
  • 直接获取某一个对象的class;
  • 调用某个对象的getClass()方法;

Class对象是反射的基础,提供了获取类信息的方法,后面会介绍。

反射提供的功能

java反射框架主要提供以下内容:

  • 在运行时判断对象所属的类;
  • 在运行时创建对象;
  • 在运行时获取类包含的成员变量、方法、父类、接口等信息;
  • 在运行时调用一个对象的方法;

下面举例说明相关功能

创建实例:

//获取String所对应的Class对象
Class<?> c = User.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
User user = (User)constructor.newInstance("calm");

获取方法:

//返回类或接口声明的所有方法,包括私有的,但不包括继承的方法
public Method[] getDeclaredMethods() throws SecurityException

//所有public方法,包括继承的方法
public Method[] getMethods() throws SecurityException

//返回一个特定的方法,第一个参数为方法名称,后面的参数为方法参数对应Class的对象
public Method getMethod(String name, Class<?>... parameterTypes)

调用方法:

Class<?> userClass=User.class;
Object obj = userClass.newInstance();
Method method =klass.getMethod("addRole",String.class);
method.invoke(obj,"超级管理员");

JDK动态代理

JDK本身提供了动态代理的实现,要求被代理者必须实现接口。

public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,InvocationHandler h)

第一个参数为类加载器,第二个参数是被代理者实现的接口列表,第三个参数是实现了InvocationHandler接口的对象。

InvocationHandler是一个接口,用于规范执行被代理者的方法,可在执行方法前后,添加公共的处理代码。生成的动态代理类包含一个InvocationHandler属性,调用对应方法时,会触发invoke方法的调用。

public class JDKProxy implements InvocationHandler {    

    private Object targetObject;//被代理对象   

    public Object newProxy(Object targetObject) {
        this.targetObject = targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}    

    public Object invoke(Object proxy, Method method, Object[] args)//invoke方法
            throws Throwable {
        Object ret = null;
        ret  = method.invoke(targetObject, args);
        return ret;
    }
}    

测试代码:

JDKProxy jdkProxy=new JDKProxy();
UserService userService = (UserService)
jdkProxy.newProxy(new UserServiceImp());
userService.addRole("超级管理员");    

JDK动态代理的基本原理是根据定义好的规则,用传入的接口创建一个新类。

CGLIB动态代理

JDK动态代理要求必须有接口,CGLIB(Code Generate Library)动态代理没有这个要求,它是通过创建一个被代理类的子类,然后使用ASM字节码库修改代码来实现的。

public class CGLibProxy implements MethodInterceptor {
    private Object targetObject; //被代理对象

    public Object createProxyObject(Object obj) {
        this.targetObject = obj;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(obj.getClass());
        enhancer.setCallback(this);
        Object proxyObj = enhancer.create();
        return proxyObj;
    }    

    public Object intercept(Object proxy, Method method, Object[] args,
            MethodProxy methodProxy) throws Throwable {
        Object obj = null;
        obj = method.invoke(targetObject, args);
        return obj;
    }
}

测试代码:

CGLibProxy cgLibProxy=new CGLibProxy();
UserService userService = (UserService)
cgLibProxy.newProxy(new UserServiceImp());
userService.addRole("超级管理员");    

ASM 是一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。不过ASM在创建class字节码的过程中,操纵的级别是底层JVM的汇编指令级别,这要求ASM使用者要对class组织结构和JVM汇编指令有一定的了解。另外可以使用javassist框架操作字节码,它对开发者提供的接口比较优化。

了解了反射和动态代理,对后面介绍MyBatis的解析和运行原理有很大帮助,下一篇会重点介绍。

欢迎扫描下方二维码,关注我的个人微信公众号 ~

原文地址:http://blog.51cto.com/13714880/2112087

时间: 2024-11-07 20:32:52

深入浅出MyBatis:反射和动态代理的相关文章

Java反射以及动态代理(上)

在常用的各种框架中,反射与动态代理很常见,也很重要.本篇就对这一小节的内容基础性地总结. 首先需要了解什么是类型信息,以及RTTI与反射的关系与区别. Java中,使用Class对象来表示所有类的对象.利用Class对象来获取类中的成员变量,构造函数以及方法,这些内容我们称之为类型信息.RTTI的含义是,在运行时识别一个对象的类型,但有一个前提,就是类型在编译时必须已知,这样才能用RTTI识别,并利用这些信息做一些有用的事情.但是如果在编译时,程序没有办法获知到这个对象所属的类,怎样才能使用这个

java反射与动态代理

Java反射与动态代理 Java反射机制可以动态地获取类的结构,动态地调用对象的方法,是java语言一个动态化的机制.java动态代理可以在不改变被调用对象源码的前提下,在被调用方法前后增加自己的操作,极大地降低了模块之间的耦合性.这些都是java的基础知识,要想成为一名合格的程序猿,必须掌握! Java反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为

黑马程序员————java中类的加载、反射、动态代理、枚举

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 类的加载.反射.动态代理.枚举 一.类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. 1.加载: 就是指将class文件读入内存,并为之创建一个Class对象 ★★

Java开发人员必懂的基础——反射与动态代理

Java的反射与动态代理是java体系结构中较为底层的知识,初学者可能觉得没有太大的用处,但他们确实著名Spring框架IOC和AOP所用的最重要的内容.当我们需要开发更基础,更广泛的的代码时,就会用到这学知识了. 在此之前,我们先来了解一下java的类加载机制 JVM与类加载机制: /* * 1.JVM:当调用java命令来运行某个java程序时,该命令会启动一个java虚拟机进程,同一个JVM中的所有线程,所有变量都处于同一个进程里,都使用该JVM的内存区 * 2.JVM:运行下面两个测试类

Java基础之反射和动态代理

1,反射是依赖于Class对象,然后根据Class对象,去操作该类的资源的.Class对象是发射的基石! 问题1:人这类事物用什么表示?汽车这类事物用什么表示>计算机文件用什么表示?有如此多的事物该用什么表示? 答案:Person类,Car类,File类,这么多的类也是一类事物,这类事物用Class表示. 问题2:Person类的对象,我们知道代表一个具体的人.那么Class类的对象,又代表什么? 一个类,在硬盘上表示一个.class文件,JVM启动的时候,把文件加载到内存上,占用一片空间,称为

java 27 - 9 反射之 动态代理的概述和实现

代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象. 举例:春季回家买票让人代买 动态代理: 在程序运行过程中产生的这个对象 而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理 在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象.JDK提供的代理只能针对接口做代理.我们有更强大的代理cglib Proxy类中的方法创建动态代

JAVA学习--反射之动态代理模式

1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 5 //动态代理的使用,体会反射是动态语言的关键 6 interface Subject { 7 void action(); 8 } 9 10 // 被代理类 11 class RealSubject implements Subject { 12 public

java反射实现动态代理

参考:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html http://my.oschina.net/lyp3314/blog/136589 反射可以通过class来创建对象或者修改对象.这样就提供了一个操作对象的方法. 下面拷贝前辈的总结: <反射机制> 为了更好的理解java的反射机制,最好先对java的泛型有所了解.java泛型就是参数化类型,即为所操作的数据类型指定一个参数.如果只指定了<?>,

Java反射以及动态代理(下)-- 源码

承接上篇,本篇就主要介绍动态代理的实现机制. 首先说说怎么去实现一个动态代理.还是可以用一个接口,两种实现来概括,但是代理中的实现并不明显,后面详细看看源码. 接口: package com.changjiang.test.RFP01.testProxy; public interface DynamicInterface { public void testNoArgs(); public String testOneArgs(String name); } 原始实现类: package co