如何在无HTTP请求下调用Spring Data JPA持久化方法?
Spring Data JPA 入门问题:非Web类调用持久化方法报空指针
我是Spring Data JPA新手,遇到一个入门问题:无法在不带@Controller或HTTP请求相关注解的类中调用持久化方法。我了解CommandLineRunner接口的run方法,但不想把核心代码都写在run方法里,希望像外观模式那样调用其他类及其自有方法。
实体类(Model)
package com.example.demo; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @Entity public class Expense { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String item; private float amount; public Expense () { } public Expense(String item, float amount) { this.item = item; this.amount = amount; } /* Getters and setters */ @Override public String toString() { return "Expense{" + "id=" + id + ", item=" + item + ", amount=" + amount + '}'; } }
Repository接口
package com.example.demo; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository public interface ExpenseRepository extends JpaRepository<Expense, Long>{ public List<Expense> findByItem (String item); @Query("SELECT e FROM Expense e WHERE e.amount >= :amount") public List<Expense> listItemsWithPriceOver(@Param("amount") float amount); }
持久化操作类
package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; public class ExpansePersistence { @Autowired private ExpenseRepository repository; public void expensePersistence() { repository.save(new Expense("tomato", 10)); repository.save(new Expense("banana", 6)); repository.save(new Expense("apple", 12)); Iterable<Expense> iterator = repository.findAll(); System.out.println("List all: "); iterator.forEach(item -> System.out.println(item.toString())); } }
主启动类
package com.example.demo; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication implements CommandLineRunner { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override public void run(String... args) throws Exception { new ExpensePersistence().expensePersistence(); } }
报错信息
Caused by: java.lang.NullPointerException: Cannot invoke "com.example.demo.ExpenseRepository.findAll()" because "this.repository" is null
解决方案
1. 将ExpansePersistence声明为Spring Bean
Spring的@Autowired仅对Spring容器管理的Bean生效,直接通过new创建的对象不在容器管理范围内,因此repository无法被注入,导致空指针。给ExpansePersistence添加@Component(或语义更贴合业务的@Service)注解:
package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; // 用@Service更贴合业务逻辑类 @Service public class ExpansePersistence { @Autowired private ExpenseRepository repository; public void expensePersistence() { // 原代码保持不变 } }
2. 在主类中注入ExpansePersistence而非手动实例化
修改DemoApplication,通过@Autowired注入Spring管理的ExpansePersistence Bean,再调用其方法:
package com.example.demo; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.beans.factory.annotation.Autowired; @SpringBootApplication public class DemoApplication implements CommandLineRunner { @Autowired private ExpansePersistence expensePersistence; public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override public void run(String... args) throws Exception { expensePersistence.expensePersistence(); } }
额外提示
- 注意类名拼写:
ExpansePersistence应为ExpensePersistence(拼写错误少了一个s),建议修正避免后续混淆。 - 业务逻辑类优先使用
@Service注解,@Component是通用Bean注解,@Service更具语义性,便于代码维护。
内容的提问来源于stack exchange,提问作者Staniack
相关产品推荐
相关产品推荐

