SpringBoot【问题 01】借助@PostConstruct解决使用@Component注解的类用@Resource注入Mapper接口为null的问题(原因解析+解决方法)

简介: SpringBoot【问题 01】借助@PostConstruct解决使用@Component注解的类用@Resource注入Mapper接口为null的问题(原因解析+解决方法)

1. 说明

有些时候我们需要一个管理类,类似 xxxManager 来处理共享的基础数据,它要在项目启动时就进行初始化且查询数据库,而且查询语句不复杂,写一整套的Service或者使用MyBatis的查询API有点儿繁琐,此时写一个简单的Mapper接口就优雅许多。

2. 代码实现

为了简洁,删掉部分不必要的备注,下边是Mapper接口:

/**
 * 集中管理非单表操作的SQL
 */
@Mapper
public interface ComplexSqlMapper {
    // 查询 view_manager 表全部数据
    @Select(" select * from view_manager ")
    List<ViewEntity> getViewManagerAllList();
}

下面是管理类,这里没有使用Doc注释:

/**
 * 查询并处理 view_manager 表数据(为了简洁这里是示例代码 真正的处理要比这个复杂)
 */
@Component
public class ViewManager {
  // Mapper 注入
  @Resource
    private ComplexSqlMapper complexSqlMapper;
    // 处理结果保存
    private Map<String, String> views = new HashMap();
    // 初始化时查询 view_manager 表数据
    private ViewManager() {
      List<ViewEntity> viewEntityList= complexSqlMapper.getViewManagerAllList();
      // 处理数据
      viewEntityList.forEach(ve-> {
            views.put(ve.getId(), ve.getName());
        });
    }
}

3. 原因解析

项目启动时有NPE,Debug才发现 complexSqlMapper 是null。我首先想到的是 Mapper 文件没有被检测到,然后确认了启动类里的 org.mybatis.spring.annotation.MapperScan 信息:

@SpringBootApplication
@MapperScan(basePackages = "com.example.demo.**.mapper")
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

并没有写错路径,那我们仔细回看 ViewManager 类就会发现 complexSqlMapper 是当作类的成员变量被注入的,那也就是说需要先实例化 ViewManager 类然后再注入 complexSqlMapper,可是我们在类的构造器里就调用了 complexSqlMapper 此时构造器没有执行完,ViewManager 也就没被实例化,那么 complexSqlMapper 自然是个null。至此通过构造器使用 Mapper 查询数据的计划落空了。

4. 问题解决

那就没有方法了吗 ❓ 怎么可能 ❗️ Spring早就想到了你想到的 😏 使用 @PostConstruct 注解的方法将会在依赖注入完成后被自动调用。

改造后的代码【这里只贴出核心代码 无关备注也省略了】

@Component
public class ViewManager {
  @Resource
    private ComplexSqlMapper complexSqlMapper;
    private Map<String, String> views = new HashMap();
    @PostConstruct
    private void init() {
        List<ViewEntity> viewEntityList= complexSqlMapper.getViewManagerAllList();
        viewEntityList.forEach(ve-> {
            views.put(ve.getId(), ve.getName());
        });
  }
}

改造后的代码,项目启动时由于 @Component 注解,ViewManager 类会被实例化并交给容器管理,此时使用的是 ViewManager 类的无参构造器。而 @PostConstruct 注解的 init 方法会待 complexSqlMapper 注入成功后调用。至此,xxxManager 的功能得以实现。

目录
相关文章
|
10月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
2969 0
|
9月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
9月前
|
XML JSON Java
【SpringBoot(三)】从请求到响应再到视图解析与模板引擎,本文带你领悟SpringBoot请求接收全流程!
Springboot专栏第三章,从请求的接收到视图解析,再到thymeleaf模板引擎的使用! 本文带你领悟SpringBoot请求接收到渲染的使用全流程!
613 3
|
10月前
|
Java 数据库 数据安全/隐私保护
Spring Boot四层架构深度解析
本文详解Spring Boot四层架构(Controller-Service-DAO-Database)的核心思想与实战应用,涵盖职责划分、代码结构、依赖注入、事务管理及常见问题解决方案,助力构建高内聚、低耦合的企业级应用。
1770 1
|
12月前
|
机器学习/深度学习 XML Java
【spring boot logback】日志logback格式解析
在 Spring Boot 中,Logback 是默认的日志框架,它支持灵活的日志格式配置。通过配置 logback.xml 文件,可以定义日志的输出格式、日志级别、日志文件路径等。
1955 5
|
12月前
|
Java 关系型数据库 数据库连接
Spring Boot项目集成MyBatis Plus操作PostgreSQL全解析
集成 Spring Boot、PostgreSQL 和 MyBatis Plus 的步骤与 MyBatis 类似,只不过在 MyBatis Plus 中提供了更多的便利功能,如自动生成 SQL、分页查询、Wrapper 查询等。
1062 2
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
927 140
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
1510 29
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
592 4

推荐镜像

更多
  • DNS