java中同一个接口有两个或两个以上实现类时应当如何注入?
例如有一个接口,如下代码:
package com.xiangxue.util;
public interface DemoService {
void demo();
}
此时有两个实现类实现了这个接口
实现类一: 代码如下
package com.xiangxue.util;
@Service("demoServiceImpl")
public class DemoServiceImpl implements DemoService{
@Override
public void demo() {
}
}
实现类二: 代码如下
package com.xiangxue.util;
@Service("demoServiceImpl2")
public class DemoServiceImpl2 implements DemoService{
@Override
public void demo() {
}
}
如果此时按照常规@Autowired注入,系统会报错,注入不进去:代码如下
package com.xiangxue.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/demoController")
public class DemoController {
@Autowired
private DemoService demoService;
@RequestMapping("demo")
public void demo(){
demoService.demo();
}
}
@Autowired是按 byType的方式进行注入的,当要注入的类型在容器中存在多个时,Spring是不知道要引入哪个实现类的,所以会报错。
这种场景下,只能通过 byName 方式注入。可以使用 @Resource 或 @Qualifier 注解。
@Resource 默认是按照 byName 的方式注入的, 如果通过 byName 的方式匹配不到,再按 byType 的方式去匹配。可以如下修改:
package com.xiangxue.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
/**
* @projectName: ref-comet
* @package: com.xiangxue.util
* @className: DemoController
* @author: sunyingtao
* @description: TODO
* @date: 2022/12/21 22:52
* @version: 1.0
*/
@Controller
@RequestMapping("/demoController")
public class DemoController {
@Resource(name = "demoServiceImpl")
private DemoService demoService;
@RequestMapping("demo")
public void demo(){
demoService.demo();
}
}
或者将@Qualifier与@Autowired组合使用,代码如下:
package com.xiangxue.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
/**
* @projectName: ref-comet
* @package: com.xiangxue.util
* @className: DemoController
* @author: sunyingtao
* @description: TODO
* @date: 2022/12/21 22:52
* @version: 1.0
*/
@Controller
@RequestMapping("/demoController")
public class DemoController {
@Autowired
@Qualifier("demoServiceImpl")
private DemoService demoService;
@RequestMapping("demo")
public void demo(){
demoService.demo();
}
}
小结:
1、@Autowired 注解是通过 byType 类型的方式注入的,要求接口只能有一个实现类。
2、@Resource 注解可以通过 byName 和 byType的方式注入, 默认先按 byName的方式进行匹配,如果匹配不到,再按 byType的方式进行匹配。
3、@Qualifier 注解配合@Autowired 一起使用。
还有另外一种方式:
在某一个实现类上加上@Primary注解来解决(该类则不需要bean的name),该注解代表优先加载哪个bean;对于其他的实现则可以在类上定义bean的name