综合

spring反射机制

时间:2010-12-5 17:23:32  作者:探索   来源:焦点  查看:  评论:0
内容摘要:Spring 的反射机制,说白了就是让你在运行时才决定“用哪个类、调哪个方法、改哪个字段”。编译期你写的是 Class<?>、Method、Field 这些抽象概念,真正跑起来才把具体类拽

Spring 的反射反射机制,说白了就是机制让你在运行时才决定“用哪个类、调哪个方法、反射改哪个字段”。机制编译期你写的反射是 Class<?>、Method、机制Field 这些抽象概念,反射真正跑起来才把具体类拽出来干活。机制没有它,反射Spring 的机制依赖注入、AOP、反射注解解析基本都转不动。机制

我最早对反射有感觉,反射是机制看 Spring 怎么把 @Autowired 塞进一个私有字段。字段是反射 private 的,外面根本碰不到,但 Spring 拿到 Field 对象后直接 setAccessible(true),然后 field.set(bean, dependency),就这么硬塞进去了。当时觉得有点“暴力”,可它确实管用。你写业务代码时不会这么干,但框架层需要这种绕过编译期检查的能力。

Spring 里反射出现最密集的地方,是 bean 的实例化阶段。配置文件或注解里只给了类名,比如 com.example.OrderService,Spring 得先 Class.forName() 拿到 Class 对象,再找构造器。默认走无参构造,clazz.getDeclaredConstructor().newInstance() 就创建出实例。如果构造器有参数,比如构造器注入,Spring 会先解析参数类型,再递归去容器里找匹配的 bean,最后 constructor.newInstance(args)。整个过程编译期完全不知道 OrderService 长什么样,全靠运行时拼出来。

方法调用也一样。AOP 代理里,@Before、@Around 这些通知最终要落到目标方法上。Spring 拿到 Method 对象后,method.invoke(target, args) 就完事了。但这里有个细节:如果目标方法是 private 的,invoke 会抛 IllegalAccessException,得先 setAccessible(true)。JDK 17 之后模块化限制更严,有些包默认不开放反射,Spring 6 为此改了不少内部实现,比如用 MethodHandles 替代部分反射调用,性能更好,权限检查也更细。

注解解析更是离不开反射。你写 @Transactional,Spring 得知道这个注解贴在哪个类、哪个方法上。它通过 clazz.getAnnotations() 或 method.getAnnotation(Transactional.class) 拿到注解实例,再读里面的属性,比如 propagation、isolation。没有反射,注解就只是源码里的标记,运行时毫无意义。Spring 的 AnnotationUtils 还处理了元注解、组合注解这些复杂情况,底层还是 getDeclaredAnnotations() 那一套。

不过反射不是没代价。每次 getMethod、invoke 都有安全检查和参数装箱,比直接调用慢不少。Spring 做了缓存,ReflectionUtils 里把 Method、Field 对象存进 ConcurrentHashMap,避免重复查找。但 invoke 本身的开销躲不掉,所以 Spring 在关键路径上会生成字节码,比如 CGLIB 代理直接继承目标类,方法调用走的是子类重写,不是反射。反射更多用在启动阶段和低频操作上。

有个坑我踩过:泛型擦除。反射拿到的 Method 参数类型是 Object,不是 List<String>。Spring 解析泛型依赖时得靠 ParameterizedType、ResolvableType 这些工具,从 Method 的 getGenericParameterTypes() 里挖出真实类型。如果泛型嵌套深了,比如 Map<String, List<Order>>,解析代码会变得很绕。这也是为什么有些 Spring 泛型注入的 bug 特别难查。

反射让 Spring 有了“看透”字节码的能力,但用多了代码可读性会下降。你读 beanFactory.getBean("orderService") 很直观,可一旦追到 AbstractAutowireCapableBeanFactory 里,满屏都是 Class、Constructor、Method,得在脑子里模拟一遍运行时才明白。框架开发者习惯了这种思维,业务开发者偶尔调一次反射,往往是为了写通用工具,比如自定义注解处理器、对象拷贝、JSON 序列化。Spring 把反射封装得足够好,我们平时感知不到,但它一直在那儿,撑着整个容器运转。

最近更新
热门排行
copyright © 2026 powered by 力不从心网   sitemap