spring版本:4.1.6.RELEASE
示例代码
接口
public interface UserService{}
实现类1
@Service("myUserService")
public class UserServiceImpl implements UserService{}
实现类2
@Service("wxUserService")
public class WxUserServiceImpl implements UserService{}
实现类3
@Service
public class ComUserServiceImpl implements UserService{}
Bean name
以上代码通过@Service
指定Bean name,也可以通过bean标签的id属性指定Bean name。Bean name的规则是即使实现类实现了不同的接口,也不允许重复。否则将抛出异常如下
org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'xxxService' for bean class [com.xxx.service.Xxx1ServiceImpl] conflicts with existing, non-compatible bean definition of same name and class [com.xxx.service.Xxx2ServiceImpl]
这表示Xxx1ServiceImpl和Xxx2ServiceImpl实现类的Bean name是一样的,这是不允许的。
Bean name的默认值
实现类Bean name的默认值为实现类名称(首字母将自动转换为小些),如以上ComUserServiceImpl的Bean name则为comUserServiceImpl
@Autowired注入
通过@Autowird注解注入有以下两种情况
- 如果为接口仅找到一个实现类,则注入该实现类
- 如果为接口找到多个实现类,则根据注入的变量名称来匹配bean的名称,如果成功匹配则注入对应的bean。
根据以上规则,以下变量均能成功注入
@Controller
public class UserController {
// 发现多个实现类,将变量名称wsUserService作为Bean name跟所有实现类的Bean name进行匹配,最终得到WsUserSeriviceImpl实例
@Autowired
private UserService wsUserService;
// 发现多个实现类,将变量名称comUserServiceImpl作为Bean name跟所有实现类的Bean name进行匹配,最终得到ComUserServiceImpl实例
@Autowired
private UserService comUserServiceImpl;
// 如果只有UserServiceImpl实现类,那么直接根据类型注入,该变量也会被成功注入值
@Autowired
private UserService us;
}
如果存在多个实现类,且变量名称没有跟任何实现类定义的名称匹配,则会抛出如下异常
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.xxx.service.XxxService] is defined: expected single matching bean but found 2
@Autowired(required=false)
@Autowired注解并不是表示不注入当前变量,或者说在多个实现类的情况下找不到对应Bean时则不注入(如果找不到依然会抛出异常),而是表示如果当前变量类型没有实现类则可以不注入,同样的情况如果required为true则会报错。
@Resource注入
@Resource注解有如下几种情况
- 什么都不指定,采用Bean name注入方式,在这里将变量名称作为Bean name进行匹配注入。
- 仅指定Bean name,采用Bean name注入方式
- 仅指定Bean type,采用Bean type注入方式
- 同时指定Bean name和Bean type,则进行双重校验,即指定的Bean type的Bean name恰好等于指定的Bean name。
根据以上规则,以下变量均能注入成功
@Controller
public class UserController {
// 将变量名称wsUserService作为Bean name跟所有实现类的Bean name进行匹配,最终得到WsUserServiceImpl
@Resource
private UserService wsUserService;
// 将name属性值wsUserService作为Bean name跟所有实现类进行匹配,最终得到WsUserServiceImpl
@Resource(name="wsUserService")
private UserService wsUserService2;
// 将type属性值作为实例类符号引用跟所有实现类进行匹配,最终得到ComUserServiceImpl
@Resource(type=ComUserServiceImpl.class)
private UserService userService;
// 同时指定name和type,先根据name找到对应的Bean,然后比对Bean的符号引用是否和指定的type相同,最终得到WsUserServiceImpl,如果不同则会抛出异常
@Resource(name="wsUserService",type=WxUserServiceImpl.class)
private UserService us;
// 注入失败,Bean name为wsUserService的类为WsUserServiceImpl,与指定的type不一致,抛出异常
@Resource(name="wsUserService",type=ComUserServiceImpl.class)
private UserService us;
}
@Qualifier
Qualifier的中文意思是“形容”,这也就不难理解@Qualifier只是一个辅助注解,用于辅助@Autowired和@Resource进一步确定Bean,当通过@Autowired或@Resouce发现多个Bean或没有发现Bean时,@Qualifier对Bean的描述就成了Bean的唯一标识。所以@Qualifier需要和@Autowired或@Resource结合使用
。
根据@Qualifier的特性,可以用以下代码来进一步诠释
@Controller
public class UserController {
// 通过@Autowired发现有多个实现类,通过us没有匹配到任何实现类,此时获取到到@Qualifier对实现类有其他形容,得到实现类的Bean name为wsUserService,最终可确认实现类为WsUserServiceImpl
@Autowired
@Qualifier("wsUserService")
private UserService us;
// @Resource通过us2没有发现实现类,此时获取到@Qualifier对实现类有其他描述,得到实现类的Bean name为comUserServiceImpl,最终可确认实现类为comUserServiceImpl
@Resource
@Qualifier("comUserServiceImpl")
private UserService us2;
}
(完)