简体   繁体   中英

Spring - How to use @Autowired correctly?

I found a strange behaviour in my Spring App.

The @autowired of an Entity is not working all the time.

I use the Elide project to build an JSONAPI and some custom controllers.

In one controller, one @Autowrited of an entity stays null however it use correctly working when called from 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 .

This is not a way how you should do that. Don't use @Autowired in your entities. This annotation is managed by Spring, but your entities are managed and created by Hibernate and it doesn't care about Spring annotations. 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. You have to add the @Configurable annotation to your class. Then your Autowired annotation will work.

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

so autowire ItemRepository a level up, at UploadController itself.

@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.
  2. you can make them final (which is not possible with @Autowire on variable directly)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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