Spring IoC之DI(依赖注入)
一、阐述
DI: Dependency(依赖) Injection(注入)
官方解释
个人理解:
依赖:Bean依赖Spring IoC容器来控制类的创建和时间,以及Bean的生命周期由IoC容器管理,降低类与类之间的依赖,转而依赖IoC容器
注入:将所需的类、属性、各种资源…注入到目标类中
好处:Bean之间的依赖交给Ioc容器,降低Bean间的耦合。不用在依赖类中new对象,当被依赖类发生变化时只需要更改Bean的配置信息即可
二、DI注入方式
1、基于构造函数的依赖注入
A类构造方法中的构造参数依赖B类
SimpleMovieLister.java
package com.hgl.day02;
public class SimpleMovieLister {
private MovieFinder movieFinder;
private MovieDownloader movieDownloader;
public SimpleMovieLister(MovieFinder movieFinder, MovieDownloader movieDownloader){
System.out.println("Injection movieFinder、movieDownloader");
this.movieFinder = movieFinder;
this.movieDownloader = movieDownloader;
}
public void startWork(){
movieFinder.starFinder();
movieDownloader.startWork();
}
}
MovieFinder.java
package com.hgl.day02;
public class MovieFinder {
public MovieFinder(){
System.out.println("movieFinder's constructor");
}
public void starFinder(){
System.out.println("movieFinder has started");
}
}
MovieDownloader.java
package com.hgl.day02;
public class MovieDownloader {
public MovieDownloader(){
System.out.println("movieDownload's constructor");
}
public void startWork(){
System.out.println("movieDownloader has started");
}
}
xml配置
<bean id="simpleMovieLister" class="com.hgl.day02.SimpleMovieLister">
<constructor-arg ref="movieFinder"/>
<constructor-arg ref="movieDownload"/>
</bean>
<bean id="movieFinder" class="com.hgl.day02.MovieFinder"/>
<bean id="movieDownload" class="com.hgl.day02.MovieDownloader"/>
- 当构造参数有多个对象时,xml配置文件中当
constructor-arg
标签要按照构造参数当顺序进行注入 - 当注入当为基本数据类型时,可以通过以下方式区别对应的构造参数
使用type属性对参数对类型进行区分
<constructor-arg type="int" value="2001"/>
<constructor-arg type="java.lang.String" value="Zara"/>
使用index索引对应参数对索引,索引从0开始
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
使用name对应参数的名字
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
参照Spring5.2.7官方文档https://docs.spring.io/spring/docs/5.2.7.RELEASE/spring-framework-reference/core.html#beans-constructor-injection
2、基于setter的依赖注入
通过设置私有属性,setter方法和getter方法来设值和获取属性
SetterMovieLister.java
package com.hgl.day02;
public class SetterMovieLister {
private MovieFinder movieFinder;
private MovieDownloader movieDownloader;
private String message;
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
public void setMovieDownloader(MovieDownloader movieDownloader) {
this.movieDownloader = movieDownloader;
}
public void setMessage(String message) {
this.message = message;
}
public MovieFinder getMovieFinder() {
return movieFinder;
}
public MovieDownloader getMovieDownloader() {
return movieDownloader;
}
public void getMessage() {
System.out.println("message : " + message);
movieFinder.starFinder();
movieDownloader.startWork();
}
}
MovieFinder.java和MovieDownloader.java为构造注入使用的例子
<bean id="setterMovieLister" class="com.hgl.day02.SetterMovieLister">
<property name="movieFinder" ref="movieFinder"/>
<property name="movieDownloader" ref="movieDownload"/>
<property name="message" value="Setter Injection"/>
</bean>
xml配置可使用p 命名空间进行简化xml的内容,可改写成
但是要在beans根目录下,添加命名空间xmlns:p="http://www.springframework.org/schema/
p"
<bean id="setterMovieLister" class="com.hgl.day02.SetterMovieLister"
p:movieFinder="movieFinder"
p:movieDownloader="movieDownloder"
p:message="Setter Injection"
/>
官网的另一种方式使用工具包中的Propreties(java.util.Properties)
<bean id="mappings"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<!-- typed as a java.util.Properties -->
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
三、内部Bean(Inner Bean)
<bean id="movieFinder" class="com.hgl.day02.MovieFinder"/>
<bean id="movieDownload" class="com.hgl.day02.MovieDownloader"/>
<bean id="setterMovieLister" class="com.hgl.day02.SetterMovieLister">
<property name="movieFinder" ref="movieFinder"/>
<property name="movieDownloader" ref="movieDownload"/>
<property name="message" value="Setter Injection"/>
</bean>
以上bean配置可改写成:
<bean id="setterMovieLister" class="com.hgl.day02.SetterMovieLister">
<property name="movieFinder">
<bean id="movieFinder" class="com.hgl.day02.MovieFinder"/>
</property>
<property name="movieDownloader">
<bean id="setterMovieLister" class="com.hgl.day02.SetterMovieLister">
</property>
</bean>
idref – 该元素只是将容器中另一个 bean 的(字符串值 - 而不是引用)传递给 或 元素的一种防错方法。
<bean id="movieFinder" class="com.hgl.day02.MovieFinder"/>
<bean id="movieDownload" class="com.hgl.day02.MovieDownloader"/>
<bean id="setterMovieLister" class="com.hgl.day02.SetterMovieLister">
<property name="movieFinder">
<idref bean="movieFinder">
</property>
<property name="movieDownloader">
<idref bean="movieDownload">
</property>
</bean>
四、Spring注入集合
List、Set、Map、Properties
InjectionCollection.java
package com.hgl.day02;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class InjectionCollection {
Properties addressProps;
List addressList;
Map addressMap;
Set addressSet;
public void setAddressProps(Properties addressProps) {
this.addressProps = addressProps;
}
public void setAddressList(List addressList) {
this.addressList = addressList;
}
public void setAddressMap(Map addressMap) {
this.addressMap = addressMap;
}
public void setAddressSet(Set addressSet) {
this.addressSet = addressSet;
}
public Properties getAddressProps() {
System.out.println("Property Elements :" + addressProps);
return addressProps;
}
public List getAddressList() {
System.out.println("List Elements :" + addressList);
return addressList;
}
public Map getAddressMap() {
System.out.println("Map Elements :" + addressMap);
return addressMap;
}
public Set getAddressSet() {
System.out.println("Set Elements :" + addressSet);
return addressSet;
}
}
package com.hgl.day02;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class CollectionInjectionMainApp {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("BeansConfigDay02.xml");
InjectionCollection collection = (InjectionCollection) context.getBean("injectionCollection");
collection.getAddressProps();
collection.getAddressList();
collection.getAddressMap();
collection.getAddressSet();
}
}
<bean id="address1" class="com.hgl.day02.Address1"/>
<bean id="address2" class="com.hgl.day02.Address2"/>
<bean id="injectionCollection" class="com.hgl.day02.InjectionCollection">
<property name="addressProps">
<props>
<prop key="address0">广州</prop>
<prop key="address1">深圳</prop>
<prop key="address2">韶关</prop>
</props>
</property>
<property name="addressList">
<list>
<value>广州</value>
<ref bean="address1"/>
<ref bean="address2"/>
</list>
</property>
<property name="addressMap">
<map>
<entry key="address0" value="广州"/>
<entry key="address1" value-ref="address1"/>
<entry key="address2" value-ref="address2"/>
</map>
</property>
<property name="addressSet">
<set>
<value>广州</value>
<ref bean="address1"/>
<ref bean="address2"/>
</set>
</property>
</bean>
ps:集合之间也可以Spring定义继承