两个原因导致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() {
  }
}

------------恢复内容结束------------

posted @ 2020-04-14 22:27  三分恶  阅读(2245)  评论(0编辑  收藏  举报