美文网首页
Java 面试系列:JDK 原生动态代理是怎么实现的 + 面试题

Java 面试系列:JDK 原生动态代理是怎么实现的 + 面试题

作者: you的日常 | 来源:发表于2020-12-12 23:12 被阅读0次

    反射
    反射机制是 Java 语言提供的一种基础功能,赋予程序在运行时自省(introspect)的能力。简单来说就是通过反射,可以在运行期间获取、检测和调用对象的属性和方法。

    反射的使用场景
    在现实中反射的使用场景有很多,比如以下几个。

    使用场景一:编程工具 IDEA 或 Eclipse 等,在写代码时会有代码(属性或方法名)提示,就是因为使用了反射。

    使用场景二:很多知名的框架,为了让程序更优雅更简洁,也会使用到反射。

    例如,Spring 可以通过配置来加载不同的类,调用不同的方法,代码如下所示:

    <bean id="person" class="com.spring.beans.Person" init-method="initPerson">
    </bean>
    复制
    例如,MyBatis 在 Mapper 使用外部类的 SQL 构建查询时,代码如下所示:

    @SelectProvider(type = PersonSql.class, method = "getListSql")
    List<Person> getList();
    class PersonSql {
    public String getListSql() {
    String sql = new SQL() {{
    SELECT("*");
    FROM("person");
    }}.toString();
    return sql;
    }
    }
    复制
    使用场景三:数据库连接池,也会使用反射调用不同类型的数据库驱动,代码如下所示:

    String url = "jdbc:mysql://127.0.0.1:3306/mydb";
    String username = "root";
    String password = "root";
    Class.forName("com.mysql.jdbc.Driver");
    Connection connection = DriverManager.getConnection(url, username, password);
    复制
    当然反射还有其他很多类似的使用场景,这里就不一一列举,读者可以举一反三,想想在平常的开发中,还有哪些使用了反射功能的场景。

    反射的基本使用
    下来我们通过反射调用类中的某个方法,来学习反射的基本使用。

    使用反射调用类中的方法,分为三种情况:

    调用静态方法
    调用公共方法
    调用私有方法
    假设有一个实体类 MyReflect 包含了以上三种方法,代码如下:

    package com.interview.chapter4;
    class MyReflect {
    // 静态方法
    public static void staticMd() {
    System.out.println("Static Method");
    }
    // 公共方法
    public void publicMd() {
    System.out.println("Public Method");
    }
    // 私有方法
    private void privateMd() {
    System.out.println("Private Method");
    }
    }
    复制
    下面分别来看,使用反射如何调用以上三种类型的方法。

    ① 反射调用静态方法
    Class myClass = Class.forName("com.interview.chapter4.MyReflect");
    Method method = myClass.getMethod("staticMd");
    method.invoke(myClass);
    复制
    ② 反射调用公共方法
    Class myClass = Class.forName("com.interview.chapter4.MyReflect");
    // 创建实例对象(相当于 new )
    Object instance = myClass.newInstance();
    Method method2 = myClass.getMethod("publicMd");
    method2.invoke(instance);
    复制
    ③ 反射调用私有方法
    Class myClass = Class.forName("com.interview.chapter4.MyReflect");
    // 创建实例对象(相当于 new )
    Object object = myClass.newInstance();
    Method method3 = myClass.getDeclaredMethod("privateMd");
    method3.setAccessible(true);
    method3.invoke(object);
    复制
    反射使用总结
    反射获取调用类可以通过 Class.forName(),反射获取类实例要通过 newInstance(),相当于 new 一个新对象,反射获取方法要通过 getMethod(),获取到类方法之后使用 invoke() 对类方法进行调用。如果是类方法为私有方法的话,则需要通过 setAccessible(true) 来修改方法的访问限制,以上的这些操作就是反射的基本使用。

    动态代理
    动态代理可以理解为,本来应该自己做的事情,却交给别人代为处理,这个过程就叫做动态代理。

    动态代理的使用场景
    动态代理被广为人知的使用场景是 Spring 中的面向切面编程(AOP)。例如,依赖注入 @Autowired 和事务注解 @Transactional 等,都是利用动态代理实现的。

    动态代理还可以封装一些 RPC 调用,也可以通过代理实现一个全局拦截器等。

    动态代理和反射的关系
    JDK 原生提供的动态代理就是通过反射实现的,但动态代理的实现方式还可以是 ASM(一个短小精悍的字节码操作框架)、cglib(基于 ASM)等,并不局限于反射。

    下面我们分别来看:JDK 原生动态代理和 cglib 的实现。

    1)JDK 原生动态代理
    interface Animal {
    void eat();
    }
    class Dog implements Animal {
    @Override
    public void eat() {
    System.out.println("The dog is eating");
    }
    }
    class Cat implements Animal {
    @Override
    public void eat() {
    System.out.println("The cat is eating");
    }
    }

    相关文章

      网友评论

          本文标题:Java 面试系列:JDK 原生动态代理是怎么实现的 + 面试题

          本文链接:https://www.haomeiwen.com/subject/ngmebktx.html