简体   繁体   English

Spring-如何正确使用@Autowired?

[英]Spring - How to use @Autowired correctly?

I found a strange behaviour in my Spring App. 我在Spring应用程序中发现了一个奇怪的行为。

The @autowired of an Entity is not working all the time. 实体的@autowired并非一直都在工作。

I use the Elide project to build an JSONAPI and some custom controllers. 我使用的Elid项目,以建立一个JSONAPI和一些定制的控制器。

In one controller, one @Autowrited of an entity stays null however it use correctly working when called from Elide. 在一个控制器中,一个@Autowrited实体保持为空,但是当从Elide调用时它使用正确。

Controller: 控制器:

@RestController
public class UploadController {
    @Autowired
    private ProjectRepository projectRepository;

    @PostMapping(value = "/api/projects/{projectId}/upload")
    public String uploadItem(@PathVariable long projectId, @RequestParam("file") MultipartFile file,
                              @RequestParam("projectName") String projectName,
                              RedirectAttributes redirectAttributes) throws IOException {
        Project project = projectRepository.findOneByProjectIdAndName(projectId, projectName);
        Integer result = project.getNumberOfItems();

        return "";
    }
}

Entity 实体

@Setter
@NoArgsConstructor
@Table(name = "projects")
@Entity
@Include(rootLevel = true, type = "projects")
public class Project extends DiffShelfBase {

    @Autowired
    @Transient
    private ItemRepository itemRepository;

    @Transient
    @ComputedAttribute
    public Integer getNumberOfItems() {
        return itemRepository.countByProjectId(this.getId());
    }
}

Repository 知识库

@Repository
@Transactional
public interface ItemRepository extends JpaRepository<Item, Long> {
    Integer countByProjectId(long projectId);
}

Configuration 组态

@Configuration
@EnableSpringConfigured
public class MyConfiguration {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedMethods("*")
                        .allowedOrigins("http://localhost:4200");
            }
        };
    }
}

I don't understand why but the itemRepository in null in Project.getNumberOfItems . 我不明白为什么,但是Project.getNumberOfItemsitemRepository为null。

This is not a way how you should do that. 这不是您应该如何做的方法。 Don't use @Autowired in your entities. 不要在您的实体中使用@Autowired This annotation is managed by Spring, but your entities are managed and created by Hibernate and it doesn't care about Spring annotations. 这个注释是由Spring管理的,但是您的实体是由Hibernate管理和创建的,它并不关心Spring注释。 You could find another way to add this property to your entity(let it be field in a database for example). 您可以找到另一种方法将此属性添加到您的实体(例如,使其成为数据库中的字段)。

The problem you have is, that your Project is no managed by spring. 您遇到的问题是,您的Project没有在春季之前进行管理。 You have to add the @Configurable annotation to your class. 您必须在类中添加@Configurable批注。 Then your Autowired annotation will work. 然后,您的自动Autowired注释将起作用。

But I would really refactor your code. 但是我真的会重构您的代码。 You should not have spring-objects in your Entities. 您的实体中不应包含弹簧对象。

An Entity should be a glorified POJO , never complicate it embedding repos inside 一个Entity应该是一个美化的POJO ,永远不要使它复杂地嵌入repos里面。

so autowire ItemRepository a level up, at UploadController itself. 因此,可以自动上ItemRepositoryUploadControllerUploadController本身。

@RestController
public class UploadController {

    @Autowired
    private ProjectRepository projectRepo;

    @Autowired
    private ItemRepository itemRepo;

    @PostMapping(value = "/api/projects/{projectId}/upload")
    public String uploadItem(@PathVariable long projectId, @RequestParam("file") MultipartFile file,
                              @RequestParam("projectName") String projectName,
                              RedirectAttributes redirectAttributes) throws IOException {

        Project project = projectRepo.findOneByProjectIdAndName(projectId, projectName);
        Integer result = itemRepo.countByProjectId(project.getId());

        return "";
    }
}

and as a good practice, you can always do a constructor injection making it easy to test 作为一种好习惯,您总是可以进行构造函数注入,从而易于测试

eg instead of 例如代替

@Autowired
private ProjectRepository projectRepo;

@Autowired
private ItemRepository itemRepo;

do a constructor injection 做一个构造函数注入

private final ProjectRepository projectRepo;
private final ItemRepository itemRepo;

@Autowired
public UploadController(final ProjectRepository projectRepo, final ItemRepository itemRepo) {
    this.projectRepo = projectRepo;
    this.itemRepo = itemRepo;
}

this way, 这条路,

  1. it is easy to test by passing mockito instances. 通过传递Mockito实例很容易进行测试。
  2. you can make them final (which is not possible with @Autowire on variable directly) 您可以将它们@Autowire (直接使用@Autowire对变量进行@Autowire是不可能的)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM