常用的注入方式主要有三种:构造方法注入,setter注入,基于注解的注入。

构造方法注入

先简单了解一下测试项目的结构,用maven构建的,四个包:

entity:存储实体,里面只有一个User类
    dao:数据访问,一个接口,两个实现类
    service:服务层,一个接口,一个实现类,实现类依赖于IUserDao
    test:测试包

在spring的配置文件中注册UserService,将UserDaoJdbc通过constructor-arg标签注入到UserService的某个有参数的构造方法

<!-- 注册userService --> <bean id="userService" class="com.lyu.spring.service.impl.UserService">   <constructor-arg ref="userDaoJdbc"></constructor-arg> </bean> <!-- 注册jdbc实现的dao --> <bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>

如 果只有一个有参数的构造方法并且参数类型与注入的bean的类型匹配,那就会注入到该构造方法中。

public class UserService implements IUserService {private IUserDao userDao; public UserService(IUserDao userDao) { this.userDao = userDao;} public void loginUser() {userDao.loginUser();}}

@Test
public void testDI() { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");// 获取bean对象UserService userService = ac.getBean(UserService.class, "userService"); // 模拟用户登录userService.loginUser();
}

测试打印结果:jdbc-登录成功

注:模拟用户登录的loginUser方法其实只是打印了一条输出语句,jdbc实现的类输出的是:jdbc-登录成功,mybatis实现的类输出的是:mybatis-登录成功。

问题一:如果有多个有参数的构造方法并且每个构造方法的参数列表里面都有要注入的属性,那userDaoJdbc会注入到哪里呢?

public class UserService implements IUserService {private IUserDao userDao; private User user; public UserService(IUserDao userDao) { System.out.println("这是有一个参数的构造方法"); this.userDao = userDao;}public UserService(IUserDao userDao, User user) { System.out.println("这是有两个参数的构造方法"); this.userDao = userDao; this.user = user; } public void loginUser() {userDao.loginUser(); }
}

结果:会注入到只有一个参数的构造方法中,并且经过测试注入哪一个构造方法与构造方法的顺序无关

接来来几个问题详情见:https://blog.csdn.net/a909301740/article/details/78379720

setter注入

配置文件如下:

<!-- 注册userService --><bean id="userService" class="com.lyu.spring.service.impl.UserService"> <!-- 写法一 --> <!-- <property name="UserDao" ref="userDaoMyBatis"></property> --><!-- 写法二 --> <property name="userDao" ref="userDaoMyBatis"></property> </bean><!-- 注册mybatis实现的dao -->
<bean id="userDaoMyBatis" class="com.lyu.spring.dao.impl.UserDaoMyBatis"></bean>

注:上面这两种写法都可以,spring会将name值的每个单词首字母转换成大写,然后再在前面拼接上"set"构成一个方法名,然后去对应的类中查找该方法,通过反射调用,实现注入。

切记:name属性值与类中的成员变量名以及set方法的参数名都无关,只与对应的set方法名有关,下面的这种写法是可以运行成功的

public class UserService implements IUserService { private IUserDao userDao1;public void setUserDao(IUserDao userDao1) { this.userDao1 = userDao1; }public void loginUser() {userDao1.loginUser();}
}

还有一点需要注意:如果通过set方法注入属性,那么spring会通过默认的空参构造方法来实例化对象,所以如果在类中写了一个带有参数的构造方法,一定要把空参数的构造方法写上,否则spring没有办法实例化对象,导致报错。

基于注解的注入
在介绍注解注入的方式前,先简单了解bean的一个属性autowire,autowire主要有三个属性值:constructor,byName,byType。

constructor:通过构造方法进行自动注入,spring会匹配与构造方法参数类型一致的bean进行注入,如果有一个多参数的构造方法,一个只有一个参数的构造方法,在容器中查找到多个匹配多参数构造方法的bean,那么spring会优先将bean注入到多参数的构造方法中。

byName:被注入bean的id名必须与set方法后半截匹配,并且id名称的第一个单词首字母必须小写,这一点与手动set注入有点不同。

byType:查找所有的set方法,将符合符合参数类型的bean注入。

下面进入正题:注解方式注册bean,注入依赖

主要有四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异:

@Component:可以用于注册所有bean
    @Repository:主要用于注册dao层的bean
    @Controller:主要用于注册控制层的bean
    @Service:主要用于注册服务层的bean

描述依赖关系主要有两种:

@Resource:java的注解,默认以byName的方式去匹配与属性名相同的bean的id,如果没有找到就会以byType的方式查找,如果byType查找到多个的话,使用@Qualifier注解(spring注解)指定某个具体名称的bean。

@Resource
@Qualifier("userDaoMyBatis")
private IUserDao userDao;public UserService(){}

  • @Autowired:spring注解,默认是以byType的方式去匹配类型相同的bean,如果只匹配到一个,那么就直接注入该bean,无论要注入的 bean 的 name 是什么;如果匹配到多个,就会调用 DefaultListableBeanFactory 的 determineAutowireCandidate 方法来决定具体注入哪个bean。determineAutowireCandidate 方法的内容如下:
// candidateBeans 为上一步通过类型匹配到的多个bean,该 Map 中至少有两个元素。 protected String determineAutowireCandidate(Map<String, Object> candidateBeans, DependencyDescriptor descriptor) {//  requiredType 为匹配到的接口的类型
Class<?> requiredType = descriptor.getDependencyType();// 1. 先找 Bean 上有@Primary 注解的,有则直接返回 String primaryCandidate = this.determinePrimaryCandidate(candidateBeans, requiredType);if (primaryCandidate != null) { return primaryCandidate; } else { // 2.再找 Bean 上有 @Order,@PriorityOrder 注解的,有则返回 String               priorityCandidate = this.determineHighestPriorityCandidate(candidateBeans, requiredType); if (priorityCandidate != null) { return priorityCandidate; } else {Iterator var6 = candidateBeans.entrySet().iterator(); String candidateBeanName; Object beanInstance; do {if (!var6.hasNext()) { return null; } // 3. 再找 bean 的名称匹配的 Entry<String, Object> entry = (Entry)var6.next(); candidateBeanName = (String)entry.getKey(); beanInstance = entry.getValue();}          while(!this.resolvableDependencies.values().contains(beanInstance) && !this.matchesBeanName(candidateBeanName,         descriptor.getDependencyName()));return candidateBeanName; }}}

determineAutowireCandidate 方法的逻辑是:

先找 Bean 上有@Primary 注解的,有则直接返回 bean 的 name。
    再找 Bean 上有 @Order,@PriorityOrder 注解的,有则返回 bean 的 name。
    最后再以名称匹配(ByName)的方式去查找相匹配的 bean。

可以简单的理解为先以 ByType 的方式去匹配,如果匹配到了多个再以 ByName 的方式去匹配,找到了对应的 bean 就去注入,没找到就抛出异常。

还有一点要注意:如果使用了 @Qualifier 注解,那么当自动装配匹配到多个 bean 的时候就不会进入 determineAutowireCandidate 方法(亲测),而是直接查找与 @Qualifer 指定的 bean name 相同的 bean 去注入,找到了就直接注入,没有找到则抛出异常。
ByName 的方式需要遍历,@Qualifier 直接一次定位。在匹配到多个 bean 的情况下,使用 @Qualifier 来指明具体装配的 bean 效率会更高一下。

博主个人觉得:@Qualifer 注解出现的意义或许就是 Spring 为了解决 JDK 自带的 ByName 遍历匹配效率低下的问题。要不然也不会出现两个容易混淆的匹配方式。
写在最后:虽然有这么多的注入方式,但是实际上开发的时候自己编写的类一般用注解的方式注册类,用@Autowired描述依赖进行注入,一般实现类也只有一种(jdbc or hibernate or mybatis),除非项目有大的变动,所以@Qualifier标签用的也较少;但是在使用其他组件的API的时候用的是通过xml配置文件来注册类,描述依赖,因为你不能去改人家源码嘛。
---------------------
作者:曲健磊
来源:CSDN
原文:https://blog.csdn.net/a909301740/article/details/78379720

转载于:https://www.cnblogs.com/cslgzl/p/10533276.html

Spring IOC的三种主要注入方式?相关推荐

  1. spring常用的三种依赖注入方式

    平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程 ...

  2. 【闲谈】论Spring的三种依赖注入方式

    知识点科普: IOC和DI:IOC是控制反转,DI是依赖注入.DI是行为,而IOC是实现这一行为的容器. 循环依赖:指类与类之间互相依赖的情况,比如有类A和类B,类A中依赖类B,类B中依赖类A,由此导 ...

  3. DI的三种依赖注入方式和底层实现

    bean 标签来表示一个对象:id 是一个对象的唯一标识:class 是类的全路径: 为对象的属性赋值 1. 设值注入 底层实现set方法赋值 ref 引用其它对象,对象的嵌套 2. 构造注入 底层实 ...

  4. IoC、Spring 环境搭建、Spring 创建对象的三种方式、DI

    二.IoC 中文名称:控制反转 英文名称:(Inversion of Control) 3.I oC 是什么? 3.1 IoC 完成的事情原先由程序员主动通过 new 实例化对象事情,转交给 Spri ...

  5. spring入门之Spring 常用的三种注入方式

    Spring 常用的三种注入方式 Spring 通过 DI(依赖注入)实现 IOC(控制反转),常用的注入方式主要有三种:构造方法注入,set 方法注入,基于注解的注入. 一.通过构造方法注入 先简单 ...

  6. Spring中IoC两种接口和两种依赖注入方式的比较

    spring是一个开源框架,是为了解决企业应用程序开发的复杂性而创建的,为J2EE应用程序开发提供集成的框架.简单来说,spring是一个轻量级的控制反转IOC和面向切面AOP的容器框架.spring ...

  7. Spring 学习之 二----Spring创建对象的三种方式

    最近在系统的学习Spring,现在就Spring的一些知识进行总结. 我们知道Spring是一个开放源代码的设计层面的框架,他主要解决的是业务逻辑层与其他各层之间松耦合的问题. Spring 有三个核 ...

  8. spring四种依赖注入方式

    平常的java开发中,程序员在某个类中需要依赖其它类的方法,通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理. spring提出了依赖注入的思想,即依赖不由程序 ...

  9. Spring集成Memcached三种方式(一)

    Spring集成Memcached三种方式(一) 转载:http://blog.csdn.net/u013725455/article/details/52102170 Memcached Clien ...

  10. 框架源码系列九:依赖注入DI、三种Bean配置方式的注册和实例化过程

    一.依赖注入DI 学习目标 1)搞清楚构造参数依赖注入的过程及类 2)搞清楚注解方式的属性依赖注入在哪里完成的. 学习思路 1)思考我们手写时是如何做的 2)读 spring 源码对比看它的实现 3) ...

最新文章

  1. java安装_Java开发中更多常见的危险信号
  2. UA STAT675 统计计算I 随机数生成8 Adaptive Rejection Sampling
  3. 32.3. redis-cli - Command-line client to redis-server
  4. LeetCode19删除链表的倒数第N个节点20有效的括号
  5. 配置Hyper-V Server 资源计量
  6. android 系统 ---(1) 框架的代码组织介绍
  7. [转载] URL短网址生成算法原理
  8. linux安装python3和pip3
  9. java怎么与数据库连接?
  10. 从零开始学android
  11. 你对软件测试了解多少?这篇文章会给你不一样的启示!
  12. IuCS IuPS IuR IuB Uu接口示意图
  13. 最简单的免费安卓手机投屏电脑游戏直播工具推荐:电脑控制手机玩游戏了解一下
  14. JavaScript生成图形验证码
  15. 2023年全国最新二级建造师精选真题及答案13
  16. 入坑rockchip 基础信息资料
  17. typedef和typename的区别
  18. 数据库trunc的用法
  19. Fedora 14 root权限登录
  20. 计算机无线传输的标准,2015计算机三级网络技术考试重点:无线网络

热门文章

  1. 程序员失业一月转行去送外卖,晒出当天收入,还以为看错了
  2. 震惊!Spring Boot 内存又泄露,排查太难了!
  3. 你见过世界顶级公司的最垃圾的代码是什么?
  4. MyBatis的9种设计模式,我猜你不知道
  5. 架构案例丨微信Android客户端架构演进之路
  6. 《Linux就该这么学》修正已知全部勘误,免费下载啦!
  7. Android设计模式之单例模式
  8. mysql基础之mariadb概念
  9. 《信息安全系统设计基础》第三周学习总结
  10. 了解typename的双重意义