@Autowired 注解属于 org.springframework.beans.factory. annotation 包,可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。
@Service 注解属于 org.springframework.stereotype 包,会将标注类自动注册到 Spring 容器中。

在一个类上面标注@Service或者@Controller或@Component或@Repository注解后,容器启动时,Spring组件扫描时就会发现它,并且会直接将其创建好变成Spring应用上下文中bean。
在需要使用时通过@Autowired注解把容器创建好的bean从容器获取过来赋予给使用类的成员属性

@Autowired注解的注入规则
默认根据类型,存在多个时则根据名字进行匹配

1.定义一个user的service接口

public interface User {
    void hello();
}

2.创建一个user的service接口的实现类

@Service
public class Userimpl implements User{
    @Override
    public void hello(){
        System.out.println("hello");
    }
}

3.增加一个Controller,注入user的service
 

@Controller
public class HelloController {
    @Autowired
    private User user;
    public void hello(){
        user.hello();
    }
}

4.在测试类中运行

@SpringBootTest
class SbPack2ApplicationTests {
    private HelloController helloController;

    @Autowired
    public SbPack2ApplicationTests (HelloController helloController)
    {
        this.helloController=helloController;
    }
    @Test
    void contextLoads() {
        helloController.hello();
    }
}

成功输出了hello

但是如果user接口有两个实现类比如说再增加如下一个实现类

@Service
public class NewUserimpl implements User{
    @Override
    public void hello(){
        System.out.println("hello");
    }
}

那么Controller里面就会出现报错,此时IoC容器中HelloService 接口存在两个实现类,自动装配决定不了使用哪一个实现类,会像下图一样报错

springboot controller中注入serverlet对象 spring注入service_spring


这时候就需要用到一个新的注解
@Qualifier是指定 一个bean的名字
作用就是解决当使用@Autowired遇到多个实现类时的问题
现在我们可以尝试

@Controller
public class HelloController {

    @Qualifier("newUserimpl") //这里并不是和实现类名完全相同,应该有自己的命名规则
    @Autowired
    private User newuser;

    @Qualifier("userimpl")
    @Autowired
    private User user;

    public void hello(){
        user.hello();
        newuser.hello();
    }
}

输出结果如下

springboot controller中注入serverlet对象 spring注入service_spring boot_02

又或者当出现多个实现类时我们还可以这样做,在service注解处直接标明限定符

@Service("abs")
public class Userimpl implements User{
    @Override
    public void hello(){
        System.out.println("hello");
    }
}
@Service("abd")
public class NewUserimpl implements User{
    @Override
    public void hello(){
        System.out.println("new hello");
    }
}

那么在Controller中使用时就可以不用加上@Qualifier注解
而是让属性名直接就是限定符

@Controller
public class HelloController {
    @Autowired
    private User abs;

    @Autowired
    private User abd;
    public void hello(){
        abs.hello();
        abd.hello();
    }
}

同样也能正常输出

springboot controller中注入serverlet对象 spring注入service_spring boot_03

但是当我们需要用同一个实现类创建两个属性时就需要属性名不同而且还要用到 @Qualifier
Controller中就变成

@Controller
public class HelloController {
    @Autowired
    private User abs;
    @Autowired
    private User abd;

    @Qualifier("abd")
    @Autowired
    private User abd1;
    public void hello(){
        abs.hello();
        abd.hello();
        abd1.hello();
    }
}

 输出变成

springboot controller中注入serverlet对象 spring注入service_java_04

上面提到的添加了@Service的实现类会在扫描进入IOC容器变成一个bean时就如下图所示
当在其中一个实现类中加上一个无参构造函数,不论下面有没有使用@Autowired进行注入都会执行一遍

@Service("abs")
public class Userimpl implements User{
    public Userimpl(){
        System.out.println("hello user");
    }
    @Override
    public void hello(){
        System.out.println("hello");
    }
}

 

springboot controller中注入serverlet对象 spring注入service_java_05

 可以看见构造参数的输出是最先出现的

总结
1.接口只有一个实现类时,属性名字随意,因为按照类型匹配就只有一个bean
2.在一个接口有多个实现类的情况下:
  (1)通过@Qualifier 注解指定实现类的标识符
  (2)在声明实现类时就加上标识符
3.在一个借口有多个实现类并且其中同一个实现类创建了多个属性的情况下
  同一个实现类创建的多个属性属性名必须不同而且除了使用标识符作为属性
  名的属性其余的都要加上@Qualifier指定标识符