欢迎光临
我们一直在努力

day6-分层解耦

三层架构

  • Controller(控制层)

    • 角色定位:请求处理的入口
    • 核心职责:接收前端发送的请求,对请求进行处理后响应数据
  • Service(业务逻辑层)

    • 角色定位:业务逻辑的处理中心
    • 核心职责:处理具体的业务逻辑
  • Dao(数据访问层,又称持久层)

    • 角色定位:数据操作的封装层(全称 Data Access Object)
    • 核心职责:负责数据访问操作,包含数据的增加、删除、修改、查询
  • Spring Boot 三种依赖注入方式核心笔记

    核心共性

    三种注入方式均由Spring 容器自动查找对应 Bean完成赋值,无需手动创建依赖对象。

    一、构造器注入(官方推荐)

    核心特性
  • 依赖强制绑定,创建 Bean 时必须传入对应依赖,容器中无匹配 Bean 则项目直接启动失败(错误提前暴露,无线上排查成本);
  • 成员变量可加final修饰,编译期强制赋值,从语法层面杜绝未初始化问题;
  • Spring Boot 2.6+ 单个构造器可省略@Autowired,容器自动识别注入,代码更简洁。
  • 优势
    • 双重非空保障:编译期(final)+ 启动期(容器校验),运行时绝对无空指针;
    • 依赖关系完全显性,看构造方法即可明确类的依赖,代码可读性 / 可维护性高。
    代码示例

    @Service
    public class UserService {
    private final UserDao userDao; // final修饰,编译期强制赋值
    // 无@Autowired,Spring自动注入(2.6+)
    public UserService(UserDao userDao) {
    this.userDao = userDao;
    }
    }

    二、Set 注入

    核心特性
  • 依赖可选绑定,容器通过 set 方法注入,无@Autowired或无匹配 Bean 时,方法不执行,变量默认为 null;
  • 成员变量不可加 final,无语法层面的赋值约束,所有校验仅在运行时生效。
  • 风险

    注入失败无任何启动提示,调用依赖方法时直接触发空指针异常,问题多在运行时暴露。

    代码示例

    @Service
    public class UserService {
    private UserDao userDao; // 不可加final
    // 无@Autowired则不注入,变量为null
    @Autowired
    public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
    }
    }

    三、属性注入

    核心特性
  • 依赖隐性绑定,仅通过成员变量上的@Autowired/@Resource声明,类自身代码无任何依赖体现;
  • 成员变量不可加 final,无初始化约束,注入失败时变量默认为 null,无启动 / 编译提示。
  • 风险

    注入失败诱因最多(忘加注解、无匹配 Bean、注入时机过早),空指针风险极高,是三者中最不推荐的方式。

    代码示例

    @Service
    public class UserService {
    // 忘加@Autowired则不注入,变量为null
    @Autowired
    private UserDao userDao; // 不可加final
    }

    四、核心差异对比(核心考点 / 开发重点)

    注入方式能否加 final注入失败表现空指针风险依赖显性化官方态度
    构造器注入 ✅ 推荐 项目直接启动失败 完全显性 推荐
    Set 注入 ❌ 不能 变量为 null,运行时报错 部分显性 不推荐
    属性注入 ❌ 不能 变量为 null,运行时报错 极高 完全隐性 不推荐

    五、核心结论

  • 三者均由 Spring 自动查找 Bean 注入,差异核心在注入失败的处理时机和非空保障机制;
  • 构造器注入是把问题提前到编译 / 启动期,Set / 属性注入是把问题留在运行期;
  • 企业开发中,核心业务 Bean 必须使用构造器 + final注入,从根源规避空指针和依赖隐藏问题。
  • Spring @Autowired 多实现类注入(兜底匹配)

    一、核心场景

    当一个接口(如UserService)有多个实现类(如UserServiceImpl、UserServiceImpl2),用@Autowired注入时,未报错的核心是触发了 Spring 的「名称兜底匹配机制」。

    二、关键前提规则

    1. 实现类的默认 Bean 名规则

    被@Service(无自定义名称)标注的实现类,Spring 自动生成 Bean 名:类名首字母小写(例:UserServiceImpl→userServiceImpl、UserServiceImpl2→userServiceImpl2)。

    2. @Autowired 注入优先级(核心)

  • 先按「类型(byType)」匹配:查找容器中所有该接口 / 类的 Bean;
  • 若类型匹配多个 Bean(如多个UserService实现类),触发「兜底机制」—— 按「名称(byName)」匹配;
  • 名称匹配成功(变量名 = Bean 名)则唯一注入,匹配失败则抛出NoUniqueBeanDefinitionException。
  • 三、场景不报错 / 报错的直接原因

    1. 不报错(变量名 = Bean 名)

    Controller 中注入变量名userServiceImpl,与UserServiceImpl的默认 Bean 名完全匹配,Spring 精准注入,无冲突。

    2. 报错(变量名≠任何 Bean 名)

    变量名改为u后,无法通过名称匹配任何实现类的 Bean,Spring 无法确定注入哪个,直接抛出异常。

    四、解决 “变量名任意取仍不报错” 的方法

    若想变量名自定义(如u),用@Qualifier明确指定 Bean 名即可,示例:

    @Autowired
    @Qualifier("userServiceImpl") // 指定要注入的Bean名
    private UserService u; // 变量名可任意,不影响注入

    五、核心结论

  • @Autowired 的「兜底机制」:类型匹配多个时,以「变量名匹配 Bean 名」为最终依据,唯一匹配则注入,否则报错;
  • 该机制是 Spring 框架特性,与 JDK 版本无关,对属性注入、Set 注入均生效;
  • 多实现类注入时,要么让变量名匹配 Bean 名,要么用@Qualifier指定 Bean 名,避免报错。
  • Spring DI(依赖注入)多 Bean 冲突解决方案核心笔记

    一、核心问题背景

    @Autowired默认按类型(byType) 注入,当接口存在多个实现类(如UserServiceImpl、UserServiceImpl2)时,Spring 容器中会有多个同类型 Bean,直接注入会抛出NoUniqueBeanDefinitionException异常,提示 “需要单个 Bean 但找到多个”。

    二、三种核心解决方案

    方案 1:@Primary(指定默认首选 Bean)

    核心逻辑

    在多个同类型 Bean 中,给优先级最高的实现类标注@Primary,Spring 会优先注入该 Bean,无需修改注入端代码。

    代码示例

    // 实现类端:标注@Primary,设为默认首选
    @Service
    @Primary
    public class UserServiceImpl implements UserService {
    // 业务方法
    @Override
    public List<User> list() {
    // 逻辑实现
    }
    }

    // Controller端:直接注入,Spring自动选@Primary的Bean
    @RestController
    public class UserController {
    @Autowired
    private UserService userService; // 注入UserServiceImpl
    }

    适用场景

    有明确 “主实现类”,其他实现类为备用的场景(如默认用 MySQL 实现,Redis 实现为兜底)。

    方案 2:@Qualifier(精准指定 Bean 名)

    核心逻辑

    配合@Autowired使用,通过@Qualifier("Bean名")明确指定要注入的 Bean 名称(Bean 名默认是实现类首字母小写),精准匹配。

    代码示例

    // 实现类端:无需额外标注,用默认Bean名
    @Service // Bean名:userServiceImpl
    public class UserServiceImpl implements UserService {}

    @Service // Bean名:userServiceImpl2
    public class UserServiceImpl2 implements UserService {}

    // Controller端:用@Qualifier指定Bean名
    @RestController
    public class UserController {
    @Autowired
    @Qualifier("userServiceImpl") // 明确指定注入该Bean
    private UserService userService; // 变量名可任意,不影响匹配
    }

    适用场景

    需要灵活切换不同实现类的场景(如按需注入 MySQL/Redis 实现),是最常用的方案。

    方案 3:@Resource(按名称注入,JDK 原生)

    核心逻辑

    @Resource是 JDK 原生注解,默认按名称(byName) 注入,通过name属性指定 Bean 名,无需搭配@Autowired。

    代码示例

    // 实现类端:默认Bean名
    @Service // Bean名:userServiceImpl
    public class UserServiceImpl implements UserService {}

    // Controller端:用@Resource指定Bean名
    @RestController
    public class UserController {
    @Resource(name = "userServiceImpl") // 直接指定Bean名
    private UserService userService; // 注入UserServiceImpl
    }

    关键区别

    与@Autowired+@Qualifier相比:

    • @Resource是 JDK 注解,@Autowired是 Spring 注解;
    • @Resource默认 byName,@Autowired默认 byType(需 @Qualifier 兜底 byName)。

    @Resource 与 @Autowired+@Qualifier 核心执行逻辑总结

    一、核心共性

    两者均用于解决多 Bean 注入冲突,最终都要求「Bean 名匹配 + 类型兼容」才能成功注入,不存在 “不校验类型” 的情况。

    二、核心差异(匹配顺序是关键)
    1. @Resource 执行逻辑(先名后型,名为主、型为兜底)
  • 优先按指定name找 Bean → 找到则校验类型是否兼容,兼容则注入,不兼容报错;
  • 名称匹配失败 → 兜底按类型(ByType)找 Bean;
  • 类型匹配到 1 个则注入,匹配多个 / 0 个均报错(不会默认选第一个)。
  • 2. @Autowired+@Qualifier 执行逻辑(先型后名,型为基础、名为筛选)
  • 先按变量类型(ByType)找所有兼容 Bean → 找不到直接报错;
  • 类型匹配多个 Bean → 再按@Qualifier指定的名称在该范围内筛选;
  • 名称筛选出唯一 Bean 则注入,筛选失败(无 / 多匹配)则报错。
  • 三、一句话核心区分
    • @Resource:先锁定 Bean 名称,再验证类型;名称找不到才按类型找;
    • @Autowired+@Qualifier:先锁定类型范围,再在范围内找指定名称的 Bean。

    三、核心对比与选型建议

    方案注解归属匹配规则代码修改位置灵活性推荐度
    @Primary Spring 类型匹配 + 默认首选 实现类端 ⭐⭐⭐
    @Qualifier Spring 类型 + 名称精准匹配 注入端 ⭐⭐⭐⭐⭐
    @Resource JDK 原生 直接按名称匹配 注入端 ⭐⭐⭐⭐

    四、核心结论

  • @Autowired默认 byType,多同类型 Bean 必报错,需用三种方案解决;
  • 日常开发优先用@Qualifier(灵活),有主实现类时用@Primary,想脱离 Spring 依赖时用@Resource;
  • 本质都是通过 “指定优先级 / 明确名称” 让 Spring 找到唯一匹配的 Bean,解决多 Bean 冲突。
  • 赞(0)
    未经允许不得转载:171主机测评 » day6-分层解耦
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址