SpringBoot 的@Repository 等注解的底层实现原理

1. @Repository注解的类如何存储的

Spring中使用一个IOC容器存储加了 @Component@Repository@Service@Controller 等注解的类,加载IOC容器基本步骤,当 Spring Boot 应用启动时,@SpringBootApplication 中包含的 @ComponentScan 会扫描包及子包下加了这些注解的类。

Spring 会读取每个使用了这些注解类的元数据,创建对应的BeanDefinition并注册到 BeanDefinitionRegistry

2. IOC容器的默认实现

BeanDefinition是一个接口,如果一个类使用派生自@Component的注解,比如@Repository@Service@Controller等,并且通过@ComponentScan注解扫描注册到IOC容器时,默认的接口BeanDefinition实现类是AnnotatedGenericBeanDefinition

BeanDefinitionRegistry也是一个接口,默认的实现是DefaultListableBeanFactory

BeanDefinition中记录的。

3. IOC容器如何管理实例

DefaultListableBeanFactory继承结构图

默认情况下注册到IOC容器中的实例是单例,能保证每次获取到的是同一个实例。

上图是DefaultListableBeanFactory继承结构图,当使用派生自@Component注解一个类时, Spring 内部使用一个三层缓存机制来管理Bean的生命周期,核心是在DefaultSingletonBeanRegistry中维护的。核心源码:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

  /**
   * 一级缓存:存放完全初始化的单例 Bean 实例
   */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

  // 二级缓存、三级缓存用于解决循环依赖,与本文关系不大,省略...
}

4. 从IOC容器中获取实例

IOC容器主要通过getBean()获取托管的Bean实例,该方法由接口BeanFactory声明,由AbstractBeanFactory实现。下面是通过getBean() 方法获取一个 Bean 时的基本执行顺序:

① 是否已经在 singletonObjects 中有现成的 Bean 实例;

② 如果没有并且是懒加载的Bean,就根据对应的 BeanDefinition 实例化一个对象;

③ 实例化之后,放进 singletonObjects 中缓存起来;

④ 之后所有获取请求,都会返回缓存中的同一个对象。

5. IOC容器创建实例时机

**懒加载方式:**上文提到的懒加载时会在getBean时创建实例外的情况,这里不多描述。

**预先实例化单例:**在使用SpringApplication.run()启动SpringBoot应用时,经过多层调用最终会调用SpringApplication.refresh()方法,该方法会根据先前创建的BeanDefinition对象找出scopesingleton且非懒加载的 Bean创建实例对象。

### @Mapper 和 @Repository 注解的区别 #### 来源与用途 - **@Mapper** 是 MyBatis 提供的注解,主要用于标记接口作为 MyBatis 的 Mapper 接口。它允许开发者定义 SQL 查询方法,并将这些方法映射到数据库操作上。通常情况下,每个 Mapper 接口都需要手动加上 `@Mapper` 注解来告诉 MyBatis 这个接口需要被处理为一个 Mapper[^2]。 - **@Repository** 是 Spring 框架提供的注解,用于标识数据访问层(DAO)的 Bean。它的主要目的是让 Spring 容器能够管理这个类的生命周期,并将其注册为一个 Bean,以便在其他组件中通过依赖注入使用。`@Repository` 注解还可以启用持久化异常转换功能,将底层的数据访问异常转换为 Spring 的统一异常体系[^1]。 #### 自动扫描与注册 - 使用 `@Mapper` 时,如果项目中有多个 Mapper 接口,开发者需要为每个接口单独添加 `@Mapper` 注解。为了简化这一过程,Spring Boot 提供了 `@MapperScan` 注解,可以在启动类或配置类中指定要扫描的包路径,自动将该包下的所有 Mapper 接口注册为 Spring Bean。这种方式避免了重复添加 `@Mapper` 注解的繁琐操作[^4]。 - 相比之下,`@Repository` 注解可以直接应用于具体的实现类或接口,只要这些类/接口位于 Spring 配置的扫描路径下,就能被自动检测并注册为 Bean。此外,`@Repository` 可以与其他 Spring 注解(如 `@ComponentScan`)一起工作,进一步简化 Bean 的管理[^3]。 #### 功能特性 - **@Mapper** 主要关注于 MyBatis 的映射逻辑,例如定义 SQL 语句、结果集映射等。它不提供任何 Spring 特有的功能,仅限于 MyBatis 的上下文使用。因此,`@Mapper` 更适合那些直接与数据库交互的接口[^2]。 - **@Repository** 不仅可以声明一个 Bean,还支持 Spring 的事务管理和异常转换。这意味着当数据访问过程中发生异常时,Spring 会自动将底层的异常(如 JDBC 异常)转换为更高层次的、未检查的异常(如 `DataAccessException`),从而使得异常处理更加简单和统一[^1]。 #### 示例代码 以下是一个简单的示例,展示了如何在实际项目中使用这两个注解: ```java // 使用 @Mapper 注解的 MyBatis Mapper 接口 import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface UserMapper { List<User> getAllUsers(); } ``` ```java // 使用 @Repository 注解Spring 数据访问层类 import org.springframework.stereotype.Repository; import java.util.List; @Repository public class UserRepository { private final UserMapper userMapper; public UserRepository(UserMapper userMapper) { this.userMapper = userMapper; } public List<User> findAll() { return userMapper.getAllUsers(); } } ``` 在这个例子中,`UserMapper` 是一个 MyBatis Mapper 接口,使用 `@Mapper` 注解进行标记;而 `UserRepository` 是一个 Spring 数据访问层类,使用 `@Repository` 注解进行标记。通过这种方式,`UserRepository` 可以利用 Spring 的依赖注入机制,轻松地调用 `UserMapper` 中的方法。 #### 启动类配置 为了确保所有的 Mapper 接口都能被正确扫描并注册为 Spring Bean,通常会在启动类中使用 `@MapperScan` 注解: ```java import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.example.demo.mapper") public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 通过 `@MapperScan` 注解Spring Boot 会自动扫描 `com.example.demo.mapper` 包下的所有 Mapper 接口,并将它们注册为 Spring Bean,无需手动添加 `@Mapper` 注解[^3]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值