理解反射与动态代理

61 阅读2分钟

反射

  1. 理解
    • 反射是在字节码交由JVM解释时,可以动态的获取类的结构信息,进而实现动态访问。
    • 这种访问是对类、字段、方法信息的获取与使用,并不能进行更改,非要更改只能通过是ASM等字节码操作库去,动态创建修改类。当然如果想通过类加载器动态加载类依然是反射实现。
    • 反射的具体实现是由java.lang.reflect内提供的运行时检查和操作类属性和方法的API。
    • 值得一提的是反射时,会进行安全检查(有权限修饰符的检查,也有安全管理器对反射行为的检查)和类型检查,这种行为所带来的额外开销,会影响性能。

动态代理

  1. JDK动态代理

    • 动态代理是基于反射实现,用于动态创建代理对象,并拦截和处理方法调用。用两种实现方式:基于接口实现的动态代理(JDK动态代理)、基于类实现的动态代理(CGLIB)。
  2. JDK动态代理

    • 只能为实现了接口的类生成代理对象。
    • 通过Proxy类和InvocationHandler接口来实现。
    import java.lang.reflect.Proxy;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    interface MyInterface {
        void doSomething();
    }
    
    class MyInterfaceImpl implements MyInterface {
        public void doSomething() {
            System.out.println("Doing something...");
        }
    }
    
    class MyInvocationHandler implements InvocationHandler {
        private final Object target;
    
        public MyInvocationHandler(Object target) {
            this.target = target;
        }
    
        @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;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            MyInterface target = new MyInterfaceImpl();
            MyInterface proxyInstance = (MyInterface) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new MyInvocationHandler(target)
            );
            proxyInstance.doSomething();
        }
    }
    
  3. CGLIB动态代理

    • 可以代理没有实现接口的类,通过字节码生成技术创建代理类。
    • 主要使用Enhancer类来创建代理对象,并设置回调方法。
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    class MyClass {
        public void doSomething() {
            System.out.println("Doing something...");
        }
    }
    
    class MyMethodInterceptor implements MethodInterceptor {
        @Override
        public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("Before method call");
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("After method call");
            return result;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(MyClass.class);
            enhancer.setCallback(new MyMethodInterceptor());
    
            MyClass proxy = (MyClass) enhancer.create();
            proxy.doSomething();
        }
    }
    

应用场景

  1. 反射应用场景

    • 序列化与反序列化:通过反射获取对象字段信息进行序列化和反序列化。
    • Spring框架:Spring利用反射机制实现控制反转(IoC)和依赖注入(DI)。
    • 动态加载类:根据需要动态加载和操作类。
  2. 动态代理应用场景

    • AOP(面向切面编程):动态代理用于在运行时织入横切关注点(如日志记录、事务管理等)。
    • 装饰器模式:在运行时为对象提供额外的功能而无需修改原有类。