如何通过Java反射访问Spring Cglib增强类中的成员字段
问题原因
你遇到的空值问题是CGLIB代理的特性导致的:
- CGLIB通过继承目标类的方式生成代理子类,代理类实例本身不会继承/持有父类的字段值
- 原始Controller的所有属性、业务逻辑都保存在代理对象内部持有的
目标对象实例中,你直接从代理对象反射读取父类字段,拿到的自然是未赋值的null
解决方案
通过Spring提供的AOP工具类先获取代理背后的原始目标对象,再对目标对象做反射操作即可,同时需要给私有字段设置可访问权限。
修改后的完整代码如下:
import org.springframework.aop.Advised; import org.springframework.aop.AopUtils; import org.springframework.stereotype.Component; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.web.bind.annotation.RestController; @Component public class TestProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { var annotation = AnnotationUtils.findAnnotation(bean.getClass(), RestController.class); if (annotation != null) { System.out.println("IM HERE"); if (UserController.class.isAssignableFrom(AopUtils.getTargetClass(bean))) { try { // 递归获取最内层的原始目标对象,兼容多层代理场景 Object targetBean = bean; while (AopUtils.isAopProxy(targetBean) && targetBean instanceof Advised) { targetBean = ((Advised) targetBean).getTargetSource().getTarget(); } // 直接从目标类获取字段 var f = UserController.class.getDeclaredField("service"); // 私有字段需要设置可访问权限 f.setAccessible(true); var obj = f.get(targetBean); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); } } return bean; } return bean; } }
注意事项
- 该实现依赖Spring AOP模块,常规Spring/Spring Boot Web项目都已默认引入,无需额外加依赖
- 如果项目开启了CGLIB代理的类缓存,拿到目标对象的逻辑不会产生额外性能开销
- 反射操作完成后不需要手动改回
setAccessible(false),JDK会自动回收该反射对象的访问权限配置
内容的提问来源于stack exchange,提问作者Goncalo Condeco
相关产品推荐
相关产品推荐

