参考什么是spring,它能够做什么? 参考w3cschool 参考Spring框架入门教程

Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系。

1 依赖注入

Spring依赖注入(Dependency Injection,DI)和控制反转含义相同,它们是从两个角度描述的同一个概念。使用依赖注入可以更轻松的管理和测试应用程序。

当某个Java实例需要另一个Java实例时,传统的方法是由调用者创建被调用者的实例(例如,使用new关键字获得被调用者实例),而使用Spring框架后,被调用者的实例不再由调用者创建,而是由Spring容器创建,这称为控制反转。

Spring容器在创建被调用者的实例时,会自动将调用者需要的对象实例注入给调用者,调用者通过Spring容器获得被调用者实例,这称为依赖注入

依赖注入主要有两种实现方式,分别是setter注入(又称设值注入)和构造函数注入。具体介绍如下。
(1)构造函数注入
指IoC容器使用构造函数注入被依赖的实例。
可以通过调用带参数的构造函数实现依赖注入,每个参数代表一个依赖。

(2)setter注入
指IoC容器使用setter方法注入被依赖的实例。通过调用无参构造器或无参static工厂方法实例化Bean后,调用该Bean的setter方法,即可实现基于setter的DI。

在Spring实例化Bean的过程中,首先会调用默认的构造方法实例化Bean对象,然后通过Java的反射机制调用setXxx()方法进行属性的注入。因此setter注入要求Bean的对应类必须满足以下两点要求。
必须提供一个默认的无参构造方法。
必须为需要注入的属性提供对应的setter方法。

使用setter注入时,在Spring配置文件中,
需要使用<bean>元素的子元素<property>为每个属性注入值。

而使用构造注入时,在配置文件中,
主要使用<constructor-arg>标签定义构造方法的参数,
使用其value属性(或子元素)设置该参数的值。

1.1 构造函数注入

使用<constructor-arg>标签实现构造函数注入。

在<constructor-arg>标签中,包含ref、value、type、index等属性。
value属性用于注入基本数据类型以及字符串类型的值;
ref属性用于注入已经定义好的Bean;
type属性用于根据参数类型进行注入;
index属性当构造函数有多个参数时,从0开始指定参数的位置。

1.1.1 文件Man.java

package net.biancheng;

public class Man {
    private String name;
    private int age;

    public Man() {
        System.out.println("在man的构造函数内");
    }

    public Man(String name, int age) {
        System.out.println("在man的有参构造函数内");
         = name;
        this.age = age;
    }

    public void show() {
        System.out.println("名称:" + name + "\n年龄:" + age);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
         = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

1.1.2 文件Person.java

package net.biancheng;

public class Person {
    private Man man;

    public Person(Man man) {
        System.out.println("在Person的构造函数内");
        this.man = man;
    }

    public void man() {
        man.show();
    }
}

1.1.3 文件Beans.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="man123" class="net.biancheng.Man">
        <constructor-arg value="lucy"/>
        <constructor-arg value="12"/>
    </bean>

    <bean id="person123" class="net.biancheng.Person">
        <constructor-arg ref="man123"/>
    </bean>

</beans>

1.1.4 文件MainApp.java

package net.biancheng;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        Person person = (Person) context.getBean("person123");
        person.man();

    }
}

输出如下所示

在man的有参构造函数内
在Person的构造函数内
名称:lucy
年龄:12

1.2 setter注入

使用<property>标签实现setter注入。

在<property>标签中,包含 name、ref、value 等属性。
name用于指定参数名称;
value属性用于注入基本数据类型以及字符串类型的值;
ref属性用于注入已经定义好的Bean。

1.2.1 文件Man.java【不变】

package net.biancheng;

public class Man {
    private String name;
    private int age;

    public Man() {
        System.out.println("在man的构造函数内");
    }

    public Man(String name, int age) {
        System.out.println("在man的有参构造函数内");
         = name;
        this.age = age;
    }

    public void show() {
        System.out.println("名称:" + name + "\n年龄:" + age);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
         = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

1.2.2 文件Person.java【改变】

package net.biancheng;

public class Person {
    private Man man;

    public Man getMan() {
        return man;
    }

    public void setMan(Man man) {
        System.out.println("在Person的setMan函数内");
        this.man = man;
    }

    public void man() {
        man.show();
    }
}

1.2.3 文件Beans.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="person123" class="net.biancheng.Person">
        <property name="man" ref="man123" />
    </bean>

    <bean id="man123" class="net.biancheng.Man">
        <property name="name" value="lily" />
        <property name="age" value="18" />
    </bean>

</beans>

1.2.4 文件MainApp.java【不变】

package net.biancheng;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        Person person = (Person) context.getBean("person123");
        person.man();

    }
}

输出如下:

在man的构造函数内
在Person的setMan函数内
名称:lily
年龄:18

每个基于应用程序的java都有几个对象,由这些对象一起工作来呈现出终端用户所看到的工作的应用程序。当编写一个复杂的Java应用程序时,应用程序类应该尽可能独立于其他Java类来增加这些类重用的可能性,并且在做单元测试时,测试独立于其他类的独立性。依赖注入(或有时称为布线)有助于把这些类粘合在一起,同时保持他们独立。

假设你有一个包含文本编辑器组件的应用程序,并且你想要提供拼写检查。
(1)标准代码如下

public class TextEditor {
   private SpellChecker spellChecker;  
   // 构造函数
   public TextEditor() {
      spellChecker = new SpellChecker();
   }
}

在这里我们所做的就是创建一个TextEditor和SpellChecker之间的依赖关系。
(2)在控制反转IoC的场景中如下

public class TextEditor {
   private SpellChecker spellChecker;
   // 构造函数
   public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }
}