SpringBoot依赖注入以及相关注解
近期的一个项目中需要搭建一个后端,根据ChatGPT之神的指引,决定使用开源、简洁的后端框架Spring Boot。选这个框架的另一个原因是《服务计算基础》这门课中接触了一下Apache Dubbo、Spring Boot和Apache Axis这几个后端的开发方式,发现还是使用Spring Boot开发一个REST接口最简单轻量,毕竟不是专门要走后端方向,最简单的学习成本才是最重要的。
依赖
读完了依赖~我很快就离开~
在了解依赖注入前需要知道什么是依赖,很显然,这里的依赖并不是更广为人知的那个,程序编译运行时所需要的第三方代码。这里的依赖指的是类在构造时所需要的其他对象,或者说这个类包含了哪些字段,这些字段都可以看成是这个类的依赖。
举个例子(没有代码,自己想象一下吧),一个汽车对象Car
需要另一个引擎对象Engine
,和轮胎对象Wheel
来实例化,而Engine
可能还需要齿轮对象Gear
来实例化,那么这样的关系就可以构成一个依赖关系了。
常规Java对象中的依赖
“常规Java对象”这个词有点老土了,现在似乎根喜欢用**POJO对象(Plain Old Java Object)**来形容一个没有依赖于特定框架、库,且没有继承关系、接口的对象,这样的对象在开发中一般是用于数据封装和传输的。
在POJO对象中,依赖关系通常是通过构造函数来完成的,这点应该比较容易理解,就不再详述了。
Spring Boot中的依赖
在Spring Boot中,很少提到构造方法这个玩意,这就是因为Spring Boot中的依赖是使用**依赖注入(Dependency Injection,DI)**来实现的。
接下来的内容,是参考w3school的Spring Boot教程以及ChatGPT,结合自己的想象而编写的,可能含有错误。
Bean
在Spring Boot中,(可以)将被依赖的对象抽象为Bean,在Spring Boot启动时,会自动将实例化这些Bean对象,并将它们装入到容器中。当有组件依赖于某个Bean时,Spring Boot就会从容器中取出这个Bean(的引用),传递给这个组件。需要注意的事,Spring Boot中的Bean默认是单例模式,也就是说,如果有多个地方依赖某个Bean,则这个Bean不会被实例化多次,每次传递回去的引用都指向同一个Bean对象。
可以通过方法或类来创建Bean。
Bean的创建——通过方法
如果通过方法来创建Bean,则只需要在相应的方法前添加@Bean
注解即可,方法的返回值即为Bean,创建的Bean名字默认为方法名,当然也可以通过@Bean(name="xxx")
来修改。另外,最好在这个方法所在的类前加上@Configuration
注解,这是为了能够保持Bean在容器中是单例模式。被@Configuration
注解的类也会被当做一个Bean,可以通过下一节的方法来为其指定依赖注入的方法。
事实上,开发Spring Boot时一般会专门创建一个Config
类,用于提供“提供Bean”的方法。
1 |
|
如果被@Bean
注解的方法依赖其他Bean,则Spring会自动解析依赖并注入。
Bean的创建——通过类
也可以通过类来创建Bean,只需要在类前添加@Component
注解,默认名字是类名首字母小写,也可以通过@Component(name="xxx")
来创建。
1 |
|
@Component
有三个派生注解,分别为@Service
、Repository
、Controller
,根据具体应用场景的不同,可以选择不同的派生注解。@Service
注解和@Component
注解几乎没有区别,但是@Service
有更明显的语义;@Repository
提供了与数据库操作相关的异常处理机制,将底层的JDBC异常转化为Spring的异常;而@Controller
是用于提供Web层的请求。
Bean的创建——通过配置文件
也可以通过@ConfigurationProperties
将配置文件中的属性值绑定到Bean的字段上,这需要配合@Component
注解来使用。
1 |
|
随后就可以使用AutoWire
来注入这个对象。
注入
创建完Bean之后,需要考虑的就是如何将其注入到对象中去。注入也有多种方法,主要靠的是@AutoWired
注解。
字段注入
直接在字段上使用@Autowired
,Spring会自动注入该Bean。
1 |
|
该方法简洁,代码量少,但是不利于单元测试(因为没有构造函数,可以直接注入时较难模拟)。最重要的是,使用字段注入很容易漏掉一些Bean,使得程序在运行过程中出现空指针,所以不推荐使用。
构造函数注入
可以在构造函数前加上@AutoWired
来注入依赖:
1 |
|
加上@AutoWired
注解后,Spring会自动对构造函数的每个函数进行依赖注入,相较于上一种方法,该方法是强制注入的,可以使得代码更健壮,因为不会出现空指针问题。使用构造函数进行依赖注入有以下规则:
- 一个(被
@Component
修饰的)类中 只能有一个构造器使用了@Autowired注解标记; - 如果没有构造器使用@Autowired注解且存在多个构造器,将选择依赖数量最多的构造器完成注入;
- 如果没有构造器使用@Autowired注解且只存在一个构造器,将选择这个默认的构造器;
Setter函数注入
1 |
|
Setter函数注入会在对象创建完成后,所以可以在初始化后修改依赖。所以,该方法也容易遗漏依赖,一般将该方法作为可选依赖的注入方法。
通过@Value
进行简单注入
@Value
注解用于注入来自配置文件(如application.properties
或application.yml
)的简单值或表达式。
1 |
|
在这种方式下,@Value
可以注入配置文件中的值,也可以直接注入常量或SpEL表达式的结果。
指定名称的注入
当容器中存在多个相同类型的Bean时,@Qualifier
可以用来指定要注入的具体Bean。
1 |
|
在这种情况下,Spring会注入名为anotherServiceA
的Bean。@Qualifier
可以和@Autowired
一起使用,确保注入正确的Bean。
注入前后的操作
如果想在Bean初始化后执行某些操作(例如初始化一些资源),可以使用@PostConstruct
注解的方法。类似地,@PreDestroy
可以在Bean销毁之前执行一些清理操作。
1 |
|
该注解不能标注在静态方法上,且要求标注的方法不能接受任何参数,返回类型必须是void
。