Spring的核心机制:依赖注入

 

依赖注入的概念

当一个对象要调用另一个对象时,一般是new一个被调用的对象,示例:

class  A{

  private B b=new B();

  public  void  test(){

    b.say();

  }

}

A类的对象依赖于B类对象,如果没有B类对象,A类对象就不能正常工作,称A依赖于B。

以上方式会增加类A与类B的耦合性,不利于项目后期的升级(扩展)、维护。

 

在Spring中,B类的实例(被调用者),不再由A类(调用者)创建,而是由Spring容器创建,创建好以后,由Spring容器将B类的实例注入A类对象中,称为依赖注入(Dependency Injection,DI)。

原本是由A类主动创建B类对象(A类控制B类的创建),现在是Spring容器创建B类对象,注入A类对象中,A类被动接受Spring容器创建的B类实例,B类对象创建的控制权发生了反转,所以又叫做控制反转(Inversion of Control,IoC)。

 

依赖注入是一种优秀的解耦方式,由Spring容器负责控制类(Bean)之间的关系,降低了类之间的耦合。

因为Spring容器负责依赖注入(IoC),所以Spring容器也被称为Spring IoC容器。

 

依赖注入有2种实现方式:

  • 设值注入
  • 构造注入

 

 

 

 

设值注入

通过主调类的setter()方法注入被调类的实例。一个参数即一个依赖对象。

 

1、分别写2个接口

1 public interface Student {
2     public String getName();
3 }
1 public interface Teacher {
2     public void say();
3 }

 

 

2、分别写2个实现类

 1 public class BadStudent implements Student {
 2     private String name;
 3 
 4     public BadStudent(String name){
 5         this.name=name;
 6     }
 7 
 8     @Override
 9     public String getName(){
10         return name;
11     }
12 }
 1 public class MathTeacher implements Teacher{
 2     private Student student;
 3 
 4     //主调者的setter()方法,接受被调者实例
 5     public void setStudent(Student student){
 6         this.student=student;
 7     }
 8 
 9     @Override
10     public void say() {
11         System.out.println(student.getName()+",叫家长来一下。");
12     }
13 }

 类与接口耦合。

 

 

3、在applicationContext.xml文件中配置Bean

1 <!-- 初始化BadStudent类的实例lisi-->
2     <bean name="lisi" class="beans.BadStudent">
3         <constructor-arg value="李四" />  <!--向BadStudent的构造函数传递”李四“-->
4     </bean>
5 
6     <!--配置依赖-->
7     <bean name="mathTeacher" class="beans.MathTeacher">
8         <property name="student" ref="lisi" />  <!--name指定setter方法的形参,ref或者value指定实参:某个Bean的name-->
9     </bean>

 

 <constructor-arg>元素向该Bean的构造函数传递实参,一个<constructor-arg>传递一个实参,一个<bean>可配置多个<constructor-arg>,根据传递的实参个数来调用相应的构造函数。constructor-arg即构造器参数。

实参值通过value或ref属性来指定。value指定的是Java基础类型的参数,ref即reference(引用),指定依赖的其它Bean。

可通过属性index指定该value是第几个参数,默认从0自动递增。

 

 

<property>属性指定setter方法的实参。一个<property>指定一个参数,一个<bean>可带有多个<property>子元素。

name属性指定setter方法中的某个形参,实参由value或ref指定。

如果实参是某个Bean的实例,用ref指定,值是该Bean的name属性值。

如果实参是Java的基础类型(整型、浮点型、String等),用value指定(放在引号中),Spring容器会自动根据name的指定形参的类型,将实参转换为相应的类型进行赋值。

 

 

4、写一个测试类

1 public class Test {
2     public static void main(String[] args) {
3         ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
4         MathTeacher mathTeacher=applicationContext.getBean("mathTeacher",MathTeacher.class);
5         mathTeacher.say();
6     }
7 }

 看到控制台已经打印出了“李四,叫家长来一下。”。

 

 

 

 

 

构造注入

通过构造函数注入。

1、上面的代码,将MathTeacher类修改如下

 1 public class MathTeacher implements Teacher{
 2     private Student student;
 3 
 4     //主调者的构造方法 5 public MathTeacher(Student student){ 6 this.student=student; 7 }  8 
 9     @Override
10     public void say() {
11         System.out.println(student.getName()+",叫家长来一下。");
12     }
13 }

不使用setter方法注入依赖的对象,而是使用构造函数注入依赖的对象。

 

2、修改Spring容器的配置如下

1  <!-- 初始化BadStudent类的实例lisi-->
2     <bean name="lisi" class="beans.BadStudent">
3         <constructor-arg value="李四" />
4     </bean>
5 
6 <!--配置依赖--> 7 <bean name="mathTeacher" class="beans.MathTeacher"> 8 <constructor-arg name="student" ref="lisi" /> 9 </bean>

 

3、运行,看到控制台打印出“李四,叫家长来一下。”。

 

 

 

说明

  • value是注入Java的基础类型,ref是注入依赖的Bean。当然也可以用<value>、<ref>子元素的形式配置。

 

点赞