同学们看到题目,就有疑惑了,上节课我们不是讲过属性的注入了吗?这节课的注入方式又是什么意思?
上节课呢,我们对于不同类型的注入深入探讨了,针对的是不同类型。这节课我们主要来聊一聊有哪些方法可以注入。举个例子,今天晚上你们吃五花肉、羊肉还是牛肉,这是我们上节课探讨的问题,这节课我们探讨的是针对某种肉,你是炸着吃、蒸着吃、还是炒着吃。
1、题目中的注入方式为什么还要加上“依赖”两个字?
我们第一节课就讲过了注入依赖,注入依赖我们提到是bean和bean之间的关系。我们上节课都是探讨的简单类型和集合以及数组注入bean,并没有提到bean注入bean。
准确的说,我们上节课只是学习了注入,但称不上依赖的注入,所以我们这节课主要是从依赖注入来入手。
2、那依赖注入有哪三种方式?
依赖注入有三种方式,分别是:属性注入、构造方法注入、工厂方式注入。
3、属性注入是怎么实现的?
属性注入,我们没有提过这个概念,但是其实上节课我们就已经接触了,并一直在用。我们先看下面的代码。
pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
Pet.java
package com.spring.test;
public class Pet {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "name==>"+getName()+"\nsex==>"+getSex()+"\nage==>"+getAge();
}
}
People.java
package com.spring.test;
public class People {
private String name;
private Pet pet;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean id="people" class="com.spring.test.People">
<property name="pet" ref="pet"></property>
</bean>
<bean id="pet" class="com.spring.test.Pet">
<property name="name" value="旺财"></property>
<property name="sex" value="男"></property>
<property name="age" value="3"></property>
</bean>
</beans>
SpringTest.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.test.People;
import com.spring.test.Pet;
public class SpringTest{
public static void main(String[] args) {
ApplicationContext content = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = (People) content.getBean("people");
Pet pet = people.getPet();
System.out.println(pet.toString());
}
}
我们发现,在bean的配置里面,我们使用ref属性引入了另一个bean,其实我们也可以这么写:
<bean id="people" class="com.spring.test.People">
<property name="name" value="wangdonghui"></property>
<property name="pet">
<bean id="pet" class="com.spring.test.Pet">
<property name="name" value="旺财"></property>
<property name="sex" value="男"></property>
<property name="age" value="3"></property>
</bean>
</property>
</bean>
下面这种写法和上面的写法效果是一样的,我们称下面内层的bean叫“内部bean”,这样写比较安全,防止其他bean错误的引用这个内部bean。但是这个内部bean如果在其他bean中也需要引用,那这么写显得不十分聪明了。
我们继续说回我们属性注入,观察代码,在People类或者Pet类中,我们实际是通过属性的setter方法进行注入的,如果想验证的话可以删除掉setter方法测试一下。由于通过属性setter方法将一个bean注入到另个bean的形式,我们称其为“属性注入”。
4、构造方法注入是怎么实现的?
顾名思义,构造方法注入就是通过bean的构造方法进行注入另个bean,直接上代码:
People.java
package com.spring.test;
public class People {
private String name;
private Pet pet;
public People(String name,Pet pet) {
// TODO Auto-generated constructor stub
this.name = name;
this.pet = pet;
}
public Pet getPet() {
return pet;
}
public void setName(String name) {
this.name = name;
}
}
pet.java
package com.spring.test;
public class Pet {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "name==>"+getName()+"\nsex==>"+getSex()+"\nage==>"+getAge();
}
}
applicationContext.xml
<bean id="people" class="com.spring.test.People">
<constructor-arg name="name" value="wangdonghui"></constructor-arg>
<constructor-arg name="pet" ref="pet"></constructor-arg>
</bean>
<bean id="pet" class="com.spring.test.Pet">
<property name="name" value="旺财"></property>
<property name="sex" value="男"></property>
<property name="age" value="3"></property>
</bean>
SrpingTest.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.test.People;
import com.spring.test.Pet;
public class SpringTest{
public static void main(String[] args) {
ApplicationContext content = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = (People) content.getBean("people");
Pet pet = people.getPet();
System.out.println(pet.toString());
}
}
构造方法注入的bean也可以写成内部bean的形式。
我们刚才在people的bean中使用constructor-arg标签,这个标签里的name,对应了构造方法的参数名,ref引入了被注入的bean。除了对应参数名,我们也可以使用对应参数位置的方式注入,配置如下:
<bean id="people" class="com.spring.test.People">
<constructor-arg index="0" value="wangdonghui"></constructor-arg>
<constructor-arg index="1" ref="pet"></constructor-arg>
</bean>
<bean id="pet" class="com.spring.test.Pet">
<property name="name" value="旺财"></property>
<property name="sex" value="男"></property>
<property name="age" value="3"></property>
</bean>
constructor-arg标签中的index属性,指明了参数的位置,从0开始,分别代表第一个参数、第二个参数…
5、工厂方式注入是怎么实现的?
工厂方式注入有两种,一种是静态工厂注入,一种是实例工厂注入。我们先来研究一下静态工厂注入,代码如下:
Pet.java
package com.spring.test;
public class Pet {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "name==>"+getName()+"\nsex==>"+getSex()+"\nage==>"+getAge();
}
}
PetFactory.java
package com.spring.test;
public class PetFactory {
public static Pet createPet(String name,String sex,int age) {
Pet pet = new Pet();
pet.setName(name);
pet.setSex(sex);
pet.setAge(age);
return pet;
}
}
People.java
package com.spring.test;
public class People {
private String name;
private Pet pet;
public People(String name,Pet pet) {
// TODO Auto-generated constructor stub
this.name = name;
this.pet = pet;
}
public Pet getPet() {
return pet;
}
public void setName(String name) {
this.name = name;
}
}
applicationContext.xml
<bean id="people" class="com.spring.test.People">
<constructor-arg index="0" value="wangdonghui"></constructor-arg>
<constructor-arg index="1" ref="pet"></constructor-arg>
</bean>
<bean id="pet" class="com.spring.test.PetFactory" factory-method="createPet">
<constructor-arg name="name" value="旺财"></constructor-arg>
<constructor-arg name="sex" value="男"></constructor-arg>
<constructor-arg name="age" value="3"></constructor-arg>
</bean>
SpringTest.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.test.People;
import com.spring.test.Pet;
public class SpringTest{
public static void main(String[] args) {
ApplicationContext content = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = (People) content.getBean("people");
Pet pet = people.getPet();
System.out.println(pet.toString());
}
}
这种方式称为静态工厂注入,在工厂类中创建pet的方法是静态的,在工厂类被实例前,pet就已经存在了。我们再来看看非静态的工厂方式注入,很多人也叫这种方式为实例工厂注入。
实例工厂方式注入相对静态工厂方式注入,首先不需要把PetFactory的createPet方法静态化,也就是不需要static关键字修饰,其次是bean的配置发生了变化,变化后如下:
<bean id="people" class="com.spring.test.People">
<constructor-arg index="0" value="wangdonghui"></constructor-arg>
<constructor-arg index="1" ref="pet"></constructor-arg>
</bean>
<bean id="petFactory" class="com.spring.test.PetFactory"></bean>
<bean id="pet" class="com.spring.test.Pet" factory-bean="petFactory" factory-method="createPet">
<constructor-arg name="name" value="旺财"></constructor-arg>
<constructor-arg name="sex" value="男"></constructor-arg>
<constructor-arg name="age" value="3"></constructor-arg>
</bean>
实例工厂方式注入,首先要把工厂类实例出来,然后pet类才会存在实例。
无论是静态注入还是非静态注入,在工厂类中的方法中,参数都是通过constructor-arg标签传参的,标签的用法和构造方法传参相同,不再累述。