ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring DI 三种注入方式和同类型多个 Bean 冲突解决方案

Spring DI 三种注入方式和同类型多个 Bean 冲突解决方案 Spring DI 三种注入方式Spring DI 一共有三种注入方式分别是构造器注入、setter 注入、字段注入。准备注入的Bean类importorg.springframework.stereotype.Component;ComponentpublicclassUserDao{publicvoidsave(){System.out.println(保存数据);}}构造器注入就是通过类的构造方法来完成依赖注入也是 Spring 官方推荐的注入方式。它的优点是依赖必须在对象创建的时候就注入可以把成员变量定义为 final保证依赖不可变方便单元测试。缺点是如果一个类依赖非常多构造方法会写得很长。importorg.springframework.stereotype.Service;ServicepublicclassUserService{privatefinalUserDaouserDao;// 只有一个构造方法时Autowired可以省略publicUserService(UserDaouserDao){this.userDaouserDao;}publicvoidtest(){userDao.save();}}Setter 注入是把 Autowired 注解写在 set 方法上Spring 会在对象实例创建完成之后调用 set 方法给成员变量赋值。适合可选依赖支持运行时动态修改依赖缺点是对象创建完才注入有可能会出现空指针问题。importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;ServicepublicclassUserService{privateUserDaouserDao;AutowiredpublicvoidsetUserDao(UserDaouserDao){this.userDaouserDao;}publicvoidtest(){userDao.save();}}字段注入直接把 Autowired 写在成员变量上面写法最简单。但是不推荐使用它不能给变量加 final 修饰依赖信息隐藏在代码内部外部无法直观看到这个类需要哪些依赖做单元测试的时候比较麻烦。importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;ServicepublicclassUserService{AutowiredprivateUserDaouserDao;publicvoidtest(){userDao.save();}}同类型多个 Bean 冲突解决方案当同一个接口或者类在 Spring 容器里面存在多个 Bean 的时候直接使用 Autowired 注入会抛出 NoUniqueBeanDefinitionException 异常下面有三种解决方式。先定义接口两个实现类产生多个同类型 BeanpublicinterfaceUserDao{voidsave();}importorg.springframework.stereotype.Component;// bean名称mysqlUserDaoComponent(mysqlUserDao)publicclassMysqlUserDaoimplementsUserDao{Overridepublicvoidsave(){System.out.println(mysql保存);}}importorg.springframework.stereotype.Component;// bean名称oracleUserDaoComponent(oracleUserDao)publicclassOracleUserDaoimplementsUserDao{Overridepublicvoidsave(){System.out.println(oracle保存);}}第一种是 Primary。Primary 是 Spring 提供的注解用来标记首选 Bean。当容器里面多个同类型 Bean没有额外指定的情况下Spring 会优先选择带有 Primary 注解的 Bean。适合大部分场景都使用这个 Bean 的情况但是一个类型只能设置一个首选 Bean如果需要随时切换不同 Bean这种方式就不适用。importorg.springframework.context.annotation.Primary;importorg.springframework.stereotype.Component;Component(mysqlUserDao)PrimarypublicclassMysqlUserDaoimplementsUserDao{Overridepublicvoidsave(){System.out.println(mysql保存);}}使用直接 Autowired自动选加了 Primary 的 MysqlUserDaoimportorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;ServicepublicclassUserService{AutowiredprivateUserDaouserDao;publicvoidtest(){userDao.save();}}第二种是 Qualifier。这个注解必须搭配 Autowired 一起使用可以明确指定要注入的 Bean 名称。Qualifier 里面填写的字符串就是 Component 注解定义的 bean 名字。只要写了 Qualifier就会按照指定名称精确匹配 Bean优先级高于 Primary就算别的 Bean 加了 Primary也会忽略掉。构造器注入、setter 注入、字段注入都可以使用 Qualifier。importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.stereotype.Service;ServicepublicclassUserService{AutowiredQualifier(oracleUserDao)privateUserDaouserDao;publicvoidtest(){userDao.save();}}构造器注入使用 Qualifier 版本importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.stereotype.Service;ServicepublicclassUserService{privatefinalUserDaouserDao;publicUserService(Qualifier(oracleUserDao)UserDaouserDao){this.userDaouserDao;}publicvoidtest(){userDao.save();}}第三种是 Resource。它不属于 Spring 注解是 Java 的 JSR250 规范注解。Resource 默认优先按照 bean 名称 byName 去查找找不到对应名字的 bean才会退化成按类型 byType 查找。可以通过 name 属性直接指定 bean 名称。它不支持配合 Primary 使用并且只能标注在成员变量或者 set 方法上不能用于构造器注入。importjakarta.annotation.Resource;importorg.springframework.stereotype.Service;ServicepublicclassUserService{Resource(nameoracleUserDao)privateUserDaouserDao;publicvoidtest(){userDao.save();}}优先级Qualifier 的优先级高于 Primary。只要写了 Qualifier就以 Qualifier 指定的 bean 为准Primary 失效。补充Resource 是 java 规范注解导入包是jakarta.annotation.Resourcespringboot3旧版本是javax.annotation.ResourceResource 不能写在构造方法上只能字段或者 setter。
返回列表