目录
为什么IDEA只对@Autowired警告,却对@Resource视而不见呢?
Spring常见的依赖注入(DI)方式
- 构造函数注入(Constructor Injection)
构造函数注入是在类的构造函数中声明 Bean 的依赖项,Spring 在创建 Bean 时通过构造函数来注入依赖项。构造函数注入是一种类型安全、清晰、可测试的依赖注入方式,由于必须在构造函数中传递所有依赖的依赖项,比较容易发现依赖项问题。public class ExampleService { private final ExampleRepository repository; public ExampleService(ExampleRepository repository) { this.repository = repository; } // More methods }
- 属性注入(Property Injection)
属性注入是在类的属性上使用注解或配置文件来声明 Bean 的依赖项,Spring 在创建 Bean 后通过为属性设值的方式来注入依赖项。相对于构造函数注入,属性注入更加简便,但由于存在循环依赖等问题,容易带来一些意外的问题。public class ExampleController { @Autowired private ExampleService service; // More methods }
- 方法注入(Method Injection)
方法注入是在类的方法上使用注解或者配置文件来声明 Bean 的依赖项,Spring 在创建 Bean 后通过调用Bean的方法来注入依赖项。方法注入的方式相对柔性,常用于一些具有特殊需求的 Bean 注入情况。public class ExampleService { private ExampleRepository repository; @Autowired public void setRepository(ExampleRepository repository) { this.repository = repository; } // More methods }
其中,构造函数注入是被 Spring 官方所推荐的一种依赖注入方式,因为构造函数的依赖关系是非循环的并且类型安全的,能够有效地避免一些意外情况的发生。同时,属性注入、方法注入虽然也有它们独特的使用场景,但它们都不够优雅和安全,需要尽量避免使用。
属性注入(Field注入)的缺点
在 Spring 的依赖注入过程中,属性注入虽然比构造函数注入更加简单方便,但也存在一些缺点:
1.无法保证依赖项的完成性
使用属性注入方式时,由于容器在创建 Bean 后直接为属性赋值,无法保证依赖项已经被完全初始化。如果一个 Bean 的依赖项没有正确初始化,就会引发一系列意外的问题。而构造函数注入能够保证在构造函数中传递所有依赖的依赖项,从而更容易发现依赖项问题。
2.循环依赖能够发生
使用属性注入时,如果两个或多个 Bean 相互依赖,循环依赖可能发生。在这种情况下,Spring 会将其中一个 Bean 创建一个代理对象,并将另一个 Bean 注入到该代理对象中。这会带来额外的性能开销以及可能出现预期外的错误。
3.加载顺序由 Spring 确定,不够自由
使用属性注入时,我们不能保证在所有的属性已经设置之前是否已经调用了其他方法。这通常不是问题,但是在某些情况下,构造函数注入能够提供更高的可读性和可测试性。
4.依赖过多时不够明显
比如我需要10个依赖,用构造器注入就会显得庞大,这时候应该考虑一下此组件是不是违反了单一职责原则
5.不能像构造器那样注入不可变的对象
5.依赖对外部不可见
外界可以看到构造器和setter,但无法看到私有字段,自然无法了解所需依赖
综上,属性注入虽然更加方便,但是存在一些缺点。在开发中,应该根据具体需要选择合适的注入方式,避免导致依赖项问题和其他潜在的风险。同时,尽管属性注入被批评为“背刺式注入”,但它仍然可以在适当的场合下使用,并且是广泛使用的依赖注入方式之一。
@Autowired VS @Resource
事实上,他们的基本功能都是通过注解实现依赖注入 ,只不过@Autowired是Spring定义的,而@Resource是JSR-250定义的。大致功能基本相同,但是还有一些细节不同:
- 依赖识别方式 :@Autowired默认是根据类型 (byType), 可以使用@Qualifier指定Name,@Resource默认时根据名字(ByName ),如果找不到再根据类型(ByType)
- 适用对象 :@Autowired可以对构造器、方法、参数、字段 使用,@Resource只能对方法、字段使用
- 提供方 :@Autowired是Spring 提供的,@Resource是JSR-250 提供的
为什么IDEA只对@Autowired警告,却对@Resource视而不见呢?
- @Autowired 是Spring 提供的,它是特定IoC提供的特定注解 ,这就导致了应用与框架的强绑定 ,一旦换用了其他的IoC框架,是不能够支持注入的。而 @Resource 是JSR-250 提供的,它是Java标准 ,我们使用的IoC容器应当去兼容它,这样即使更换容器,也可以正常工作。
- 同时,@Autowired和 @Resource的默认注入方式不同,@Autowired默认是根据类型进行注入的, @Resource默认是先根据名字注入,找不到再根据类型注入的。所以,相比于 @Autowired 注解,@Resource 注解更加灵活,但同时也更难以确保依赖项的正确性。如果无法确定自动注入的 Bean 是否正确,可以通过 @Qualifier 注解或者手动注入的方式显式指定 Bean 的名称或类型,避免依赖项注入的错误和困扰。