springboot反射执行private方法@Autowired字段为空

news2024/10/6 8:26:30

springboot反射执行private方法@Autowired字段为空

  • 描述
  • 错误复现
    • controller
    • service
      • ReflectServiceImpl
      • ReflectCallService
      • service 层切面
    • debug 结果图
      • 调用 reflectTest 方法(public反射)
      • 调用 reflectTest1方法(private反射)
  • 分析
  • 参考

描述

业务代码写完之后,懒得写mock代码,想直接暴露个接口测一下。但是因为目标方法是个private方法,所以不能直接用@Autowired注入类实例然后调用方法,便想到用反射来调用方法。然后,不试不知道,一试吓一跳。代码看着没问题,但是执行的时候报空指针异常(私有方法中有调用注入的其他service方法,这个service是空)

错误复现

controller

package com.yichen.casetest.controller;
// ... 其他import
@Controller
@RequestMapping("/test")
@Slf4j
public class TestController {

	@Autowired
    private ReflectServiceImpl reflectService;

    @PostMapping("/reflectTest")
    @ResponseBody
    public Object reflectTest(@RequestParam String name, @RequestParam String age){
        try {
            Method method = ReflectServiceImpl.class.getDeclaredMethod("reflectTest", String.class, String.class);
            return method.invoke(reflectService, name, age);

        }
        catch (Exception e){
            log.error("reflectTest出现错误{}", e.getMessage(), e);
        }
        return "error";
    }

    @PostMapping("/reflectTest1")
    @ResponseBody
    public Object reflectTest1(@RequestParam String name, @RequestParam String age){
        try {


            Method method = ReflectServiceImpl.class.getDeclaredMethod("reflectTest1", String.class, String.class);
            method.setAccessible(true);
            return method.invoke(reflectService, name, age);

        }
        catch (Exception e){
            log.error("reflectTest出现错误{}", e.getMessage(), e);
        }
        return "error";
    }

}

service

ReflectServiceImpl

package com.yichen.casetest.test.service.reflect.impl;

import com.yichen.casetest.test.service.reflect.ReflectCallService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class ReflectServiceImpl extends AbstractReflectService {

    @Autowired
    private ReflectCallService reflectCallService;

    public String reflectTest(String name, String age){
        String s = name + "-" + age;
        log.info("==> {} ==> ???", s);
        return reflectCallService.getName();
    }

    private String reflectTest1(String name, String age){
        String s = name + "-" + age;
        log.info("==> {} ==> ???", s);
        return reflectCallService.getName();
    }

    @Override
    public String getCombineData(String name, String age){
        String s = name + "-" + age;
        log.info("==> {}", s);
        return reflectCallService.getName();
    }

    @Override
    public String addressFrom() {
        rainNow();
        return reflectCallService.getName();
    }
}

ReflectCallService

package com.yichen.casetest.test.service.reflect;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ReflectCallService {

    @Autowired
    private TransactionService transactionService;


    public String getName(){
        transactionService.save();
        return "shanliang";
    }

}

service 层切面

package com.yichen.casetest.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;


@Aspect
@Component
@Slf4j
public class LogAspect {

    @Pointcut("execution(* com.yichen.casetest.test.service..*.*(..))")
//    @Pointcut("execution(* com.yichen.casetest.test.service.reflect.impl.ReflectServiceImpl.*(..))")
    public void logAspect() {

    }

    @Before("logAspect()")
    public void before(JoinPoint joinPoint){
        log.info("{} logAspect before", joinPoint.getTarget().getClass().getName());
    }

    @After("logAspect()")
    public void after(JoinPoint joinPoint){
        log.info(" {} logAspect after", joinPoint.getTarget().getClass().getName());
    }
}

debug 结果图

调用 reflectTest 方法(public反射)

public方法反射

可以看到,AutoWired字段是有值的,而是是一个cglib代理。

调用 reflectTest1方法(private反射)

私有方法反射

这里可以看到,AutoWired字段是个null

分析

如果把LogAspect注销,则privatepublic都可以通过反射执行。那么问题就是出在cglib代理身上了。具体看一下cglib代理的描述:

动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

可以看到它是通过生成子类的方法来创建代理。而java中子类是不继承父类的private方法的。这一点就是导致上面问题的原因。具体点说,因为启用了cglib代理,所以类的属性都通过代理绑定了,实际属性字段是null
在这里插入图片描述
如果是非private,以及非final修饰的方法,都会通过代理最终调用实际对象,而实际对象的@autowired字段是有值的。但如果是privatefinal修饰的方法,则会直接用属性,而此时属性为null,因为被代理了。。

参考

Spring AOP中private(踩坑)实践总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/37425.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python基础(四):Python必需掌握基础注释、变量、输出

文章目录 Python必需掌握基础注释、变量、输出 一、注释 1、作用 2、分类及语法 3、快速体验 4、总结 二、变量 1、作用 2、定义变量 三、输出 1、格式化符号 2、体验 3、转义字符 4、结束符 Python必需掌握基础注释、变量、输出 14天学习训练营导师课程&#xf…

[附源码]计算机毕业设计JAVA汽车租赁系统

[附源码]计算机毕业设计JAVA汽车租赁系统 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis M…

自动化运维CICD

目录 概述 为什么持续集成和发布可以提高效率 如何实现 1、在linux服务器安装部署代码仓库 2、安装jenkins 使用shell脚本实现CICD 使用pipeline实现CICD 使用Blue Ocean实现CICD 概述 持续集成(Continuous Integration,CI)和持续发布&#xff0…

C/C++编译器配置——MinGW下载安装

一. 前言 由于重装Win11系统,所有配置环境需要重装,对于C/C编译器MinGW配置做一个简单记录。 VS code等软件只提供编辑器,不提供编译器,因此windows系统上的C/C编译器需要通过安装MinGW实现。 二. 安装过程 在MinGW官网下载安装…

元宇宙产业委风语筑董事长李晖:到更多城市探索元宇宙“虚实结合”

导语:近期李晖和风语筑团队在深度探索“虚实结合”,布局元宇宙,谋求更多的创新。他受中国移动通信联合会元宇宙产业委员会委托,参与研究编撰《元宇宙十大技术》,并为该书做序《元宇宙:数字技术构建美好生活…

(十)延迟队列

延迟队列1. 延迟队列概念2. 延迟队列使用场景3. 整合Springboot4. TTL队列1. 代码架构图2.MQ组件配置文件类代码3. 消息生产者代码4. 消息消费者代码5. 延时队列优化1. 代码架构图2. 配置文件类代码3. 消息生产者代码6. Rabbitmq插件实现延迟队列1.安装延时队列插件2.代码实现7…

强强联合:OpenFeign 整合 Sentinel

书接前文: 微服务间的远程接口调用:OpenFeign 的使用 当项目中使用了 OpenFeign 后,可以很方便的进行远程服务调用,现在有个问题,假如远程服务出现故障了,调不了远程的接口,这边又着急等着返回…

系统启动其实就2个步骤BIOS和MBR(和之后的init/systemd的关系)

1.让计算机知道系统被放在哪个设备上了(BIOS) 计算机启动先启动bios,再去读MBR,MBR动了才会启动操作系统 2.让计算机知道哪里的分区是活动分区(MBR),找出来把系统引导到这里来 这两部类似于早先游戏里的红色警报和星…

springcloud20:springcloudalibaba之Nacos

为什么会出现spring alibaba 整个Netflix项目进入维护模式(不会添加新功能) springcloud: Nerflix:eureka ribbon feign ruul config springcloud一些小技术和其整合 此时内部出问题 SpringCloud 吸收了springcloud alibaba 此时springcloud带了了什么呢…

【笔试强训】Day 3

🌈欢迎来到笔试强训专栏 (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是Scort目前状态:大三非科班啃C中🌍博客主页:张小姐的猫~江湖背景快上车🚘,握好方向盘跟我有一起打天下嘞!送给自己的一句鸡汤&#x…

python中pytest库用法详解

Pytest 是用于测试 Python 应用的 Python 库。 官方文档:Full pytest documentation — pytest documentation 安装: pip install pytest pytest 测试发现约定规范 如果未指定任何参数,则在testpaths(如果已配置)或…

智慧水利数字孪生案例分享:数字孪生水利,助力三峡科学防洪防汛

长江是我国第一大河流,长江流域在我国经济发展中,占据举足轻重的地位。与此同时,长江流域频繁的洪涝、气象灾害,严重影响危害着流域内经济社会发展和生态环境,因此长江流域防汛管理被作为我国防洪体系中的关键工程。水…

阿里大咖纯手写的微服务入门笔记,从基础到进阶直接封神

前言 学习是一种基础性的能力。然而,“吾生也有涯,而知也无涯。”,如果学习不注意方法,则会“以有涯随无涯,殆矣”。 学习就像吃饭睡觉一样,是人的一种本能,人人都有学习的能力。我们在刚出生的…

通讯/服务器公司 测试|测试开发 面试真题|面经 汇总

浪潮 测试开发 一面 8.24 三个面试官。一个HR,两个技术官。 1 为什么选择测开?意向工作地点。 2 软件质量模型 3 测试要做哪些测试 4 集成测试和验收测试的区别? 5 黑盒测试和白盒测试的理解 6 知道哪些黑盒测试和白盒测试的方法 7 手工测试…

【观察】“中国算力网”向全社会开放,意味着什么?

今天,算力的重要性已被提升到全新的高度,这是因为算力作为数字经济时代新的生产力,对推动科技进步、行业数字化转型以及经济社会发展都发挥着至关重要的作用。根据中国信通院发布《中国算力发展指数白皮书(2022年)》显…

AE插件:流体渐变着色特效动画生成 Potok mac

Potok是After Effects的流体渐变插件。它会产生噪波并使用渐变对其进行着色。可以从UI Gradient Control或任何图层设置渐变。噪波可以用任何层掩盖。 Noise噪波:Potok 插件有一个内置的噪音发生器,有四种噪音类型。噪声动画可以无缝循环。此外&#xf…

ASM3142 USB 3.1控制芯片_ ASM3242 USB 3.2 2x2 控制器

一、ASM3142 USB 3.1控制芯片 ASM3142 USB 3.1控制芯片将成为通过USB进行快速数据传输的新标准。是全球最快的USB解决方案, 可提高性能并实现更高的功效,节省高达50%的功耗。 与ASM 2142 USB控制芯片相比,新的ASM 3142超高速USB控…

pandas数据分析:pandas基础函数入门教程【w3school学习笔记】

系列文章目录 pandas数据分析:十分钟快速入门重点函数速查 文章目录系列文章目录前言一、Pandas作用二、数据结构2.1 Series2.2 DataFrame三、读取数据3.1 读取CSV文件数据3.2 读取JSON文件数据四、分析数据五、清洗数据5.1 空值5.1.1 删除包含空值的行5.1.2 填充空…

微信群发工具,纯Python编写~

前言 接到了一个需求:现微信有8000好友,需要给所有好友发送一则一样的消息。网上搜索一番后,发现uiautomation 可以解决该需求,遂有此文。这是第五篇,也是最后一篇。 正如上面所见,这是uiautomition 微信群…

web前端期末大作业——网页制作基础大二dw作业——动画漫展学习资料电影模板(6页)

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置,有div的样式格局,这个实例比较全面,有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 文章目录一、网页介绍一…