1 使用XML文件实现依赖注入
1.1 setter实现依赖注入
通过<bean>标签下的<property>标签进行注入。
- 若要注入简单值,则通过<property>的value属性
- 若要注入引用其他的bean的id或name,则使用<property>的ref属性
- 若要注入集合,则<property>下有对应<set>、<list>、<map>、<props>。若注入简单值,直接使用<value>;如果集合中是引用的其他bean,使用<ref>
- 对于map存储的是键值对,应使用<enter>标签。如果键是简单值,则使用key属性指定其值,如果是引用的其他bean,使用key-ref属性指定bean的id或name;如果值是简单值,则使用value属性指定其值,如果是引用的其他bean,使用value-ref属性指定bean的id或name
-
注入Properties集合,可以使用<props>或<value>
1.1.1 注入简单值(基本数据类型或字符串)
<bean id="person" class="com.qdu.bean.Girl">
<property name="name" value="小明" />
</bean>
1.1.2 注入引用的其他bean(引用类型)
<bean id="person" class="com.qdu.bean.Girl">
<property name="axe" ref="fuzi" />
<property name="pet" ref="chongwu" />
</bean>
1.1.3 注入集合(Set、List、Map、Properties)
<bean id="company" class="com.qdu.bean.Company">
<property name="companyName" value="二维数组有限公司" />
<property name="companyAddress" ref="addr3" />
<property name="branchNames">
<!-- set标记用于注入set集合的值 -->
<set>
<!-- 如果集合中是引用的其他bean,使用ref标记,通过bean指定引用的bean的id或name -->
<!-- <ref bean="id或name" /> -->
<!-- 如果集合中是简单值,使用value指定值即可 -->
<value>山东分公司</value>
<value>山西分公司</value>
<value>广东分公司</value>
<value>广西分公司</value>
<value>海南分公司</value>
</set>
</property>
<property name="partnerNames">
<list>
<!-- 如果集合中是引用的其他bean,使用ref标记,通过bean指定引用的bean的id或name -->
<!-- <ref bean="id或name" /> -->
<!-- 如果集合中是简单值,使用value指定值即可 -->
<value>Oracle</value>
<value>Microsoft</value>
<value>IBM</value>
<value>Google</value>
</list>
</property>
<property name="employeeList">
<list>
<!-- 如果集合中是引用的其他bean,使用ref标记,通过bean指定引用的bean的id或name -->
<ref bean="emp1" />
<ref bean="emp2" />
</list>
</property>
<property name="branchManagers">
<map>
<!-- entry用于指定一项数据的注入 -->
<!-- 如果键是简单值,则使用key指定其值,如果是引用的其他bean,使用key-ref指定bean的id或name -->
<!-- 如果值是简单值,则使用value指定其值,如果是引用的其他bean,使用value-ref指定bean的id或name -->
<entry key="山东分公司" value-ref="emp1" />
<entry key="山西分公司" value-ref="emp2" />
</map>
</property>
<!-- 注入Properties集合,可以使用props标记或value标记 -->
<property name="extraInfo1">
<props>
<prop key="registeredCapital">1000000</prop>
<prop key="legalPerson">小胖</prop>
<prop key="type">Joint venture</prop>
</props>
</property>
<property name="extraInfo2">
<value>
registeredCapital=2000000
legalPerson=Allen
type=Joint venture
</value>
</property>
</bean>
注意:在相应类中,必须要给对应的属性生成setter访问器,因为要使用setXXX()方法来注入/设置需要的值
诸如在Girl类中:
public class Girl implements Person {
private String name;
private Axe axe;
private Pet pet;
public Girl() {
}
public Girl(String name, Axe axe, Pet pet) {
this.name = name;
this.axe = axe;
this.pet = pet;
}
public void setName(String name) {
this.name = name;
}
public void setAxe(Axe axe) {
this.axe = axe;
}
public void setPet(Pet pet) {
this.pet = pet;
}
@Override
public void kanChai() {
System.out.println("Girl砍柴,力气更大!!!");
axe.cut();
pet.showSkill();
}
}
1.2 构造函数实现依赖注入
通过<bean>标签下的<constructor-arg>标签实现注入。注意,如果使用setter注入,<constructor-arg>的name属性是类中的属性名;但这里使用构造函数注入,<constructor-arg>的name属性指定的是构造函数的参数的名称。也可不写参数名称,但是必须保证参数的顺序是对的。可以使用参数索引index属性(0表示第一个参数),这样参数顺序随便写。但是如果不写参数名称,也不写参数索引,则参数顺序必须正确。
- 注入简单值,通过value属性指定要注入的值即可
- 如果注入引用的其他bean,使用ref属性指定要注入的bean的id或name
- 若要注入集合,则<constructor-arg>下有对应<set>、<list>、<map>、<props>。若注入简单值,直接使用<value>;如果集合中是引用的其他bean,使用<ref>
- 对于map存储的是键值对,应使用<enter>标签。如果键是简单值,则使用key属性指定其值,如果是引用的其他bean,使用key-ref属性指定bean的id或name;如果值是简单值,则使用value属性指定其值,如果是引用的其他bean,使用value-ref属性指定bean的id或name
-
注入Properties集合,可以使用<props>或<value>
1.2.1 注入简单值(基本数据类型或字符串)
<bean id="addr1" class="com.qdu.bean.Address">
<constructor-arg name="pro" value="山东" />
<constructor-arg name="city" value="青岛" />
</bean>
使用构造函数注入,也可不写参数名称,但是必须保证参数的顺序是对的。
可以使用参数索引(0表示第一个参数),这样参数顺序随便写。
但是如果不写参数名称,也不写参数索引,则参数顺序必须正确。
<bean id="addr2" class="com.qdu.bean.Address">
<constructor-arg index="0" value="山东" />
<constructor-arg index="1" value="济南" />
<constructor-arg index="2" value="泉城广场" />
</bean>
1.2.2 注入引用的其他bean(引用类型)
<bean id="emp1" class="com.qdu.bean.Employee">
<constructor-arg name="empId" value="E001" />
<constructor-arg name="empName" value="小强" />
<constructor-arg name="empSalary" value="50000" />
<!-- 如果注入引用的其他bean,使用ref属性指定要注入的bean的id或name -->
<constructor-arg name="address" ref="addr1" />
</bean>
1.2.3 注入集合(Set、List、Map、Properties)
<bean id="company" class="com.qdu.bean.Company">
<constructor-arg name="companyName" value="二维数组有限公司" />
<constructor-arg name="companyAddress" ref="addr3" />
<constructor-arg name="branchNames">
<set>
<!-- 如果集合中是简单值,使用value指定值即可 -->
<value>山东分公司</value>
<value>山西分公司</value>
<value>广东分公司</value>
<value>广西分公司</value>
<value>海南分公司</value>
</set>
</constructor-arg>
<constructor-arg name="partnerNames">
<list>
<value>Oracle</value>
<value>Microsoft</value>
<value>IBM</value>
<value>Google</value>
</list>
</constructor-arg>
<constructor-arg name="employeeList">
<list>
<!-- 如果集合中是引用的其他bean,使用ref标记,通过bean指定引用的bean的id或name -->
<ref bean="emp1" />
<ref bean="emp2" />
</list>
</constructor-arg>
<constructor-arg name="branchManagers">
<map>
<!-- entry用于指定一项数据的注入 -->
<!-- 如果键是简单值,则使用key指定其值,如果是引用的其他bean,使用key-ref指定bean的id或name -->
<!-- 如果值是简单值,则使用value指定其值,如果是引用的其他bean,使用value-ref指定bean的id或name -->
<entry key="山东分公司" value-ref="emp1" />
<entry key="山西分公司" value-ref="emp2" />
</map>
</constructor-arg>
<!-- 注入Properties集合,可以使用props标记或value标记 -->
<constructor-arg name="extraInfo1">
<props>
<prop key="registeredCapital">1000000</prop>
<prop key="legalPerson">小胖</prop>
<prop key="type">Joint venture</prop>
</props>
</constructor-arg>
<constructor-arg name="extraInfo2">
<value>
registeredCapital=2000000
legalPerson=Allen
type=Joint venture
</value>
</constructor-arg>
</bean>
注意:在相应类中,必须要生成构造函数:
public class Address {
private String province; //省
private String city; //市
private String detailedAddress; //详细地址
@Override
public String toString() {
return "地址::" + province + "省" + city + "市" + detailedAddress;
}
public Address() {
super();
}
public Address(String pro, String city, String detailedAddress) {
System.out.println("调用了带3个参数的构造函数实现依赖注入!!!");
this.province = pro;
this.city = city;
this.detailedAddress = detailedAddress;
}
public void setProvince(String province) {
System.out.println("setProvince()方法被调用........");
this.province = province;
}
public void setCity(String city) {
this.city = city;
}
public void setDetailedAddress(String detailedAddress) {
this.detailedAddress = detailedAddress;
}
}
1.3 自动装配
在应用程序对象之间创建和管理关联的过程叫做装配,这构成了DI的核心。以上两种方法为显示装配(显式声明Bean之间的依赖),自动装配(autowiring)不显式声明Bean之间的依赖,让容器选择合适的依赖项注入。
1.3.1 byName
byName是按照名称自动装配,意思是要注入的属性的属性名和要注入的bean的id或name(别名)相同,即可实现按照名称自动装配。
当一个bean带有autowire byName的属性时:
- 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
- 去spring容器中寻找是否有此字符串名称id的对象。
- 如果有,就取出注入;如果没有,就报空指针异常
<bean id="person" class="com.qdu.bean.Boy" autowire="byName">
<property name="name" value="小兰" />
</bean>
1.3.2 byType
byType是按照类型自动装配。如果要注入的属性的数据类型和容器中某个bean的类型匹配,则实现自动装配。
自动装配跟 id 无关,在配置bean 时不写 id 都不会报错。
但是 byType 的自动装配存在一个很严重的问题,因为不是通过唯一的 id 来匹配,而是通过类型来匹配,所以容器中不能存在多个相同类型的 bean,否则会抛出NoUniqueBeanDefinitionException异常。
<bean id="person" class="com.qdu.bean.Girl" autowire="byType">
<property name="name" value="小明" />
</bean>
1.3.3 constructor
constructor表示使用对应的构造函数实现自动装配,所以需要生成对应的构造函数
<bean id="person" class="com.qdu.bean.Girl" autowire="constructor">
<property name="name" value="小明" />
</bean>
public class Girl implements Person {
private String name;
private Axe axe;
private Pet pet;
@Override
public void kanChai() {
System.out.println("砍柴人:"+name);
System.out.println("Girl砍柴,力气更大!!!");
pet.showSkill();
axe.cut();
}
public Girl() {
super();
}
//如果使用构造函数实现自动装配,需要生成对应的构造函数
//使用constructor实现自动装配,只要构造函数的数据类型对了即可,参数名无所谓
public Girl(Axe a, Pet p) {
super();
System.out.println("带2个参数的构造函数~~~");
this.axe = a;
this.pet = p;
}
public void setName(String name) {
this.name = name;
}
public void setAxe(Axe axe) {
this.axe = axe;
}
public void setPet(Pet pet) {
this.pet = pet;
}
}
2 使用Java代码实现依赖注入
2.1 调用@Bean修饰的对应方法实现注入
使用Java代码进行注入,首先要先写一个Java代码的Spring配置类SpringConfig1.class
首先要注意,配置类需要用@Configuration注解修饰。而且由于我们使用的是java配置类,而不是xml配置文件,则需要使用ApplicationContext接口的AnnotationConfigApplicationContext实现类来创建容器。
ApplicationContext ctx
= new AnnotationConfigApplicationContext(SpringConfig.class);
使用@Bean修饰的方法注册一个bean成为spring管理的bean,方法返回的对象成为Spring管理的bean。于是, 可通过调用产生bean的方法来获取一个bean实现依赖注入。
@Configuration
public class SpringConfig1 {
@Bean
public Axe fuzi() {
return new SteelAxe();
}
@Bean
public Pet chongwu() {
return new Pig();
}
@Bean
public Person person() {
Girl girl=new Girl();
girl.setName("小花");
girl.setAxe(fuzi()); //调用fuzi()方法获取的是spring管理的SteelAxe对象
girl.setPet(chongwu()); //调用chongwu()方法获取的是spring管理的Pig对象
return girl;
}
}
2.2 通过方法参数获取要注入的bean
同上,首先要有一个Spring的配置类SpringConfig2.class。仍然使用@Bean修饰的方法注册一个bean成为spring管理的bean。
这一方法与2.1不同的是,这一种直接在方法上添加对应类型的参数,使用传入的参数设置属性实现依赖注入。参数的名称和顺序无所谓,只要参数类型对了即可。
@Bean
public Person person(Pet p,Axe a) {
Girl girl=new Girl();
girl.setName("小花");
girl.setAxe(a); //直接使用传入的参数进行注入即可
girl.setPet(p);
return girl;
}
3 使用注解实现依赖注入
使用注解,首先要在Spring的配置类中使用@ComponentScan开启包扫描,也别忘记@Configuration。使用注解的一个好处就是SpringConfig.class非常简单:
@Configuration
@ComponentScan("com.qdu.bean")
//@ComponentScan({"com.qdu.bean","com.qdu.service","com.qdu.dao"})
public class SpringConfig {
}
开启包扫描后,别忘记在每个类使用添加注解@Component,将一个类注册为spring管理的bean
在字段前使用@Autowired注解,则使用反射实现注入。@Autowired注解按照类型进行装配,如果存在多个匹配类型,会报错。@Autowired可用于构造函数前、setter方法前、其他任何用于注入的方法前或字段前。
@Component
public class Girl implements Person {
private String name;
@Autowired
private Axe axe;
@Autowired
private Pet pet;
public Girl() {
}
public Girl(String name, Axe axe, Pet pet) {
this.name = name;
this.axe = axe;
this.pet = pet;
}
public void setName(String name) {
this.name = name;
}
public void setAxe(Axe axe) {
this.axe = axe;
}
public void setPet(Pet pet) {
this.pet = pet;
}
@Override
public void kanChai() {
System.out.println("Girl砍柴,力气更大!!!");
axe.cut();
pet.showSkill();
}
}