谈谈反射机制,动态代理基于什么原理

简介: 谈谈反射机制,动态代理基于什么原理

谈谈反射机制,动态代理基于什么原理



Java 反射机制?


反射机制是Java语言提供的一种基础功能,赋予程序在运行时自省(introspect,官方用语)的能力。通过反射我们可以直接操作类或者对象,比如获取某个对象的类定义,获取类声明的属性和方法,调用方法或者构造对象,甚至可以运行时修改类定义。

反射提供的 Accessibleobject.setAccessible(boolean flag)。它的子类也大都重写了这个方法,这里的所谓 accessible可以理解成修饰成员的 public、 protected、 private,这意味着我们可以在运行时修改成员访问限制。

setAccessible 的应用场景非常普遍,遍布我们的日常开发、测试、依赖注入等各种框架中。比如,在O/R Mapping框架中,我们为一个Java实体对象,运行时自动生成 setter 和 getter 的逻辑。


class Employee {
    private int id;
    private String name;
    private int age;
    public Employee() {
    }
    public Employee(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    private void setId(int id) {
        this.id = id;
    }
    private int judge(int id) {
        return this.id - id;
    }
    private String sayHalo(String name) {
        return "Halo" + name;
    }
}
public class PrivateTest {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Employee em = new Employee(1, "Alex", 22);
        // 获取Class对象
        Class<?> emClass = em.getClass();
        // 获取特定的声明了的方法
        Method judgeMethod = emClass.getDeclaredMethod("judge", new Class[] { Integer.TYPE });
        // setAccessible(boolean flag)使所有成员可以访问,访问之前设置
        judgeMethod.setAccessible(true);
        // 获取所有声明的方法
        Method[] allMethods = emClass.getDeclaredMethods();
        // AccessibleObject.setAccessible(AccessibleObject[] array,boolean flag)
        //批量给访问权限
        AccessibleObject.setAccessible(allMethods, true);
        // 下面就可以通过反射访问了
        System.out.println(judgeMethod.invoke(em, new Object[] { 3 }));
        // or...
        for (Method method : allMethods) {
        }
    }
}

动态代理


动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制,很多场景都是利用类似机制做到的,比如用来包装RPC调用、面向切面的编程(AOP) 实现动态代理的方式很多,比如JDK自身提供的动态代理,就是主要利用了上面提到的反射机制。还有其他的实现方式,比如利用传说中更高性能的字节码操作机制,类似ASM、 Cglib(基于ASM)、 Javassist等

反射,引入运行时自省能力,赋予了Java语言令人意外的活力,通过运行时操作元数据或对象,Java可以灵活地操作运行时才能确定的信息。而动态代理,则是延伸岀来的一种广泛应用于产品开发中的技术,很多繁琐的重复编程,都可以被动态代理机制优雅地解决。


动态代理解决了什么问题?


首先,它是一个代理机制。设计模式中的代理模式,代理可以看作是对调用目标的一个包装,这样我们对目标代码的调用不是直接发生的,而是通过代理完成。其实很多动态代理场景,我认为也可以看作是装饰器( Decorator)模式的应用,通过代理可以让调用者与实现者之间解耦。比如进行RPC调用,框架内部的寻址、序列化、反序列化等。


JDK 动态代理


JDK  动态代理例子,实现了对应的 InvocationHandler ,然后以接口 Hello 为纽带,为被调用目标构建代理对象,进而应用程序就可以用代理对象间接运行调用目标的逻辑。


interface Hello{
    void sayHello();
}
class HelloImpl implements Hello{
    public void sayHello() {
        System.out.println("Hello World");
    };
}
class MyInvocationHandler implements InvocationHandler{
    private Object target;
    public MyInvocationHandler(Object target){
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Invocking sayHello");
        Object result = method.invoke(target, args);
        return result;
    }
}
public class MyDyamicProxy {
    public static void main(String[] args) {
         HelloImpl hello = new HelloImpl();
         MyInvocationHandler hadler = new MyInvocationHandler(hello);
         // 构造代码示例
         Hello myHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), hadler);
         // 调用代理方法
         myHello.sayHello();
    }
}

但是 JDK 动态代理有个局限,它只能为接口创建代理,返回的代理对象也只能转换到接口类型,如果一个类没有接口,或者希望代理非接口中定义的方法。那 JDK 动态代理无法实现。


JDK 动态代理优点


  • 最小化依赖关系,减少依赖意味着简化开发和维护, JDK 本身支持,比 CGLIb 可靠
  • 平滑进行 JDK 版本升级,而字节码库通常需要进行更新保证最新 Java 上能够使用。
  • 代码实现简单


CGLIB 动态代理


CGLIb 动态代理使用的是字节码技术, 采用的方式是创建代理类的子类,继承的方式

import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class CglibProxyHandler implements MethodInterceptor {
    /**
     * 维护目标对象
     */
    private Object target;
    public Object getProxyInstance(final Object target) {
        this.target = target;
        // Enhancer类是CGLIB中的一个字节码增强器,它可以方便的对你想要处理的类进行扩展
        Enhancer enhancer = new Enhancer();
        // 将被代理的对象设置成父类
        enhancer.setSuperclass(this.target.getClass());
        // 回调方法,设置拦截器
        enhancer.setCallback(this);
        // 动态创建一个代理类
        return enhancer.create();
    }
    @Override
    public Object intercept(Object object, Method method, Object[] args,
            MethodProxy methodProxy) throws Throwable {
        System.out.println("代理先进行谈判……");
        // 唱歌需要明星自己来唱
        Object result = methodProxy.invokeSuper(object, args);
        System.out.println("演出完代理去收钱……");
        return result;
    }
 }
public class Client {
    public static void main(String[] args) {
        Star realStar = new RealStar();
        Star proxy = (Star) new CglibProxyHandler().getProxyInstance(realStar);
        proxy.sing();
    }
 }


CGLIB 动态代理优点


  • 调用对象可以不实现接口,可以打破 JDK  动态代理的限制
  • 只关心操作的类,不必为其他相关类增加工作量
  • 高性能

从性能角度,有人曾经得出结论说JDKProxγ比cgliB或者 Javassist慢几十倍。坦白说,不去争论具体的 benchmark细节,在主流JDK版本中,JDK Proxy在典型场景可以提供对等的性能水平,数量级的差距基本上不是广泛存在的。而且,反射机制性能在现代JDK中,自身已经得到了极大的改进和优化,同时,JDK很多功能也不完全是反射,同样使用了ASM进行字节码操作。


动态代理的应用


动态代理应用非常广泛,虽然最初多是因为RPC等使用进入我们视线,但是动态代理的使用场景远远不仅如此,它完美符合 Spring AOP等切面编程。简单来说它可以看作是对OOP的一个补充,因为OOP对于跨越不同对象或类的分散、纠缠逻辑表现力不够,比如在不同模块的特定阶段做一些事情,类似日志、用户鉴权、全局性异常处理、性能监控,甚至事务处理等,你可以參考下面这张图。

相关文章
|
1月前
|
Java
【编程进阶知识】静态代理、JDK动态代理及Cglib动态代理各自存在的缺点及代码示例
本文介绍了三种Java代理模式:静态代理、JDK动态代理和Cglib动态代理。静态代理针对特定接口或对象,需手动编码实现;JDK动态代理通过反射机制实现,适用于所有接口;Cglib动态代理则基于字节码技术,无需接口支持,但需引入外部库。每种方法各有优缺点,选择时应根据具体需求考虑。
21 1
|
2月前
|
安全 Java 编译器
Java反射的原理
Java 反射是一种强大的特性,允许程序在运行时动态加载、查询和操作类及其成员。通过 `java.lang.reflect` 包中的类,可以获取类的信息并调用其方法。反射基于类加载器和 `Class` 对象,可通过类名、`getClass()` 或 `loadClass()` 获取 `Class` 对象。反射可用来获取构造函数、方法和字段,并动态创建实例、调用方法和访问字段。虽然提供灵活性,但反射会增加性能开销,应谨慎使用。常见应用场景包括框架开发、动态代理、注解处理和测试框架。
|
1月前
|
IDE Java 编译器
java反射机制原理
java反射机制原理
55 0
|
3月前
|
设计模式 Java 中间件
静态代理和动态代理的区别以及实现过程
这篇文章通过示例代码讲解了静态代理和动态代理在Java中的使用方式和区别,重点介绍了动态代理的实现原理及其在Spring框架中的应用。
静态代理和动态代理的区别以及实现过程
|
6月前
|
设计模式 Java
java反射基础
本文主要针对java中的反射基础知识进行讲解
48 0
|
6月前
|
Java 开发者 Spring
什么是静态代理和动态代理,两者的区别(笔记)
什么是静态代理和动态代理,两者的区别(笔记)
208 0
|
设计模式 缓存 SpringCloudAlibaba
浅析动态代理原理与实现
代理是一种软件设计模式,目的地希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法。这个就好比 商户---->明星经纪人(代理)---->明星这种模式。我们可以不通过直接与明星对话的情况下,而通过明星经纪人(代理)与其产生间接对话
142 0
浅析动态代理原理与实现
|
设计模式 监控 Java
|
存储 设计模式 缓存
一直在使用JDK动态代理, 不明白原理如何实现?
一直在使用JDK动态代理, 不明白原理如何实现?
一直在使用JDK动态代理, 不明白原理如何实现?
|
Java Android开发
Java反射技术详解
Java反射技术详解
3408 3
Java反射技术详解