Spring常用的三种注入方式

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Spring常⽤的三种注⼊⽅式
Spring通过DI(依赖注⼊)实现IOC(控制反转),常⽤的注⼊⽅式主要有三种:构造⽅法注⼊,setter注⼊,基于注解的注⼊。

构造⽅法注⼊
先简单看⼀下测试项⽬的结构,⽤maven构建的,四个包:
entity:存储实体,⾥⾯只有⼀个User类
dao:数据访问,⼀个接⼝,两个实现类
service:服务层,⼀个接⼝,⼀个实现类,实现类依赖于IUserDao
test:测试包
在spring的配置⽂件中注册UserService,将UserDaoJdbc通过constructor-arg标签注⼊到UserService的某个有参数的构造⽅法
<!-- 注册userService -->
<bean id="userService" class="erService">
<constructor-arg ref="userDaoJdbc"></constructor-arg>
</bean>
<!-- 注册jdbc实现的dao -->
<bean id="userDaoJdbc" class="erDaoJdbc"></bean>
如果只有⼀个有参数的构造⽅法并且参数类型与注⼊的bean的类型匹配,那就会注⼊到该构造⽅法中。

public class UserService implements IUserService {
private IUserDao userDao;
public UserService(IUserDao userDao) {
erDao = 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("这是有⼀个参数的构造⽅法");
erDao = userDao;
}
public UserService(IUserDao userDao, User user) {
System.out.println("这是有两个参数的构造⽅法");
erDao = userDao;
er = user;
}
public void loginUser() {
userDao.loginUser();
}
}
结果:会注⼊到只有⼀个参数的构造⽅法中,并且经过测试注⼊哪⼀个构造⽅法与构造⽅法的顺序⽆关
问题⼆:如果只有⼀个构造⽅法,但是有两个参数,⼀个是待注⼊的参数,另⼀个是其他类型的参数,那么这次注⼊可以成功吗?public class UserService implements IUserService {
private IUserDao userDao;
private User user;
public UserService(IUserDao userDao, User user) {
erDao = userDao;
er = 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) {
erDao = userDao;
er = user;
}
public void loginUser() {
userDao.loginUser();
}
}
参考写法:通过name属性指定要注⼊的值,与构造⽅法参数列表参数的顺序⽆关。

<!-- 注册userService -->
<bean id="userService" class="erService">
<constructor-arg name="userDao" ref="userDaoJdbc"></constructor-arg>
<constructor-arg name="user" ref="user"></constructor-arg>
</bean>
<!-- 注册实体User类,⽤于测试 -->
<bean id="user" class="er"></bean>
<!-- 注册jdbc实现的dao -->
<bean id="userDaoJdbc" class="erDaoJdbc"></bean>
问题四:如果有多个构造⽅法,每个构造⽅法只有参数的顺序不同,那通过构造⽅法注⼊多个参数会注⼊到哪⼀个呢?
public class UserService implements IUserService {
private IUserDao userDao;
private User user;
public UserService(IUserDao userDao, User user) {
System.out.println("这是第⼆个构造⽅法");
erDao = userDao;
er = user;
}
public UserService(User user, IUserDao userDao) {
System.out.println("这是第⼀个构造⽅法");
erDao = userDao;
er = user;
}
public void loginUser() {
userDao.loginUser();
}
}
结果:哪个构造⽅法在前就注⼊哪⼀个,这种情况下就与构造⽅法顺序有关。

setter注⼊
配置⽂件如下:
<!-- 注册userService -->
<bean id="userService" class="erService">
<!-- 写法⼀ -->
<!-- <property name="UserDao" ref="userDaoMyBatis"></property> -->
<!-- 写法⼆ -->
<property name="userDao" ref="userDaoMyBatis"></property>
</bean>
<!-- 注册mybatis实现的dao -->
<bean id="userDaoMyBatis" class="erDaoMyBatis"></bean>
注:上⾯这两种写法都可以,spring会将name值的每个单词⾸字母转换成⼤写,然后再在前⾯拼接上”set”构成⼀个⽅法名,然后去对应的类中查找该⽅法,通过反射调⽤,实现注⼊。

切记:name属性值与类中的成员变量名以及set⽅法的参数名都⽆关,只与对应的set⽅法名有关,下⾯的这种写法是可以运⾏成功的public class UserService implements IUserService {
private IUserDao userDao1;
public void setUserDao(IUserDao userDao1) {
erDao1 = 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配置⽂件来注册类,描述依赖,因为你不能去改⼈家源码嘛。

相关文档
最新文档