百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

啥?你还不懂Java反射机制与动态代理

ztj100 2025-02-15 18:23 6 浏览 0 评论

Java开发中反射和动态代理放有一定的相关性,但单纯的说动态代理是由反射机制实现的,其实是不够全面不准确的,动态代理是一种功能行为,而它的实现方法有很多。

一、反射

反射机制是Java的核心特性之一,它允许在程序运行时检查类的结构并对其进行操作。这种动态特性为程序提供了极高的灵活性,可以在运行时加载类、调用方法、修改字段值,甚至实例化对象。反射机制被广泛应用于各种框架和库中,如Spring、Hibernate、MyBatis等,它们通过反射实现了高度的动态性和灵活性。

通过反射,开发者可以:

  • 动态加载类及其依赖
  • 动态调用方法,而无需在编译时知道具体方法
  • 动态修改对象的字段,甚至是私有字段

尽管反射为开发者提供了强大的功能,但也伴随着一定的性能开销和安全隐患,因此在实际使用中需要谨慎。

1. 实现方式

想象你是一名厨师,而食谱就是一个类。食谱中记录了所有菜品的制作方法,而你作为厨师通过食谱(类)指导自己的烹饪过程。这就类似于反射机制,你可以在程序运行时查看类的结构并通过类中的方法制作“菜品”。

// 示例:获取类信息和方法
Class recipeClass = Class.forName("com.example.Recipe");
String recipeName = recipeClass.getName();
System.out.println("菜品名称: " + recipeName);


// 动态调用方法
Method cookMethod = recipeClass.getDeclaredMethod("cook");
cookMethod.invoke(recipeObject);  


2. 获取类(Class)对象

在使用反射机制时,第一步是获取Class对象。Java为此提供了三种方式:

1.通过forName() -> 示例:Class.forName(“People”)
2.通过getClass() -> 示例:new People().getClass()
3.class直接获取 -> 示例:PeopleImpl.class

2.1静态方法调用

使用 getMethod(xx) 获取到对应的方法,直接使用 invoke(xx)就可以了。

public static void main(String[] args) {
    Class myClass = Class.forName("example.People");
    // 调用静态(static)方法
    Method getSex = myClass.getMethod("getName");
    getSex.invoke(myClass);
}

2.2 普通方法调用

使用getMethod() 获取方法,可以声明需要传递的参数的类型。

Object object = myClass.newInstance();
Method method = myClass.getMethod("hello",String.class);
method.invoke(object,"word!");

2.3 调用私有方法

调用私有方法的关键是设置 setAccessible(true) 属性,修改访问限制,这样设置之后就可以进行调用

Method greetMethod = clazz.getDeclaredMethod("greet", String.class);
greetMethod.setAccessible(true); // 允许访问私有方法
greetMethod.invoke(personObj, "John Doe");  // 调用方法

3. 应用

反射机制在实际开发中有广泛的应用,尤其是在框架和工具开发中。以下是一些常见的应用场景:

  • 动态加载类与方法例如Spring框架通过反射来动态加载Bean对象并调用其初始化方法。
  • 序列化与反序列化例如JSON库(如Jackson和Gson)通过反射将JSON字符串转换为Java对象
  • 注解处理在Spring等框架中,通过反射扫描类上的注解并执行相应的逻辑。
  • 动态代理例如Java AOP(面向切面编程)利用动态代理实现方法的拦截和增强。


二、动态代理

动态代理是一种方便运行时动态构建代理、动态处理代理方法调用的机制,很多场景都是利用类似机制做到的,比如用来包装 RPC 调用、面向切面的编程(AOP)。

实现动态代理的方式很多,比如 JDK 自身提供的动态代理,就是主要利用了上面提到的反射机制。还有其他的实现方式,比如利用传说中更高性能的字节码操作机制,类似 ASM、cglib(基于 ASM)等。

Java的动态代理主要有两种方式:

1. JDK动态代理

JDK动态代理是通过实现接口的方式生成代理类。Proxy类和InvocationHandler接口是JDK动态代理的核心。

public class CalculatorProxy implements InvocationHandler {
    private final Object target;


    public CalculatorProxy(Object target) {
        this.target = target;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法 " + method.getName() + " 开始执行");
        Object result = method.invoke(target, args);
        System.out.println("方法 " + method.getName() + " 执行完毕");
        return result;
    }


    public static Object newProxyInstance(Object target) {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new CalculatorProxy(target));
    }
}

注意:JDK Proxy 只能代理实现接口的类(即使是extends继承类也是不可以代理的)。

2. CGlib代理

JDK 动态代理机制只能代理实现了接口的类,CGlib 是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对 final 修饰的类进行代理。

CGlib 的调用通过实现 MethodInterceptor 接口的 intercept 方法,调用 invokeSuper 进行动态代理的,可以直接对普通类进行动态代理。

class CglibProxy implements MethodInterceptor {
    private Object target; // 代理对象
    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        // 设置父类为实例类
        enhancer.setSuperclass(this.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) {
    // CGLIB 动态代理调用
    CglibProxy proxy = new CglibProxy();
    Panda panda = (Panda)proxy.getInstance(new Panda());
    panda.eat();
}


3. 应用

动态代理主要用于 AOP 场景,例如日志、权限控制、事务管理等。动态代理还常用于 RPC 框架中实现远程服务调用的透明化。例如,Spring AOP 使用动态代理来实现切面编程,dubbo使用动态代理来实现远程调用。

三. 总结

Java的反射机制和动态代理为开发者提供了强大的动态功能,使得程序可以在运行时灵活地处理类、对象及其行为。虽然这些特性极大地增强了灵活性和可扩展性,但也带来了性能开销和安全隐患。因此,反射和动态代理的使用应该谨慎,尤其是在对性能有较高要求的场景下。

通过对反射机制和动态代理的深入理解,两者在实际开发中常常各自发挥作用,或者结合使用,以实现复杂的动态行为和灵活的系统设计。


如果这篇文章对您有所帮助,或者有所启发的话,帮忙给个赞 谢谢!!!

相关推荐

从IDEA开始,迈进GO语言之门(idea got)

前言笔者在学习GO语言编程的时候,GO语言在国内还没有像JAVA/Php/Python那样普及,绕了不少的弯路,要开始入门学习一门编程语言,最好就先从选择一个好的编程语言的开发环境开始,有了这个开发环...

基于SpringBoot+MyBatis的私人影院java网上购票jsp源代码Mysql

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目介绍基于SpringBoot...

基于springboot的个人服装管理系统java网上商城jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目介绍基于springboot...

基于springboot的美食网站Java食品销售jsp源代码Mysql

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目介绍基于springboot...

贸易管理进销存springboot云管货管账分析java jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目描述贸易管理进销存spring...

SpringBoot+VUE员工信息管理系统Java人员管理jsp源代码Mysql

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目介绍SpringBoot+V...

目前见过最牛的一个SpringBoot商城项目(附源码)还有人没用过吗

帮粉丝找了一个基于SpringBoot的天猫商城项目,快速部署运行,所用技术:MySQL,Druid,Log4j2,Maven,Echarts,Bootstrap...免费给大家分享出来前台演示...

SpringBoot+Mysql实现的手机商城附带源码演示导入视频

今天为大家带来的是基于SpringBoot+JPA+Thymeleaf框架的手机商城管理系统,商城系统分为前台和后台、前台用的是Bootstrap框架后台用的是SpringBoot+JPA都是现在主...

全网首发!马士兵内部共享—1658页《Java面试突击核心讲》

又是一年一度的“金九银十”秋招大热门,为助力广大程序员朋友“面试造火箭”,小编今天给大家分享的便是这份马士兵内部的面试神技——1658页《Java面试突击核心讲》!...

SpringBoot数据库操作的应用(springboot与数据库交互)

1.JDBC+HikariDataSource...

SpringBoot 整合 Flink 实时同步 MySQL

1、需求在Flink发布SpringBoot打包的jar包能够实时同步MySQL表,做到原表进行新增、修改、删除的时候目标表都能对应同步。...

SpringBoot + Mybatis + Shiro + mysql + redis智能平台源码分享

后端技术栈基于SpringBoot+Mybatis+Shiro+mysql+redis构建的智慧云智能教育平台基于数据驱动视图的理念封装element-ui,即使没有vue的使...

Springboot+Mysql舞蹈课程在线预约系统源码附带视频运行教程

今天发布的是由【猿来入此】的优秀学员独立做的一个基于springboot脚手架的Springboot+Mysql舞蹈课程在线预约系统,系统项目源代码在【猿来入此】获取!https://www.yuan...

SpringBoot+Mysql在线众筹系统源码+讲解视频+开发文档(参考论文

今天发布的是由【猿来入此】的优秀学员独立做的一个基于springboot脚手架的在线众筹管理系统,主要实现了普通用户在线参与众筹基本操作流程的全部功能,系统分普通用户、超级管理员等角色,除基础脚手架外...

Docker一键部署 SpringBoot 应用的方法,贼快贼好用

这两天发现个Gradle插件,支持一键打包、推送Docker镜像。今天我们来讲讲这个插件,希望对大家有所帮助!GradleDockerPlugin简介...

取消回复欢迎 发表评论: