ToB企服应用市场:ToB评测及商务社交产业平台
标题:
使用 Spring 实现控制反转和依赖注入
[打印本页]
作者:
曹旭辉
时间:
2023-8-11 23:55
标题:
使用 Spring 实现控制反转和依赖注入
概述
在本文中,我们将介绍IoC(控制反转)和DI(依赖注入)的概念,以及如何在Spring框架中实现它们。
什么是控制反转?
控制反转是软件工程中的一个原则,它将对象或程序的某些部分的控制权转移给容器或框架。我们最常在面向对象编程的上下文中使用它。
与传统编程相比,传统编程中我们的自定义代码调用库,而IoC使框架控制程序的流程并调用我们的自定义代码。为了实现这一点,框架使用具有附加行为的抽象。如果我们想要添加自己的行为,我们需要扩展框架的类或插入自己的类。
这种架构的优点是:
将任务的执行与其实现分离
更容易在不同实现之间切换
程序的更高的模块化
更容易通过隔离组件或模拟其依赖项来测试程序,并允许组件通过契约进行通信
我们可以通过各种机制实现IoC,例如:策略设计模式、服务定位器模式、工厂模式和依赖注入(DI)。
什么是依赖注入?
依赖注入是一种我们可以用来实现IoC的模式,其中被反转的控制是设置对象的依赖项。
将对象与其他对象连接或将对象“注入”到其他对象中是由汇编程序而不是对象本身完成的。
下面是在传统编程中创建对象依赖关系的方法:
publicclassStore<bean id="store" autowire="byType"> </bean>{
private<bean id="store" autowire="byType"> </bean>Item<bean id="store" autowire="byType"> </bean>item;
publicStore()<bean id="store" autowire="byType"> </bean>{
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>item<bean id="store" autowire="byType"> </bean>=newItemImpl1();
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>}
}Copy
复制代码
在上面的示例中,我们需要在
Store
类本身中实例化
Item
接口的实现。
通过使用DI,我们可以重写该示例,而不指定我们想要的
Item
的实现:
publicclassStore<bean id="store" autowire="byType"> </bean>{
private<bean id="store" autowire="byType"> </bean>Item<bean id="store" autowire="byType"> </bean>item;
publicStore(Item<bean id="store" autowire="byType"> </bean>item)<bean id="store" autowire="byType"> </bean>{
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>this.item<bean id="store" autowire="byType"> </bean>=<bean id="store" autowire="byType"> </bean>item;
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>}
}Copy
复制代码
在接下来的几节中,我们将看看如何通过元数据提供
Item
的实现。
IoC和DI都是简单的概念,但它们对我们构建系统的方式有深刻的影响,因此值得充分理解。
Spring<bean id="store" autowire="byType"> </bean>IoC容器
IoC容器是实现IoC的框架的常见特征。
在Spring框架中,接口ApplicationContext表示IoC容器。Spring容器负责实例化、配置和组装称为bean的对象,以及管理它们的生命周期。
Spring框架提供了
ApplicationContext
接口的几个实现:
ClassPathXmlApplicationContext
和
FileSystemXmlApplicationContext
用于独立应用程序,以及
WebApplicationContext
用于Web应用程序。
为了组装bean,容器使用配置元数据,可以是XML配置或注释形式。
以下是手动实例化容器的一种方法:
ApplicationContext<bean id="store" autowire="byType"> </bean>context
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>=newClassPathXmlApplicationContext("applicationContext.xml");Copy
复制代码
在上面的示例中,我们可以使用元数据设置
item
属性,然后容器将读取此元数据并在运行时使用它来组装bean。
在Spring中,可以通过构造函数、setter或字段来进行依赖注入。
基于构造函数的依赖注入
在基于构造函数的依赖注入的情况下,容器将调用具有表示我们要设置的依赖项的参数的构造函数。
Spring通过类型解决每个参数,然后按属性名称和索引进行消歧。让我们看看使用注释配置bean及其依赖项的配置:
@Configuration
publicclassAppConfig<bean id="store" autowire="byType"> </bean>{
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>@Bean
public<bean id="store" autowire="byType"> </bean>Itemitem1()<bean id="store" autowire="byType"> </bean>{
returnnewItemImpl1();
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>}
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>@Bean
public<bean id="store" autowire="byType"> </bean>Storestore()<bean id="store" autowire="byType"> </bean>{
returnnewStore(item1());
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>}
}Copy
复制代码
@Configuration
注释表示该类是bean定义的源。我们也可以将其添加到多个配置类中。
我们在方法上使用@Bean注释来定义bean。如果我们没有指定自定义名称,则bean名称将默认为方法名称。
对于默认的
singleton
范围的bean,Spring首先检查是否已存在缓存的bean实例,仅在不存在时创建新实例。如果我们使用
prototype
范围,则容器为每个方法调用返回一个新的bean实例。
创建bean的另一种方式是通过XML配置:
<bean<bean id="store" autowire="byType"> </bean>id="item1"<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>/>
<bean<bean id="store" autowire="byType"> </bean>id="store"<bean id="store" autowire="byType"> </bean>>
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><constructor-arg<bean id="store" autowire="byType"> </bean>type="ItemImpl1"<bean id="store" autowire="byType"> </bean>index="0"<bean id="store" autowire="byType"> </bean>name="item"<bean id="store" autowire="byType"> </bean>ref="item1"<bean id="store" autowire="byType"> </bean>/>
</bean>Copy
复制代码
基于setter的依赖注入
对于基于setter的DI,容器将在调用没有参数的构造函数或没有参数的静态工厂方法来实例化bean之后调用我们类的setter方法。让我们使用注释创建此配置:
@Bean
public<bean id="store" autowire="byType"> </bean>Storestore()<bean id="store" autowire="byType"> </bean>{
Store<bean id="store" autowire="byType"> </bean>store<bean id="store" autowire="byType"> </bean>=newStore();
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>store.setItem(item1());
return<bean id="store" autowire="byType"> </bean>store;
}Copy
复制代码
我们也可以使用XML进行相同的bean配置:
<bean<bean id="store" autowire="byType"> </bean>id="item1"<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>/>
<bean<bean id="store" autowire="byType"> </bean>id="store"<bean id="store" autowire="byType"> </bean>>
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><constructor-arg<bean id="store" autowire="byType"> </bean>type="ItemImpl1"<bean id="store" autowire="byType"> </bean>index="0"<bean id="store" autowire="byType"> </bean>name="item"<bean id="store" autowire="byType"> </bean>ref="item1"<bean id="store" autowire="byType"> </bean>/>
</bean>Copy
复制代码
我们可以将构造函数和setter类型的注入结合在同一个bean中。Spring文档建议将基于构造函数的注入用于必需的依赖项,将基于setter的注入用于可选的依赖项。
基于字段的依赖注入
在基于字段的DI的情况下,我们可以通过带有@Autowired注释的注释将依赖项注入其中:
publicclassStore<bean id="store" autowire="byType"> </bean>{
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>@Autowired
private<bean id="store" autowire="byType"> </bean>Item<bean id="store" autowire="byType"> </bean>item;
}Copy
复制代码
在构造
Store
对象时,如果没有构造函数或setter方法将
Item
<bean id="store" autowire="byType"> </bean>bean注入其中,容器将使用反射将
Item
注入
Store
中。
我们也可以使用XML来实现这一点。
这种方法可能看起来更简单、更清晰,但我们不建议使用它,因为它有一些缺点,例如:
此方法使用反射来注入依赖项,这比基于构造函数或setter的注入更昂贵。
使用此方法很容易添加多个依赖项。如果我们使用构造函数注入,有多个参数会让我们认为这个类做了不止一件事,这可能违反单一责任原则。
自动装配依赖项
自动装配允许Spring容器通过检查已定义的bean来自动解决协作bean之间的依赖关系。
使用XML配置有四种自动装配bean的模式:
no:默认值<bean id="store" autowire="byType"> </bean>-<bean id="store" autowire="byType"> </bean>这意味着不使用自动装配,我们必须显式地命名依赖项。
byName:按属性名称进行自动装配,因此Spring将查找与需要设置的属性同名的bean。
byType:类似于按名称进行自动装配,仅基于属性的类型。这意味着Spring将查找具有相同类型的属性来设置的bean。如果有多个bean具有该类型,则框架会抛出异常。
constructor:基于构造函数参数进行自动装配,意味着Spring将查找具有与构造函数参数相同类型的bean。
例如,让我们通过类型创建具有依赖项
item
的
store
bean。
public<bean id="store" autowire="byType"> </bean>class<bean id="store" autowire="byType"> </bean>AppConfig<bean id="store" autowire="byType"> </bean>{
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>@Bean
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>public<bean id="store" autowire="byType"> </bean>Item<bean id="store" autowire="byType"> </bean>item()<bean id="store" autowire="byType"> </bean>{
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>return<bean id="store" autowire="byType"> </bean>new<bean id="store" autowire="byType"> </bean>ItemImpl1();
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>}
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>@Bean(autowire<bean id="store" autowire="byType"> </bean>=<bean id="store" autowire="byType"> </bean>Autowire.BY_TYPE)
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>public<bean id="store" autowire="byType"> </bean>Store<bean id="store" autowire="byType"> </bean>store()<bean id="store" autowire="byType"> </bean>{
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>return<bean id="store" autowire="byType"> </bean>new<bean id="store" autowire="byType"> </bean>Store();
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>}
}
复制代码
请注意,自Spring<bean id="store" autowire="byType"> </bean>5.1起,
autowire
属性已弃用。
我们还可以使用@Autowired注释按类型注入bean:
public<bean id="store" autowire="byType"> </bean>class<bean id="store" autowire="byType"> </bean>Store<bean id="store" autowire="byType"> </bean>{
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>@Autowired
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>private<bean id="store" autowire="byType"> </bean>Item<bean id="store" autowire="byType"> </bean>item;
}
复制代码
如果存在相同类型的多个bean,则可以使用@Qualifier注释按名称引用bean:
public<bean id="store" autowire="byType"> </bean>class<bean id="store" autowire="byType"> </bean>Store<bean id="store" autowire="byType"> </bean>{
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>@Autowired
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>@Qualifier("item1")
<bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean><bean id="store" autowire="byType"> </bean>private<bean id="store" autowire="byType"> </bean>Item<bean id="store" autowire="byType"> </bean>item;
}
复制代码
现在,让我们通过XML配置按类型自动装配bean:
<bean id="store" autowire="byType"> </bean>
复制代码
接下来,让我们通过XML按名称将名为
item
的bean注入到
store
bean的
item
属性中:
[/code]我们还可以通过构造函数参数或setter显式定义依赖关系来覆盖自动装配。
[size=5]惰性初始化的bean[/size]
默认情况下,容器在初始化期间创建和配置所有单例bean。为了避免这种情况,我们可以在bean配置上使用值为[i]true[/i]的[i]lazy-init[/i]属性:
[code]
复制代码
因此,只有在第一次请求它时,才会初始化
item1
bean,而不是在启动时。这样做的优点是初始化时间更快,但缺点是我们在bean被请求之后才会发现任何配置错误,这可能是应用程序已运行数小时甚至数天之后。
结论
在本文中,我们介绍了控制反转和依赖注入的概念,并在Spring框架中进行了示例。
最后
为了方便其他设备和平台的小伙伴观看往期文章,链接奉上:
公众号搜索Let<bean id="store" autowire="byType"> </bean>us<bean id="store" autowire="byType"> </bean>Coding
,
知乎
,
开源中国
,
CSDN
,
思否
,
掘金
,
InfoQ
,
简书
,
博客园
,
慕课
,
51CTO
,
helloworld
,
腾讯开发者社区
,
阿里开发者社区
看完如果觉得有帮助,欢迎
点赞、收藏
和
关注
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4