`
情情说
  • 浏览: 38896 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

深入浅出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的解析和运行原理有很大帮助,下一篇会重点介绍。

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

 


情情说

 

 

0
0
分享到:
评论

相关推荐

    Java 208道面试.docx

    - MyBatis:动态SQL,Mapper接口和XML配置的使用。 13. **消息队列**: - RabbitMQ和Kafka:消息模型,生产者消费者模型,以及如何确保消息的可靠传递。 14. **分布式协调**: - Zookeeper:集群管理,分布式锁...

    更新至2020年12月最全Java 面试全解析:核心知识点与典型面试题.pdf

    - 动态代理:介绍动态代理的原理和使用,包括常见的IO操作和Socket编程示例。 5. 多线程编程 - 线程池:包含Java8在内的8种线程池的介绍和正确使用方法。 - 死锁和锁机制:包括死锁的代码示例、解决方案,以及...

    Java 最常见 200+ 面试题全解析:面试必备.pdf

    5. 对象拷贝:分为浅拷贝和深拷贝,研究如何在Java中进行对象的复制操作,包括使用clone方法和拷贝构造函数等。 6. JavaWeb:包括了解和使用Servlet、Filter、Listener、JSP、EL表达式、JSTL标签库等Web技术。 7. ...

    疯狂JAVA:突破程序员基本功的16课 源码

    在《疯狂JAVA:突破程序员基本功的16课》中,作者深入浅出地探讨了Java编程中的核心概念和技术,旨在提升程序员的基本技能和解决问题的能力。以下是对这些知识点的详细阐述: 1. **Java基础**:Java是一种面向对象...

    Java开发技术大全 清晰版

    《Java开发技术大全》是一...这本书深入浅出地讲解了Java开发的各个方面,无论是初学者还是有经验的开发者,都能从中受益。通过学习,读者将能够熟练运用Java进行软件开发,并为进阶到更高级的技术领域打下坚实的基础。

    传智播客韩顺平Java视频教程完整版 [30.16G]

    【描述】中的“韩顺5D”可能是笔误,实际应指韩顺平的授课风格或教学方法,通常他以其深入浅出的教学方式和丰富的实战经验,使得复杂的编程概念易于理解。"30.16G"则表示该教程的容量,暗示了内容的详尽和深度。 ...

    java之浅谈深说--教你如何成长

    1. **反射与代理**:掌握反射机制,学会使用动态代理。 2. **泛型**:理解泛型的概念及其应用场景。 3. **注解**:了解注解的用法以及如何自定义注解。 4. **Spring框架**:Spring是目前最流行的Java企业级开发框架...

    JAVA案例开发集锦

    这本书深入浅出地展示了Java在实际项目中的应用,是提高编程技能和解决问题能力的重要参考资料。标签“JAVA案例”进一步强调了本书的核心内容——通过具体的实例来学习和理解Java编程。 书中可能包含以下重要知识点...

    张孝祥Java 就业培训教程

    该教程以中文撰写,适合国内读者阅读,内容深入浅出,易于理解,是计算机学习者理想的自学资料。 Java作为一门广泛应用的编程语言,广泛应用于企业级应用开发、移动应用(Android)、大数据处理等多个领域。张孝祥...

    java面试,经典的八股文208题测试

    - 动态代理是反射的一个重要应用,如 Java 中的 Proxy 类和动态生成的字节码。 5. **对象拷贝** - 浅拷贝和深拷贝的概念,以及如何实现对象的克隆。 - 掌握 Cloneable 接口和 `clone()` 方法的使用。 6. **Java...

    Java 面试宝典 - v1.1

    这份资料深入浅出地讲解了Java编程语言的核心概念、最佳实践以及面试中常问的问题,涵盖了从基础到高级的各种知识点。 一、Java基础 在Java面试中,基础扎实是必不可少的。这包括对Java语法的理解,如类、对象、...

    Java最常见的面试题208道.docx

    以上只是部分内容,完整的208道面试题涵盖了更多深入的Java知识,包括设计模式、Spring框架、Mybatis、RabbitMQ、Kafka、Zookeeper、MySQL、Redis、JVM优化等方面,每一道题目都值得深入探讨和学习。

    JAVA 208道面试题.pdf

    根据提供的文件内容,下面详细阐述了Java相关的面试知识点: ### Java基础 #### JDK与JRE的区别 ...以上为根据文件内容提炼出的Java面试知识点,希望能帮助读者朋友们准备面试和深入了解Java编程语言。

Global site tag (gtag.js) - Google Analytics