
本文共 4040 字,大约阅读时间需要 13 分钟。
反射和动态代理虽然存在一定的关联,但将动态代理简单归结为反射机制的实现是不够全面的。实际上,动态代理是一种功能行为,其实现方式种类繁多。要理解这个问题,我们可以从反射与动态代理各自的特点和应用场景入手。
一、反射
反射是Java语言中提供的一项强大的功能,赋予程序在运行时自省的能力。通过反射,我们可以对类、对象进行操作,如获取类定义、获取属性和方法、调用方法、构造对象等。此外,反射甚至可以在运行时修改类定义。
1、获取类
反射中的类操作主要通过Class
对象来实现。可以通过以下几种方式获得Class
对象:
forName()
方法:使用Class.forName(name)
工厂方法。例如:Class myClass = Class.forName("com.example.MyClass");
getClass()
方法:通过对对象调用getClass()
方法。例如:MyClass obj = new MyClass();Class myClass = obj.getClass();
class
属性。例如:Class myClass = MyClass.class;
2、类的常用方法
反射中的Class
对象提供了多种方法来获取类信息和执行操作:
获取类名:使用
getName()
方法。如:String className = myClass.getName();
获取父类:使用
getSuperclass()
方法。如:Class superClass = myClass.getSuperclass();
获取实例对象:使用
newInstance()
方法。如:Object obj = myClass.newInstance();
获取属性:使用
getFields()
或getDeclaredFields()
方法。如:Field[] allFields = myClass.getFields();
Field[] declaredFields = myClass.getDeclaredFields();
获取方法:使用
getMethod()
或getDeclaredMethods()
方法。如:Method[] allMethods = myClass.getMethods();
Method[] declaredMethods = myClass.getDeclaredMethods();
调用静态方法:使用
invoke()
方法。如:Method staticMethod = myClass.getMethod("staticMethod");staticMethod.invoke(myClass);
调用非静态方法:需要有实例并设置访问权限。如下:
Object instance = myClass.newInstance();Method nonStaticMethod = myClass.getMethod("nonStaticMethod");nonStaticMethod.invoke(instance);
调用私有方法:需要设置可访问权限。如:
Method privateMethod = myClass.getDeclaredMethod("privateMethod");privateMethod.setAccessible(true);privateMethod.invoke(instance);
3、总结
反射操作的核心包括:
newInstance()
获取类实例。getMethod(…)
或`getDeclaredMethod(…)获取方法。setAccessible(true)
设置访问权限。需要注意的是:在反射中,使用get*
方法获取属性和方法时,携带“Declared”限定词的方法可以获取本类所有属性/方法(包括private属性/方法),而不携带则只能获取public属性/方法。
二、动态代理
动态代理是一种运行时动态构建代理和处理代理方法调用的机制,常用于RPC调用、AOP编程等场景。
动态代理的实现方式多种多样,主要可分为两类:
1、JDK Proxy 动态代理
JDK Proxy动态代理基于反射机制,通过实现InvocationHandler
接口来实现动态代理。代码示例如下:
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"); }}class AnimalProxy implements InvocationHandler { private Object target; public Object getInstance(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("调用前"); Object result = method.invoke(target, args); System.out.println("调用后"); return result; }}public static void main(String[] args) { AnimalProxy proxy = new AnimalProxy(); Animal dogProxy = (Animal) proxy.getInstance(new Dog()); dogProxy.eat();}
2、Cglib 动态代理
Cglib动态代理基于ASM框架,通过对目标类进行عية类生成,覆盖特定方法实现动态代理。适用于需要对 तरफ省方法实现扩展的场景。
class Panda { public void eat() { System.out.println("The panda is eating"); }}class CglibProxy implements MethodInterceptor { private Object target; public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("调用前"); Object result = methodProxy.invokeSuper(o, objects); System.out.println("调用后"); return result; }}public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Panda panda = (Panda) proxy.getInstance(new Panda()); panda.eat();}
三、JDK Proxy 与 Cglib Compared
JDK Proxy和Cglib的主要区别在于:
1 J DK Proxy的优势:
- 工作于标准类加载器下。
- 可靠性高。
- 维护成本低。
- 易于实现,依赖少。
2 Cglib 的优势:
- 支持普通类代理。
- 性能更高。
- 方法拦截更灵活。
3 综合考虑
在实际应用中,需要根据项目需要选择适合的动态代理实现方式。JDK Proxy适合用于需要标准化接口的场景,而Cglib则适合对具体类进行动态代理更复杂的场景。
本文所有示例代码均基于Java语言规范编写,避免使用任何外部资源或非标准编码。如需进一步了解Java反射与动态代理的具体应用,可以参考相关技术文档和实践案例。
发表评论
最新留言
关于作者
