JAVA中的反射和动态代理

1.反射概念

在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

根据类的全限定名可以从JVM的方法区(类加载后存放在方法区中)获取类所有的信息(名称, 常量,属性,静态代码块,构造器,方法,接口,权限)

一个类的构成:名称, 常量,属性,静态代码块,构造器,方法,接口,权限,所以反射能够操作的东西也无非是这些内容

2.使用反射的方式

1.Class clazz = object.getClass //通过实例的getClass()方法获取类信息

2.Class clazz = Object.class      //直接获取

3.Class clazz = Class.forName("com.mysql.jdbc.Driver");//类加载器  

 本质调用public final native Class<?> getClass();直接调用本地方法去拿相关信息

3.世人都说反射慢

由于反射获取属性,方法,类加载等操作都是调用native接口和底层交互,所以导致了操作慢

但是JDK 其实对反射做了优化

1.优化一引入ReflectionData类,缓存类,对于读取Fields,Methods之类的操作方法返回的数据做了一次缓存,除了第一次读取,其他都是内存数据比较快

 private Field[] privateGetPublicFields(Set<Class<?>> traversedInterfaces) {
        checkInitted();
        Field[] res;
        ReflectionData<T> rd = reflectionData();
        if (rd != null) {
            //有缓存则返回
            res = rd.publicFields;
            if (res != null) return res;
        }

        // No cached value available; compute value recursively.
        // Traverse in correct order for getField().
        List<Field> fields = new ArrayList<>();
        if (traversedInterfaces == null) {
            traversedInterfaces = new HashSet<>();
        }

        // Local fields
        //没有则调本地方法获取
        Field[] tmp = privateGetDeclaredFields(true);
        addAll(fields, tmp);

        // Direct superinterfaces, recursively
        for (Class<?> c : getInterfaces()) {
            if (!traversedInterfaces.contains(c)) {
                traversedInterfaces.add(c);
                addAll(fields, c.privateGetPublicFields(traversedInterfaces));
            }
        }

        // Direct superclass, recursively
        if (!isInterface()) {
            Class<?> c = getSuperclass();
            if (c != null) {
                addAll(fields, c.privateGetPublicFields(traversedInterfaces));
            }
        }

        res = new Field[fields.size()];
        fields.toArray(res);
        //加入缓存
        if (rd != null) {
            rd.publicFields = res;
        }
        return res;
    }

2.优化二 对于Field,Method,Constructor的访问加入了代理类,在调用invoke(),或new Instance()等方法时当次数>15次时,创建代理类实现

 public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
            MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
            this.parent.setDelegate(var3);
        }

        return invoke0(this.method, var1, var2);
    }

1.动态代理概念

代理:为其他对象提供一种代理以控制对这个对象的访问

动态代理:程序运行过程中动态创建代理类

2.动态代理实现的两种方式

1). Java反射方式:实现java.lang.reflect.InvocationHandler接口,且实现invoke()方法

2). cglib方式:实现CGLIB提供的org.springframework.cglib.proxy.MethodInterceptor,且实现intercept()

举例:鹿晗是明星,找他工作先要找经纪人

/**
 * @author z
 * @date 2020-10-13 16:04
 **/
public class LuHan implements Star {

    @Override
    public void work() {
        System.out.println("鹿晗工作");
    }
}

Java反射方式案例:

public class ManagerProxy implements InvocationHandler {

    private Star star;
    //经纪人不一定只管一个人
    public ManagerProxy(Star star) {
        this.star = star;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("经过经纪人");
        Object o = method.invoke(star, args);
        return o;
    }

    public static void main(String[] args) {
        Star luhan = new LuHan();
        ManagerProxy proxy = new ManagerProxy(luhan);
        Star star = (Star) Proxy.newProxyInstance(
                luhan.getClass().getClassLoader(),
                luhan.getClass().getInterfaces(),
                proxy);
        star.work();
    }
}

Cglib方式案例: 

public class ManagerCglibProxy implements MethodInterceptor {

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("经过经纪人");
        Object o = methodProxy.invokeSuper(object, args);
        return o;
    }

    public static void main(String[] args) {
        ManagerCglibProxy cglibProxy = new ManagerCglibProxy();

        //cglib方式简洁很多,但是Enhancer不能代理final类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(LuHan.class);
        enhancer.setCallback(cglibProxy);
        Star star = (Star) enhancer.create();
        star.work();
    }

}
两次输出:
经过经纪人
鹿晗工作

cglib效率会比java反射方式高,但是cglib方式不能代理finl类 

 
<think>嗯,我现在要理解Java中的反射动态代理之间的关系。首先,我需要分别弄清楚什么是反射,什么是动态代理,然后再看看它们之间是如何关联的。 反射,我记得应该是Java中一种在运行时检查或修改类、方法、字段等的能力。比如可以通过Class对象获取类的信息,调用方法,访问字段,甚至创建实例。这样的话,反射允许程序在运行时动态地操作类的行为,而不需要在编译时就确定具体的类。 动态代理,好像是一种设计模式,用来创建代理对象,在运行时动态地处理对实际对象的方法调用。动态代理通常用于AOP(面向切面编程)或者各种装饰器模式中,比如日志记录、事务管理等。动态代理的核心是InvocationHandler接口,需要实现invoke方法,然后在其中定义代理的逻辑。 那反射动态代理的关系是什么呢?动态代理是不是依赖于反射机制来实现的?比如,当动态代理拦截到方法调用时,是否通过反射来调用实际对象的方法?可能还有其他的关联点,比如生成代理类的时候,可能用到了反射来获取接口的信息,或者动态生成字节码? 我记得Java中的动态代理主要是通过Proxy类InvocationHandler来实现的。Proxy.newProxyInstance()方法需要传入类加载器、接口数组InvocationHandler实例。这时候,Proxy会动态生成一个代理类,这个代理类实现了指定的接口,然后将所有的方法调用分派给InvocationHandler的invoke方法。在invoke方法中,可以通过反射调用实际对象的方法。 所以,动态代理在实现过程中确实用到了反射机制。反射允许动态代理在运行时获取被代理类的方法,并调用这些方法。而动态代理本身则是基于反射的一种高级应用,它封装了反射的细节,让开发者可以更方便地创建代理对象,而无需手动处理每个方法的反射调用。 有没有可能动态代理不仅仅依赖反射?比如,生成代理类的字节码可能用到其他技术,如Java的ASM库或者其他的字节码操作工具?不过,在标准库中,Java的Proxy类可能是在运行时生成代理类的字节码,然后通过反射来实例化这个类。这时候,虽然生成字节码的过程可能不直接使用反射,但动态代理的实现确实需要反射来调用方法。 总结一下,反射动态代理的基础,动态代理利用反射机制在运行时动态创建代理对象,并拦截处理方法调用。反射提供了动态调用方法的能力,而动态代理则构建在反射之上,提供更高层次的抽象,使得代理的创建使用更加方便。</think>### 反射动态代理的关系分步解析 #### 1. **反射(Reflection)的核心作用** 反射Java在**运行时**分析或操作类、方法、字段等的能力,核心类包括: - `Class`:获取类信息(如方法、字段、构造器) - `Method`:动态调用方法 - `Field`:访问或修改字段值 - `Constructor`:创建对象实例 **示例**:通过反射调用方法 ```java Class<?> clazz = MyClass.class; Method method = clazz.getMethod("doSomething"); Object instance = clazz.newInstance(); method.invoke(instance); // 反射调用方法 ``` #### 2. **动态代理(Dynamic Proxy)的核心机制** 动态代理用于**运行时生成代理对象**,拦截目标对象的方法调用。核心组件: - `java.lang.reflect.Proxy`:生成代理类的工厂 - `InvocationHandler`:定义代理逻辑(如增强方法) **示例**:创建动态代理 ```java // 目标对象 MyInterface target = new MyClass(); // 生成代理对象 MyInterface proxy = (MyInterface) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before method call"); Object result = method.invoke(target, args); // 反射调用目标方法 System.out.println("After method call"); return result; } } ); // 调用代理对象的方法 proxy.doSomething(); ``` #### 3. **反射动态代理的关系** - **依赖关系**:动态代理的实现**依赖反射**: 1. **生成代理类**:`Proxy`类在运行时通过反射分析目标接口,动态生成代理类的字节码。 2. **方法调用**:代理对象拦截方法后,通过反射的`Method.invoke()`调用目标方法。 - **封装关系**:动态代理是对反射的**高层封装**: - 开发者无需手动处理`Method`对象,只需实现`InvocationHandler`。 - 代理类自动实现接口的所有方法,简化了反射的复杂性。 #### 4. **关键区别** | **特性** | **反射** | **动态代理** | |----------------|-----------------------------|------------------------------| | 主要目的 | 运行时操作类的任意成员 | 拦截方法调用,增强逻辑 | | 使用场景 | 通用动态操作(如框架底层) | AOP、权限控制、日志等 | | 复杂度 | 需直接处理类、方法等细节 | 通过接口处理器简化逻辑 | #### 5. **典型应用场景** - **反射**:框架中加载配置文件定义的类(如Spring IoC)、序列化工具(如Jackson)。 - **动态代理**:Spring AOP的事务管理、RPC框架的客户端存根(Stub)生成。 #### 6. **总结** 反射动态代理的**底层基础**,提供动态调用方法的能力;动态代理反射的**高级应用**,封装反射细节,专注于方法拦截增强。两者结合,实现了Java的灵活性动态性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值