Spring通过DI(依赖注入)实现IOC(控制反转),常用的注入方式主要有三种:构造方法注入,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(); } }

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

问题二:如果只有一个构造方法,但是有两个参数,一个是待注入的参数,另一个是其他类型的参数,那么这次注入可以成功吗?

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

结果:失败了,即使在costract-arg标签里面通过name属性指定要注入的参数名userDao也会失败.

问题三:如果我们想向有多个参数的构造方法中注入值该在配置文件中怎么写呢?

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

参考写法:通过name属性指定要注入的值,与构造方法参数列表参数的顺序无关。

<!-- 注册userService -->
<bean id="userService" class="com.lyu.spring.service.impl.UserService"> <constructor-arg name="userDao" ref="userDaoJdbc"></constructor-arg> <constructor-arg name="user" ref="user"></constructor-arg> </bean> <!-- 注册实体User类,用于测试 --> <bean id="user" class="com.lyu.spring.entity.User"></bean> <!-- 注册jdbc实现的dao --> <bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>

问题四:如果有多个构造方法,每个构造方法只有参数的顺序不同,那通过构造方法注入多个参数会注入到哪一个呢?

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

结果:哪个构造方法在前就注入哪一个,这种情况下就与构造方法顺序有关。

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,每种注解可以任意使用,只是语义上有所差异:

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

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

  • @Resource:java的注解,默认以byName的方式去匹配与属性名相同的bean的id,如果没有找到就会以byType的方式查找,如果byType查找到多个的话,使用@Qualifier注解(spring注解)指定某个具体名称的bean。
@Resource
@Qualifier("userDaoMyBatis")
private IUserDao userDao;public UserService(){
  • @Autowired:spring注解,默认是以byType的方式去匹配与属性名相同的bean的id,如果没有找到,就通过byName的方式去查找,
@Autowired
@Qualifier("userDaoJdbc")
private IUserDao userDao;

写在最后:虽然有这么多的注入方式,但是实际上开发的时候自己编写的类一般用注解的方式注册类,用@Autowired描述依赖进行注入,一般实现类也只有一种(jdbc or hibernate or mybatis),除非项目有大的变动,所以@Qualifier标签用的也较少;但是在使用其他组件的API的时候用的是通过xml配置文件来注册类,描述依赖,因为你不能去改人家源码嘛。

转载于:https://www.cnblogs.com/moxiaotao/p/9304810.html

Spring常用的三种注入方式相关推荐

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

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

  2. Spring bean的三种注入方式

    Spring的一个重要原理就是IOC(Inverse Of Control),即控制反转.IOC就是一种将组件依赖关系的创建和管理置于程序外部的技术,在Spring中Bean组件的实例化和依赖关系的管 ...

  3. Spring构造器的三种注入方式

    构造器注入:通过构造方法注入就相当于给构造方法的参数传值,构造注入的优势是通过构造强制依赖关系,使得实例化出的bean对象一定是完整的或者可以使用的. Salary类 public class Sal ...

  4. Spring的三种注入方式(为什么推荐构造器注入?)

    Spring的三种注入方式 一.属性注入 @Resource和@Autowired的区别 为什么尽量使用 @Resource? 二.setter 注入 三.构造器注入 具体可以看看Spring官网 为 ...

  5. spring三种注入方式

    设置Spring的作用域 或者使用枚举值设置 单例和多里使用场景 自动注入 @Primary 一个接口有多个实现被spring管理吗,在依赖注入式,spring会不知道注入哪个实现类就会抛出NoUni ...

  6. Spring 依赖注入的理解及三种注入方式

    Spring 依赖注入概念和三种注入方式(理解及应用) 什么是注入 要了解Spring的三种注入方式首先前提是得先了解一下什么是注入,相信很多人对这个概念都是模糊不清的,网上的解释是这样的: 依赖注入 ...

  7. 扯一把 Spring 的三种注入方式,到底哪种注入方式最佳?

    循环依赖这个问题,按理说我们在日常的程序设计中应该避免,其实这个本来也是能够避免的.不过由于总总原因,我们可能还是会遇到一些循环依赖的问题,特别是在面试的过程中,面试考察循环依赖,主要是想考察候选人对 ...

  8. Spring 的三种注入方式?

    1. 实例的注入方式 首先来看看 Spring 中的实例该如何注入,总结起来,无非三种: 属性注入 set 方法注入 构造方法注入 我们分别来看下. 1.1 属性注入 属性注入是大家最为常见也是使用最 ...

  9. Spring 的三种注入方式,到底哪种注入方式最佳?

    1. 实例的注入方式 首先来看看 Spring 中的实例该如何注入,总结起来,无非三种: 属性注入 set 方法注入 构造方法注入 我们分别来看下. 1.1 属性注入 属性注入是大家最为常见也是使用最 ...

最新文章

  1. PAT甲级1030 Travel Plan (30分):[C++题解]dijkstra求单源最短路、保存路径
  2. Java Web 分页实现
  3. 【转】 ID,ClientID和UniqueID
  4. 『C#基础』调用CMD的一个小工具
  5. 虚拟机安装CentOS6.4
  6. HTML文件属于void值吗,使用HTML :: TreeBuilder查找html文件中的值
  7. 自适应灰色动态滚动网站404页面源码
  8. python的魔法方法
  9. yum php mysql5.5_CentOS 5.5使用yum来安装LAMP(php运行环境)
  10. python绘制散点图的函数_python绘制散点图
  11. 幼儿园学校网站JAVA_基于jsp的幼儿园网站-JavaEE实现幼儿园网站 - java项目源码
  12. Java实现语音播报功能
  13. VUE系列——弹窗代码编写与调用弹窗过程详解
  14. 把Colab运行后生成的文件保存到Google drive
  15. 作业1:关于使用python中scikit-learn(sklearn)模块,实现鸢尾花(iris)相关数据操作(数据加载、标准化处理、构建聚类模型并训练、可视化、评价模型)
  16. 伦敦国王学院EEM专业介绍
  17. 原生实现freeCodeCamp上的Build a Personal Portfolio Webpage
  18. Python数据可视化之散点图和折线图
  19. LightOJ-1253 Misere Nim
  20. 设置css手机屏幕 media all,手机屏幕自适应之css写法@media

热门文章

  1. Python经典实例:五人分鱼
  2. 二本学生小公司实习遭领导歧视,于是逆袭进百度!
  3. css 盒子模型及其理解
  4. Oracle 分析函数案例
  5. python对于前端开发有用吗_python和前端开发怎么抉择?
  6. JS字符串截取方法汇总(slice、substring、substr等)
  7. 未来计算机会是什么样子的呢,未来的电脑会是什么样?
  8. 猎豹股价跌破发行价 傅盛称内容转型导致增速放缓
  9. sql server 有关锁的视图说明 syslockinfo
  10. Vue登录注册,并保存登录状态