两个原因导致Spring @Autowired注入的组件为空

简介: 两个原因导致Spring @Autowired注入的组件为空

文章目录

原文作者:Steve Claridge   原文链接:https://www.moreofless.co.uk/spring-mvc-java-autowired-component-null-repository-service/

译文

Spring框架大量使用了控制反转(IoC),让你可以进行类的注入,而不必担心它们的作用域,生存周期或者回收。

大家遇到的一个常见错误是,当自动装配一个类,尝试调用该类的方法时,发现该类的实例为null而导致空指针异常。那么,为什么Spring没有自动注入类呢?有两个可能的原因:

你手动实例化了一个类

@Controller
public class Controller {
  @GetMapping("/example")
  public String example() {
    MyService my = new MyService();
    my.doStuff();
  }
}
@Service
public class MyService() {
  @Autowired
  MyRepository repo;
  public void doStuff() {
    repo.findByName( "steve" );
  }
}
@Repository
public interface MyRepository extends CrudRepository<My, Long> {
  List<My> findByName( String name );
}

你好,2005呼叫并要求返回他们的代码。好吧,IoC就像是街上的帅小伙子一样,如果你使用的是Spring(自动注入),则需要一直使用它。这是Controller,  Service 和 Repository的代码片段,它们将导致NullPointerException。

@Controller
public class Controller {
  @GetMapping("/example")
  public String example() {
    MyService my = new MyService();
    my.doStuff();
  }
}
@Service
public class MyService() {
  @Autowired
  MyRepository repo;
  public void doStuff() {
    repo.findByName( "steve" );
  }
}

当它尝试访问MyRepository自动连接的存储库时,这将在Service中引发NullPointerException,这不是因为Repository的连接有任何问题,而是因为你使用MyService  my = new MyService()手动实例化了MyService。要解决此问题,需要自动注入MyService:

@Controller
public class Controller {
  @Autowired
  MyService service;
  @GetMapping("/example")
  public String example() {
    service.doStuff();
  }
}
@Service
public class MyService() {
  @Autowired
  MyRepository repo;
  public void doStuff() {
    repo.findByName( "steve" );
  }
}
@Repository
public interface MyRepository extends CrudRepository<My, Long> {
  List<My> findByName( String name );
}

你忘记在某个类使用组件注解或者它的扩展注解

Spring使用组件扫描来查找需要自动注入并放入到IoC容器中的类。基本上,Spring将扫描项目的类路径(或你指定的路径),找到所有@Component注解的类并将其用于自动装配。因此,如果你忘记注解一个类,则该类将不能自动注入,当你尝试使用它时,将得到一个空的实例,从而导致NullPointerException。

@ Service,@ Repository和@Controller都是@Component特殊情景下的子注解,因此要自动注入的任何类都必须使用其中之一进行注释。否则,自动注入将导致实例为空:

public class MyService {
  public void doStuff() {
  }
}

这样的是没有问题的:

@Service
public class MyService {
  public void doStuff() {
  }
}


本文仅是阅读英文文档练手,原文如下:

原文

 Two reasons why your Spring @Autowired component is null

The Spring framework makes heavy use of Inversion of Control (IoC) to  let you inject classes without having to worry about their scope,  lifetime or cleanup.

A common error people hit is when they autowire a class and when they  try to call a method on it find that it is null and they get a  NullPointerException. So why didn’t Spring auto-wire your class for you?  Here’s two possible reasons:

YOU INSTANTIATED THE A CLASS MANUALLY

Hi, 2005 called and asked for their code back. Yeah, OK, IoC is like  the cool kid on the block and if you are using Spring then you need to  be using it all the time. Here’s a code snippet of a Controller, Service  and Repository that will result in a NullPointerException.

@Controller
public class Controller {
  @GetMapping("/example")
  public String example() {
    MyService my = new MyService();
    my.doStuff();
  }
}
@Service
public class MyService() {
  @Autowired
  MyRepository repo;
  public void doStuff() {
    repo.findByName( "steve" );
  }
}
@Repository
public interface MyRepository extends CrudRepository<My, Long> {
  List<My> findByName( String name );
}

This will throw a NullPointerException in the service class when it  tries to access the MyRepository auto-wired Repository, not because  there is anything wrong with the wiring of the Repository but because  you instantiated MyService() manually with MyService my = new  MyService(). To fix this auto-wire the Service as well:

@Controller
public class Controller {
  @Autowired
  MyService service;
  @GetMapping("/example")
  public String example() {
    service.doStuff();
  }
}
@Service
public class MyService() {
  @Autowired
  MyRepository repo;
  public void doStuff() {
    repo.findByName( "steve" );
  }
}
@Repository
public interface MyRepository extends CrudRepository<My, Long> {
  List<My> findByName( String name );
}

YOU FORGOT TO ANNOTATE A CLASS AS A COMPONENT OR ONE OF ITS DESCENDANTS

Spring uses component scanning to find the classes that it needs to  auto-wire and insert into classes for IoC. Basically, Spring is going to  scan the project’s classpath (or paths you specified), find all of the  @Component classes and make them available for auto-wiring. So if you  forget to annotate a class it will not be auto-wired and when you try  and use it you will get a null and a NullPointerException.

@Service, @Repository and @Controller are all specializations of  @Component, so any class you want to auto-wire needs to be annotated  with one of them. So auto-wiring this will cause a null:

public class MyService {
  public void doStuff() {
  }
}

but this will work fine

@Service
public class MyService {
  public void doStuff() {
  }
}


目录
相关文章
|
11月前
|
NoSQL 安全 Java
深入理解 RedisConnectionFactory:Spring Data Redis 的核心组件
在 Spring Data Redis 中,`RedisConnectionFactory` 是核心组件,负责创建和管理与 Redis 的连接。它支持单机、集群及哨兵等多种模式,为上层组件(如 `RedisTemplate`)提供连接抽象。Spring 提供了 Lettuce 和 Jedis 两种主要实现,其中 Lettuce 因其线程安全和高性能特性被广泛推荐。通过手动配置或 Spring Boot 自动化配置,开发者可轻松集成 Redis,提升应用性能与扩展性。本文深入解析其作用、实现方式及常见问题解决方法,助你高效使用 Redis。
1106 4
|
12月前
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
430 0
|
12月前
|
负载均衡 Java Nacos
Spring Cloud五大组件
Spring Cloud五大组件
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
866 3
|
8月前
|
JSON 前端开发 Java
Spring MVC 核心组件与请求处理机制详解
本文解析了 Spring MVC 的核心组件及请求流程,核心组件包括 DispatcherServlet(中央调度)、HandlerMapping(URL 匹配处理器)、HandlerAdapter(执行处理器)、Handler(业务方法)、ViewResolver(视图解析),其中仅 Handler 需开发者实现。 详细描述了请求执行的 7 步流程:请求到达 DispatcherServlet 后,经映射器、适配器找到并执行处理器,再通过视图解析器渲染视图(前后端分离下视图解析可省略)。 介绍了拦截器的使用(实现 HandlerInterceptor 接口 + 配置类)及与过滤器的区别
738 0
|
Java 测试技术 程序员
为什么Spring不推荐@Autowired用于字段注入?
作为Java程序员,Spring框架在日常开发中使用频繁,其依赖注入机制带来了极大的便利。然而,尽管@Autowired注解简化了依赖注入,Spring官方却不推荐在字段上使用它。本文将探讨字段注入的现状及其存在的问题,如难以进行单元测试、违反单一职责原则及易引发NPE等,并介绍为何Spring推荐构造器注入,包括增强代码可读性和维护性、方便单元测试以及避免NPE等问题。通过示例代码展示如何将字段注入重构为构造器注入,提高代码质量。
500 1
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
1258 61
|
Java Spring
一键注入 Spring 成员变量,顺序编程
介绍了一款针对Spring框架开发的插件,旨在解决开发中频繁滚动查找成员变量注入位置的问题。通过一键操作(如Ctrl+1),该插件可自动在类顶部添加`@Autowired`注解及其成员变量声明,同时保持光标位置不变,有效提升开发效率和代码编写流畅度。适用于IntelliJ IDEA 2023及以上版本。
212 2
一键注入 Spring 成员变量,顺序编程
|
缓存 负载均衡 监控
Spring Cloud 五大组件 简介 Eureka、Ribbon、Hystrix、Feign和Zuul
Spring Cloud 五大组件 简介 Eureka、Ribbon、Hystrix、Feign和Zuul
2347 0
|
负载均衡 算法 网络协议
Spring Cloud 五大核心组件解析之Ribbon简介
Spring Cloud 五大核心组件解析之Ribbon简介