【问题标题】:How to update row value using JPA repository outside the controller?如何使用控制器外部的 JPA 存储库更新行值?
【发布时间】:2019-05-13 13:32:33
【问题描述】:

我试图从控制器外部(在某些线程内)更新表格行数据并总是得到“NullPointerException”。

线程代码:

public class S3Thread implements Runnable {

@Autowired  
private IAutomationService automationService;

@Override
public void run() { 
    Automation config = new Automation("user1","success");
    automationService.updateAutomation(config);
 }
}

以下行引发了 NullPointer 异常: 自动化服务.updateAutomation(config);

注意:我能够从控制器类创建/更新。仅在线程中。

【问题讨论】:

  • 如何调用run() 方法?根据您初始化S3Thread 类的方式,@Autowired 注释可能无法正常工作。
  • S3Thread 类既不是服务类也不是组件类
  • S3Thread thread1 = new S3Thread();线程 t0 = 新线程(线程 1); t0.start();
  • @Autowired 在这种情况下将不起作用,因为 S3Thread 类是以编程方式实例化的。不受 Spring 管理
  • 需要提供 IAutomationService 实现。使用某些工厂或在创建 S3Thread 类的实例时

标签: java spring-boot jpa crud


【解决方案1】:

嗯,这是经典的Why is my Spring @Autowired field null 案例。您自己创建 S3Thread 实例,因此不会向其中注入任何 bean。

考虑到你只是想在一个单独的线程中做某事,你可以考虑使用@Async:

@Async
public void updateAutomationConfiguration() {
    Automation config = new Automation("user1", "success");
    automationService.updateAutomation(config);
}

注意事项:

  • 您必须将 @EnableAsync 注释添加到任何配置类(例如您的主类)中才能使这项工作。
  • Spring 默认使用代理,这意味着你不能将这个updateAutomationConfiguration() 类添加到你的控制器本身。直接调用同一 bean 中的方法会绕过代理逻辑。解决方案是将此方法放在一个单独的 bean 中,该 bean 可以从控制器内部自动装配和调用。我在this answer 中提供了有关替代解决方案的更详细答案。

Spring 还有一个creating asynchronous methods 的入门指南。


另外,还有一些方法可以执行asynchronous calls within controllers,例如在控制器中使用CompletableFuture:

@PutMapping("/automation/configuration")
public CompletableFuture<String> updateAutomationConfiguration() {
    return CompletableFuture.supplyAsync(() -> {
        Automation config = new Automation("user1", "success");
        return automationService.updateAutomation(config);
    });
}

相关:How to create a non-blocking @RestController webservice in Spring?

【讨论】:

    【解决方案2】:

    Spring不会扫描你的runnable,因为它没有用@Component注解。尝试用@Component/@Service注解它。 不过不要忘记设置范围所需的范围!

    【讨论】:

    • 我尝试使用 @Component 进行注释并获取 org.springframework.beans.factory.BeanCreationException: while run application
    • 上下文初始化期间遇到异常 - 取消刷新尝试:org.springframework.beans.factory.BeanCreationException:创建文件 [C:\Users\Manigandan.Seetharam\Documents 中定义的名称为 's3Thread' 的 bean 时出错\workspace-spring-tool-suite-4-4.2.1.RELEASE\E2E_Automation\target\classes\com\smarsh\e2e\egw\S3Thread.class]:通过构造函数的 Bean 实例化失败;嵌套异常是 org.springframework.beans.BeanInstantiationException:无法实例化 [com.smarsh.e2e.egw.S3Thread]:构造函数抛出异常;嵌套异常是 java.lang.NullPointerException
    【解决方案3】:

    您的问题有两种可能的解决方案:

    您需要通过使用@Service 或@Component 注释它并在调用类上自动装配它来使S3Thread 类成为服务,或者您可以使用构造函数来初始化您的automationService,例如private IAutomationService automationService = new AutomationService();

    【讨论】:

    • IAutomationService 是一个接口,我们不能为此创建 obj
    • 那么哪个类实现了IAutomationService?
    • @Service 公共类 AutomationService 实现 IAutomationService{
    【解决方案4】:

    由于您的线程类不是由 spring 管理的,因此您将无法在 S3Thread 类中注入 spring 管理的 bean。

    为了做到这一点,您需要创建一个应挂钩到 Spring 生命周期的类或工厂。

    一旦您拥有该类,您就可以获取适当的 bean 并将引用传递到/或直接在 S3Thread 类中使用。像这样的

    @Component
    public class ApplicationContextUtils implements ApplicationContextAware {
    
        private static ApplicationContext ctx;
    
        @Override
        public void setApplicationContext(ApplicationContext appContext)
        {
            ctx = appContext;
    
        }
    
        public static ApplicationContext getApplicationContext() {
            return ctx;
        }
    }
    
    public class S3Thread implements Runnable {
    
    
    @Override
    public void run() { 
        Automation config = new Automation("user1","success");
     IAutomationService automationService= 
          ApplicationContextUtils.getApplicationContext().getBean(IAutomationService .class);
        automationService.updateAutomation(config);
     }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-02
      • 2021-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-08
      • 2016-06-19
      相关资源
      最近更新 更多