springboot 反射调用ServiceImpl时报错:java.lang.NullPointerExceptio、,mapper为null【解决方法】

springboot 反射调用ServiceImpl时报错:java.lang.NullPointerException、mapper为null【解决方法】

问题描述

在使用Spring Boot时,我们希望能够通过反射动态调用Service层中的方法,但在实践中发现,直接使用反射调用ServiceImpl中的方法时可能会导致NullPointerException异常。特别是当ServiceImpl中的依赖对象未正确注入时,这种情况更加常见。

问题分析

依赖注入机制失效:Spring Boot通常使用依赖注入来管理Service层的实例和依赖对象。然而,直接通过反射调用ServiceImpl的方法时,Spring的依赖注入机制可能会失效,导致依赖对象未能正确初始化,从而导致空指针异常。

依赖对象为null:当ServiceImpl中依赖的对象,如Mapper,未正确注入时,反射调用相关方法可能会导致依赖对象为null,进而触发空指针异常。

解决方案的选择:针对这样的问题,需要寻找方法来确保依赖注入机制的生效,以及正确地初始化ServiceImpl中的依赖对象,同时保证动态调用方法的合法性。

解决方案

创建SpringBootBeanUtil

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;


/**
 * Keafmd
 *
 * @ClassName: SpringBootBeanUtil
 * @Description:
 * @author: 牛哄哄的柯南
 * @date: 2024/4/7
 */
@Component
public class SpringBootBeanUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringBootBeanUtil.applicationContext == null) {
            SpringBootBeanUtil.applicationContext = applicationContext;
        }
    }

    /**
     * 获取applicationContext
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 通过name获取 Bean.
     * @param name
     * @return
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    /**
     * 通过class获取Bean.
     * @param clazz
     * @return
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * 通过name,以及Clazz返回指定的Bean
     * @param name
     * @param clazz
     * @return
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

}

编写调用方法 executeMethod

public Object executeMethod(String classAndMethodPath, Object... args) {
   try {
       // classAndMethodPath = "com.example.demo.Test.test"
       // 分割字符串,获取类名和方法名
       String[] split = classAndMethodPath.split("\\.");
       String methodName = split[split.length-1];
       String className = classAndMethodPath.replace("."+methodName,"");

       ApplicationContext applicationContext = SpringBootBeanUtil.getApplicationContext();

       //反射创建serviceimpi实体对象,和实体类
       Class<?> ServiceImplType = Class.forName(className);
       //反射设置方法参数。
       Class<?>[] parameterTypes = new Class[args.length];
       for (int i = 0; i < args.length; i++) {
           parameterTypes[i] = args[i].getClass(); 
       }
       Method method = ServiceImplType.getDeclaredMethod(methodName,parameterTypes);
       //在ApplicationContext中根据class取出已实例化的bean
       return method.invoke(applicationContext.getBean(ServiceImplType),args);

   } catch (Exception e) {
       // 处理异常
       e.printStackTrace();
   }
   return null;
}

调用

Object object = executeMethod("com.XXXXX.selectXxById","666666666");      

总结

以上就是springboot 反射调用ServiceImpl时报错:java.lang.NullPointerExceptio、,mapper为null【解决方法】的全部内容。

版权声明:
原创博主:牛哄哄的柯南
博主原文链接:https://keafmd.blog.csdn.net/
个人博客链接:https://www.keafmd.top/

看完如果对你有帮助,感谢点击下面的点赞支持!
[哈哈][抱拳]

在这里插入图片描述
加油!

共同努力!

Keafmd

感谢支持牛哄哄的柯南,期待你的三连+关注~~

keep accumulate for my dream【共勉】

                                                       ↓   ↓   ↓   合作 交流  ↓   ↓   ↓  

<think>好的,用户遇到了一个FreeMarker模板找不到的问题,错误信息是找不到"/templates/entity.java.ftl.ftl"。用户还提供了他们的配置代码,其中指定了实体类的模板路径为"/templates/entity.java.ftl"。我需要仔细分析这个问题。 首先,错误提示中的文件名是"entity.java.ftl.ftl",看起来像是重复了扩展名。这可能是因为在配置路径写错了。用户配置的是entity("/templates/entity.java.ftl"),而FreeMarker可能自动添加了.ftl扩展名,导致实际寻找的是entity.java.ftl.ftl。这候需要确认模板配置是否正确,是否应该省略.ftl扩展名。 接下来,我要回忆MyBatis-Plus Generator的模板配置机制。通常,在配置模板路径,不需要包含文件扩展名,因为FreeMarker会自动附加.ftl。例如,如果模板文件名为entity.java.ftl,在配置只需指定路径到文件名部分,如"/templates/entity.java",系统会自动补全.ftl。因此,用户当前的配置可能错误地包含了.ftl扩展名,导致FreeMarker在查找重复添加,形成双扩展名的问题。 另外,检查用户提供的TemplateConfig的配置。用户使用了.template(new TemplateConfig.Builder()...,其中entity方法指定了路径。如果路径中包含.ftl,那么FreeMarker在加载会尝试查找该路径加上.ftl扩展名,导致问题。正确的做法是路径中不包含.ftl扩展名,只需指定到模板文件的基本名。 还需要确认用户是否在正确的位置放置了模板文件。默认情况下,MyBatis-Plus Generator会在classpath下的/templates目录中查找模板。如果用户自定义了模板路径,需要确保文件实际存在于该路径,并且文件名正确,没有重复的扩展名。 可能的解决方案是修改模板配置,去掉路径中的.ftl扩展名。例如,将.entity("/templates/entity.java.ftl")改为.entity("/templates/entity.java")。同,确保模板文件的实际名称是entity.java.ftl,这样FreeMarker就能正确找到它。此外,检查文件路径是否正确,确认模板文件是否在项目的资源目录下的正确位置,比如src/main/resources/templates/entity.java.ftl。 总结用户的错误原因:模板路径配置错误,导致FreeMarker在解析生成了错误的文件名。需要调整配置中的路径,避免重复扩展名,并确保模板文件存放正确。</think>--- ### 一、问题分析 错误信息 `TemplateNotFoundException` 指出 FreeMarker **无法找到模板文件**,直接原因是配置的模板路径存在 **双重后缀名**(`.ftl.ftl`)。 通过你的配置 `.entity("/templates/entity.java.ftl")`,MyBatis-Plus 实际会拼接路径为 **`/templates/entity.java.ftl.ftl`**,导致文件无法加载。 --- ### 二、错误原因 #### 关键点:**模板路径配置规则** 1. **FreeMarker 自动补全后缀** 默认情况下,FreeMarker 会为模板路径**自动追加 `.ftl` 后缀**。 - 若配置路径为 `/templates/entity.java` → 实际加载 `/templates/entity.java.ftl` ✅ - 若配置路径为 `/templates/entity.java.ftl` → 实际加载 `/templates/entity.java.ftl.ftl` ❌ 2. **路径中的目录层级** MyBatis-Plus Generator 默认从 `classpath:/templates/` 目录下加载模板文件,需确保文件存放位置正确。 --- ### 三、解决方案 #### 1. **修正模板路径配置** 移除路径中的 `.ftl` 后缀,保持**基础模板名**即可: ```java .template(new TemplateConfig.Builder() .controller("") .service("") .serviceImpl("") .entity("/templates/entity.java") // 只保留基础名称,无需 .ftl 后缀 .build()) ``` #### 2. **检查模板文件存放位置** 确保模板文件 `entity.java.ftl` 位于项目的以下路径中: ``` src/main/resources/templates/entity.java.ftl ``` #### 3. **验证模板加载逻辑** 通过代码打印模板路径,确认最终加载路径: ```java // 调试代码(可临添加) System.out.println("模板路径: " + new ClassTemplateLoader(FreemarkerTemplateEngine.class, "/").getResource("/templates/entity.java").getPath()); ``` --- ### 四、完整配置示例 ```java AutoGenerator generator = new AutoGenerator(); // 模板配置(关键修正) TemplateConfig templateConfig = new TemplateConfig.Builder() .controller("") // 使用默认模板 .service("") // 使用默认模板 .serviceImpl("") // 使用默认模板 .entity("/templates/entity.java") // 自定义实体类模板(不带 .ftl 后缀) .build(); generator.setTemplate(templateConfig); ``` --- ### 五、扩展说明 #### 1. **自定义模板的两种方式** | 方式 | 说明 | |-----------------------|------------------------------------| | 覆盖默认模板 | 在 `resources/templates` 下创建同名模板文件(如 `entity.java.ftl`)| | 完全自定义模板路径 | 通过 `.entity("custom/path/entity")` 指定新路径 | #### 2. **常见错误排查** | 现象 | 原因 | 解决方案 | |------------------------------|----------------------------|----------------------------| | 双重后缀(`.ftl.ftl`) | 配置路径包含 `.ftl` 后缀 | 删除路径中的 `.ftl` 后缀 | | `FileNotFoundException` | 模板文件未放入 `resources` 目录 | 检查文件存放位置 | | 模板语法错误 | FreeMarker 渲染失败 | 使用 IDE 验证模板语法 | --- 通过修正路径后缀并确保文件存放位置正确,即可解决该模板加载问题。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛哄哄的柯南

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值