为啥这个 Spring Boot Web 应用不需要 @Repository?

Posted

技术标签:

【中文标题】为啥这个 Spring Boot Web 应用不需要 @Repository?【英文标题】:Why isn't necessary @Repository for this Spring Boot web app?为什么这个 Spring Boot Web 应用不需要 @Repository? 【发布时间】:2019-01-25 20:12:11 【问题描述】:

我正在学习 Spring Boot 和 JPA、Spring Data Rest、H2 数据库,并且我找到了一个教程。我试图理解它,这是一个简单的例子,但我不明白。为什么不需要将@Repository@Component 放在 AlienRepo 类中?

repo 对象被注入到 AlienController 类中,我从之前的教程中知道你需要使用@Component@Repository。我认为必须使用此注释。

控制器:

package com.dgs.springbootjpa.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.dgs.springbootjpa.dao.AlienRepo;
import com.dgs.springbootjpa.model.Alien;

@Controller
public class AlienController 

    @Autowired
    AlienRepo repo;

    @RequestMapping("/")
    public String home() 

        return "home.jsp";
    

    @RequestMapping("/addAlien")
    public String addAlien(Alien alien) 

        repo.save(alien);
        return "home.jsp";
    


POJO:

package com.dgs.springbootjpa.model;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Alien 

    @Id
    private int aid;

    private String aname;

    public int getAid() 
        return aid;
    
    public void setAid(int aid) 
        this.aid = aid;
    
    public String getAname() 
        return aname;
    
    public void setAname(String aname) 
        this.aname = aname;
    

    @Override
    public String toString() 

        return "Alien [aid=" + aid + ", aname=" + aname + "]";
    

dao接口:

package com.dgs.springbootjpa.dao;

import org.springframework.data.repository.CrudRepository;

import com.dgs.springbootjpa.model.Alien;

public interface AlienRepo extends CrudRepository<Alien, Integer> 


可以看到AlienRepo界面中没有@Repository@Component,代码运行成功。

谢谢!

更新---------------------------------

我想从数据库中获取数据并添加以下代码。我想问你为什么@RequestParam 不是强制性的?如果我删除了@RequestParam,应用程序就会成功运行。

@RequestMapping("/getAlien")
public ModelAndView addAlien(@RequestParam int aid) 

    ModelAndView mv = new ModelAndView("showAlien");
    Alien alien = repo.findById(aid).orElse(new Alien()); 
    mv.addObject(alien); 
    return mv;

【问题讨论】:

【参考方案1】:

你注意到了吗,CrudRepository 有@NoRepositoryBean 注解,这个注解使CrudRepository 成为一个中间接口。一个中间接口基本上是添加 派生存储库的一般功能。

如果任何使用@NoRepositoryBean注解的类,Spring Data 不会在运行时创建实例。因为它是中间类,它是为派生类添加功能而创建的。

如果您扩展一个具有@NoRepositoryBean 的接口,而您的派生接口没有@NoRepositoryBean,Spring 知道您正在尝试在您的真实存储库接口中使用该功能,因此添加@Repository 注释是冗长的。


编辑:为什么@RequestParam 不是强制性的?

从the official documentation可以看到“控制器方法参数”表,表的最后一行写着:

任何其他论点:

如果方法参数与上述任何一个都不匹配,默认情况下它 如果是简单类型,则解析为@RequestParam,如 由BeanUtils#isSimpleProperty 确定,或作为 @ModelAttribute 否则。

因此,如果您省略了“控制器方法参数”的注释,并且您没有编写 @MatrixVariable、@PathVariable 或 @RequestParam 之类的内容。 默认是@RequestParam

【讨论】:

非常感谢您的帮助!你能帮我更新一下吗?为什么@RequestParam 不是强制性的? 很高兴为您提供帮助,猫王!我已经更新了我的答案,希望能再次提供帮助。【参考方案2】:

@Component@Repository 可以在类上使用,以将它们用作 Spring Bean。但是,AlienRepo 不是一个类,它是一个扩展 Spring Data 接口的接口。 Spring Data 不使用注释,它通过扫描类路径并查看接口层次结构来检测接口,以查看 Spring Data 接口是否被扩展。如果是这种情况,它会在运行时为每个接口创建一个实现,然后将其作为 Spring Bean 添加到应用程序上下文中。这就是为什么您不需要在 Spring Data 接口上进行任何注释。

【讨论】:

【参考方案3】:

你的@SpringBootApplication 引入了@EnableAutoConfiguration 注解的效果:

@EnableAutoConfiguration
public @interface SpringBootApplication

此注解将猜测并自动配置 bean。

Spring Data 的 JPA 存储库的自动配置。 当上下文中配置了一个 DataSource 类型的 bean,Spring Data JPA JpaRepository 类型在类路径上,并且没有配置其他现有的 JpaRepository 时激活。

一旦生效,自动配置就相当于使用 EnableJpaRepositories 注解启用 JPA 存储库。

这个配置类会在 Hibernate 自动配置之后激活。

public class JpaRepositoriesAutoConfiguration 


当你添加 data-jpa 依赖时,JpaRepositoriesAutoConfiguration 被触发并为你的应用带来@EnableJpaRepositories 注解的效果

Your repository then auto-configured:

Spring Data 存储库通常从 Repository 或 CrudRepository 接口扩展而来。如果您使用自动配置,则从包含您的主配置类(使用 @EnableAutoConfiguration 或 @SpringBootApplication 注释的那个)的包中向下搜索存储库。

【讨论】:

问题是关于@org.springframework.stereotype.Repository annotation,而不是org.springframework.data.repository.Repository interface @Lu55 OP 问题是“为什么不需要将@Repository 或@Component 放在AlienRepo 类中”,我解释了为什么Spring 可以自动完成(自动注册Repository/CrudRepository 子接口通过@EnableJpaRepositories)。老实说,我什至不知道为什么上面的答案被接受了大声笑【参考方案4】:

您的 AlienRepo 类扩展了 CrudRepository,因此 Spring 将能够浏览配置中指定的包并找到存储库。

附带说明,如果只有一个构造函数AlienController(AlienRepo),您可以删除@Autowired,Spring 也可以解决这个问题。

【讨论】:

以上是关于为啥这个 Spring Boot Web 应用不需要 @Repository?的主要内容,如果未能解决你的问题,请参考以下文章

spring boot web应用为啥刷新页面没用

为啥必须在 spring-boot 中为 web 应用程序提供单独的 @Controller 类文件?

为啥我的 Spring Boot Web 应用程序无法在 Gradle 中完全运行?

为啥我的控制器中的根路径映射到 Spring Boot Web 应用程序中的 index.html?

为啥这个 Spring Boot 应用程序找不到主页?

为啥我的 Spring Boot 应用程序会自行关闭