@Autowired如何知道JPA Repository该怎样实现?

我是一个JAVA初学者
在看到JPA基础的时候,对于继承JpaRepository接口后,直接使用@Autowird即可自动获取相关查询方法感到很神奇,如下:
定义一个repository接口,继承JpaRepository

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

直接可以使用:

@SpringBootTest
@RunWith(SpringRunner.class)
public class UserRepositoryTest {
    @Autowired 
    private UserRepository userRepository;
    private Long id;

    @Before
    public void setUp() {
        assertNotNull(userRepository);
        User user = new User("SnailClimb", 23);
        User savedUser = userRepository.saveAndFlush(user);// 更新 user 对象的姓名
        savedUser.setName("UpdatedName");
        userRepository.save(savedUser);

        id = savedUser.getId();
    }

我并没有给容器中注入相关Bean,@Autowired是如何知道该怎样正确实现这些方法的?


增加问题描述:

感谢大家的回答,但可能我没有很清晰的描述好我的问题:

其实我想知道的是Spring是如何通过 Repository 接口类型(在UserRepository接口类型上注明了@Autowired),来知道如何注入,注入哪一个实现类的。

比如:

按照Spring自己的用法,我在一个类上注明一个@Component,就表明这是个Bean,那么Spring可以很容易的通过反射找到这个类实例化并注册到IoC容器中,然后在使用的地方注入这个对象即可。

但是我在一个接口上注明@Component,系统就不应该知道这个接口的方法如何实现。应该是先绑定一个接口到一个已经实现接口的类(我没有找到这一步,所以不太理解注入机制),然后系统去实例化这个接口实现类。但是我不是很清楚Repository接口是如何绑定到具体实现的。

不知是否表达清楚,大概是这个意思。

阅读 4k
3 个回答

你问的其实是Spring IOC容器的原理

  1. springboot启动的时候会默认扫码启动类当前目录和子目录下,带有@Component注解的类(包括@Controller、@RestController、@Service等等都是)
  2. 把扫描到的组件类实例化以后放入容器中,就是bean
  3. 在依赖某个bean的类实例化时,把带有@Autowired注解的属性、构造方法、setter方法注入bean完成自动装配

另外再说两点

  1. 你那个@Repository注解其实是不需要的,只要继承了JpaRepository都算repository,因为JpaRepository自带了一个组件注解
  2. spring4和5版本推荐构造器注入(并且这个方式可以省略@Autowired注解),最核心的优点就是自行实例化具体的类时,不会因为没有注入bean而报错

有一个对应的repository工厂类,根据你repository接口的定义和传入的实体类,自动代理实现了一个基于模板仓库类中的方法+你自定义方法的类的实例放到容器中

相关的两个类,供参考:
https://docs.spring.io/spring...

https://docs.spring.io/spring...

新手上路,请多包涵

因为@Repository注解里使用了@Component的
类似的还有@Service、@Controller等
image.png

cglib(或者其他工具)运行期根据注解参数等等生成了具体的类
mybatis的mapper接口同理

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题