使用前提

  • 在spring容器中
  • 在包扫描路径下

使用场景

该注解主要用于创建对象(比较常用的就是CRUD操作)

测试结构

1
2
3
4
5
6
7
src.main    
├── java.com.auto.test // 启动类
│ └── Base.java // 父接口
│ └── Dog.java // 子类1
│ └── Cat.java // 子类2
│ └── MyComponent.java // 自定义
├── test.java.auto // 测试类

测试子类及结论

先证明@Autowired发挥作用

1
2
3
4
// 父类
public interface Base {
void eat();
}
1
2
3
4
5
6
7
8
// 子类1
@Component
public class Cat implements Base {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
// 测试类
@SpringBootTest
class PracticeApplicationTests {
@Autowired
Base dog;

@Test
void contextLoads() {
dog.eat();
}

}

成功运行并打印猫吃鱼
结论1:此时Dog类还没有被定义,说明@Autowired是根据类型注入的
结论2:@Component必须放在实现类中,如果放到父类中,子类实现其方法无法进行继承(无论有无@Inherited注解)

1
2
3
4
5
6
7
8
// 子类2
@Component
public class Dog implements Base{
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
// 测试类
@SpringBootTest
class AutoApplicationTests {
@Autowired
Base dog;

@Test
void contextLoads() {
dog.eat();
}

}

此时输出狗吃肉
结论3:因为两个类都实现Base接口,spring无法根据其类型去确定哪一个实现类,会根据名称来确定,如果未指定,则根据变量名确定。此时定义dog,所以输出dog的方法。如果变量名既不是cat也不是dog,那么IDE会提示Could not autowire. There is more than one bean of 'Base' type.也无法正常运行

证明结论2,@Component本身没有实现@Inherited,所以才不能作用于接口吗?

1
2
3
4
5
6
7
// 自定义接口类并定义继承行为
@Component
@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {
}
1
2
3
4
5
6
7
8
// 修改注解,验证自定义注解可用
@MyComponent
public class Dog implements Base{
@Override
public void eat() {
System.out.println("狗吃肉");
}
}

此时输出狗吃肉
在将该注解去除,并在Base接口上添加,运行会提示Unsatisfied dependency expressed through field 'cat';无法找到依赖对象,说明没有加入spring容器中,也就证明结论2

如果多个类实现了一个接口,应该如何指定?

使用@Qualifier("cat")注解,或者使用@Resource(name = "cat")进行名称指定。这两个注解作用是相同的,但一般使用@Autowired实现