Spring框架学习笔记1

Spring框架IOC和DI,以及XML注入

引用了博客:
https://blog.csdn.net/qq_40414738/article/details/83552219
https://blog.csdn.net/luoyepiaoxue2014/article/details/72426666 (浅谈对Spring IOC以及DI的理解)

一、IOC和DI的基本概念

Spring框架的两大特征: IOC(Inverse of Control)和DI (Dependency Injection)

我们首先要明确一点,IOC和DI不是一种技术,而是一种程序设计理念或者思路。他们俩本质是一个东西,只是一种东西的两种叫法,或者说是一个东西从两方面来描述。
控制反转和依赖注入从表面上来看,就是一种不同形式的对象创建方式。一般来说,我们如果要创建一个对象,我们是使用如下图所示的形式来创建的:

 类名 变量名 = new 类名();

然而,所谓的IOC就是说,我们换一种形式来创建,例如:

类名 对象名 = (类名)context.getBean("XML配置文件中的id名");
那么为什么这玩意要叫做IOC(控制反转)还有依赖注入呢?

原本在程序中手动创建对象(new出来的一个对象)和维护对象之间的相互依赖关系的控制权,交由 Spring 框架来管理, 需要时由容器完成对象的注入即可.换句话说,IOC 反转了依赖关系的满足方式,由之前的自己创建依赖对象,变为由工厂推送。(变主动为被动,即反转)它解决了具有依赖关系的组件之间的强耦合,使得项目形态更加稳健.比如:Class A 中用到了 Class B 的对象 b,一般情况下,需要在 A 的代码中显式的 new 一个 B 的对象。在使用了 IOC 之后呢?A 的代码只需要定义一个私有的 B 对象,不需要直接 new 来获得这个对象,而是通过相关的容器控制程序来将 B 对象在外部new 出来并注入到 A 类里的引用中。

如果上面的解释还是难以理解,那么再通俗一点讲:

Spring框架会给你提供一个容器,这个容器就是对象的外壳,再有需要的时候,我们把具体需要创建的对象的内容(也就是具体是什么对象)放到到这个容器里面,然后再推送给程序员使用。

如果实在不理解,那就再通俗一点就是:

Spring框架帮你建立了一个对象,但是具体是什么对象,这个对象里面有什么属性,都不确定,等到需要用的时候再说,等到需要用的时候,我们把具体的是什么对象告诉Spring,然后由Spring来创建这个对象,创建完成之后给到程序员使用。也就是说,整个创建对象的具体过程已经全部交给Spring来做了,我们程序员只需要告诉Spring,“来,Spring你来创建一个对象”, 就可以了,具体的创建操作,步骤,我们不需要考虑。

那么什么是依赖注入呢?

依赖注入说白点就是:在Spring生成了对象之后,我们的程序,依赖于,spring给我们提供的对象。所以这个时候Spring生成好了的对象就要“注入”到我们的程序中。这就是所谓的依赖注入。

二、XML配置文件注入

依赖注入主要的两种方式: XML配置文件注入 和 注解注入(以后会讲)
XML配置文件注入也有两种方式:setter注入 和 Constructor注入
    <!--Setter注入-->
    <bean id="textEditor2" class="com.example.demospringbean.TextEditor"  >
        <property name="spellChecker" ref="spellChecker"/>
    </bean>
    <!--构造函数注入-->
    <bean id="textEditor1" class="com.example.demospringbean.TextEditor">
        <constructor-arg ref="spellChecker"/>
    </bean>

具体操作:
主程序:

package com.example.demospringbean;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp2 {
    public static void main(String[] args) {
        AbstractApplicationContext  context =
                new ClassPathXmlApplicationContext("Beans.xml");
        System.out.println("构造器注入");
        TextEditor te1 = (TextEditor) context.getBean("textEditor1"); 
        te1.spellCheck();
        System.out.println("setter注入");
        TextEditor te2 = (TextEditor) context.getBean("textEditor2");
        te2.spellCheck();
        System.out.println("嵌套bean");
        TextEditor te = (TextEditor) context.getBean("textEditor");
        te.spellCheck();
        System.out.println("注入集合");
        JavaCollection jc=(JavaCollection)context.getBean("javaCollection");
        jc.getAddressList();
        jc.getAddressSet();
        jc.getAddressMap();
        jc.getAddressProp();
    }
}

对应的XML配置文件:

```javascript
<?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.xsd">
	//创建对象的时候直接给里面的属性赋值
    <bean id="hello" class="com.example.demospringbean.HelloWorld" scope="prototype" init-method="init" destroy-method="destroy">
        <property name="message" value="asd" />
    </bean>
	//创建对象的时候直接给里面的属性赋值
    <bean name="helloChina" class="com.example.demospringbean.HelloChina" parent="hello">
        <property name="message2" value="Hello China"/>
    </bean>

    //<!--构造函数注入-->
    <bean id="textEditor1" class="com.example.demospringbean.TextEditor">
        <constructor-arg ref="spellChecker"/>
    </bean>

   // <!--Setter注入-->
    <bean id="textEditor2" class="com.example.demospringbean.TextEditor"  >
        <property name="spellChecker" ref="spellChecker"/>
    </bean>

    <bean id="spellChecker" class="com.example.demospringbean.SpellChecker">
    </bean>

   // <!--嵌套bean Setter注入-->
    <bean id="textEditor" class="com.example.demospringbean.TextEditor">
        <property name="spellChecker">
            <bean class="com.example.demospringbean.SpellChecker"/>
        </property>
    </bean>

    //<!-- Definition for javaCollection -->
    <bean id="javaCollection" class="com.example.demospringbean.JavaCollection">

        //<!-- results in a setAddressList(java.util.List) call -->
        <property name="addressList">
            <list>
                <value>INDIA</value>
                <value>Pakistan</value>
                <value>USA</value>
                <value>USA</value>
            </list>
        </property>

       // <!-- results in a setAddressSet(java.util.Set) call -->
        <property name="addressSet">
            <set>
                <value>INDIA</value>
                <value>Pakistan</value>
                <value>USA</value>
                <value>USA</value>
            </set>
        </property>

       // <!-- results in a setAddressMap(java.util.Map) call -->
        <property name="addressMap">
            <map>
                <entry key="1" value="INDIA"/>
                <entry key="2" value="Pakistan"/>
                <entry key="3" value="USA"/>
                <entry key="4" value="USA"/>
            </map>
        </property>

       // <!-- results in a setAddressProp(java.util.Properties) call -->
        <property name="addressProp">
            <props>
                <prop key="one">INDIA</prop>
                <prop key="two">Pakistan</prop>
                <prop key="three">USA</prop>
                <prop key="four">USA</prop>
            </props>
        </property>

    </bean>
</beans>
我们可以看到,在生成对象的时候,我们使用下面这个语句:
```javascript
 TextEditor te1 = (TextEditor) context.getBean("textEditor1"); 

在getBean后面的这个字符串里面的内容就是XML配置文件中的bean id, 也就是和以下代码对应:

 <!--构造函数注入-->
    <bean id="textEditor1" class="com.example.demospringbean.TextEditor">
        <constructor-arg ref="spellChecker"/>
    </bean>

以上具体所述的例子是使用构造函数注入,另外一种如上图所显示,也就是setter方法注入。

具体解析代码

现在我们把以上代码进行拆解分析,全部分析清楚之后,Spring框架中关于对象的建立,也就是所谓的IOC和DI,就应该有一个直接明了的了解了,我们采取从主程序一步步往里深入的分析方法:
主程序中,我们首先引入这三个非常重要也是必要的包:

package com.example.demospringbean;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

原因是我们需要使用这两个包来建立一个容器。在这个程序中建立容器对象,对象名为context。

AbstractApplicationContext  context = new ClassPathXmlApplicationContext("Beans.xml");

这样我们就可以用context对象里面getBean这个方法来生成对象了。
如果我们追踪getBean这个方法,我们会发现getBean这个方法是在AbstractApplicationContext abstract class下面的一个override了的一个方法。以下是源码:

//---------------------------------------------------------------------
	// Implementation of BeanFactory interface
	//---------------------------------------------------------------------

	@Override
	public Object getBean(String name) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name);
	}

如果我们要创建一个对象,并且这个对象类里面的属性类型为基本类型或者是String的话:

然后如果我们想建立一个对象的话,我们可以这样:

HelloWorld objA = (HelloWorld) context.getBean("hello");

创建AbstractApplicationContext 的实现类的对象和使用context.geBean来创建对象的。
这个getBean后面的String类型的参数“hello”指向的是XML配置文件中 id = “hello”的那个配置语句,也就是下面这段话:

//创建对象的时候直接给里面的属性赋值
    <bean id="hello" class="com.example.demospringbean.HelloWorld" scope="prototype" init-method="init" destroy-method="destroy">
        <property name="message" value="asd" />
    </bean>

然后这个XML配置文件中, class=“com.example.demospringbean.HelloWorld”, 这句话是实际上和真正的HelloWorld类关联起来的语句。下一行中,property name=“message” value=“asd” ,指的就是在生成这个对象的时候,这个对象的属性中,我们把属性名为message的属性的值设为“asd”。(也就是说,在HelloWorld类里面,其中有一个属性的属性名为property)

如果我们要创建一个对象,并且这个对象类里面的属性类型为一个对象类的话:

然后我们可以看到,以下是配置文件中的部分具体内容

    <!--构造函数注入-->
    <bean id="textEditor1" class="com.example.demospringbean.TextEditor">
        <constructor-arg ref="spellChecker"/>
    </bean>

    <!--Setter注入-->
    <bean id="textEditor2" class="com.example.demospringbean.TextEditor"  >
        <property name="spellChecker" ref="spellChecker"/>
    </bean>

    <bean id="spellChecker" class="com.example.demospringbean.SpellChecker">

    </bean>

这时候我们看到主程序,
TextEditor te1 = (TextEditor) context.getBean(“textEditor1”);
和之前讲到的一样,我们需要去XML文件里面找到id = textEditor1 的XML语句。在XML配置文件中我们发现,constructor-args 这个语句,说明在这里的注入方法是使用构造函数,也就是构造器注入,后面class=“com.example.demospringbean.TextEditor”,就是和具体的类名为TextEditor的类关联起来。
下图是TextEditor类:

    package com.example.demospringbean;

public class TextEditor {
    private SpellChecker spellChecker;
    public TextEditor(){};
    //构造器注入
    public TextEditor(SpellChecker spellChecker) {
        System.out.println("Inside TextEditor constructor." );
        this.spellChecker = spellChecker;
    }

    //Setter注入
    public void setSpellChecker(SpellChecker spellChecker) {
        System.out.println("Inside setSpellChecker." );
        this.spellChecker = spellChecker;
    }

    public SpellChecker getSpellChecker() {
        return spellChecker;
    }

    public void spellCheck() {
        spellChecker.checkSpelling();
    }
}

然而下面还有一句话: constructor-arg ref=“spellChecker”, 这个又是什么意思呢?
这个时候我们发现,TextEditor类的构造器里面除了无参数构造器以外,还有一个以SpellChecker类的对象为参数的构造器,那么如果我们想利用这个构造器来创建TextEditor的对象的话,这时候就要用到这个ref="spellChecker"了。并且注意: 这里的双引号里面的spellChecker 因为是ref = 的值,所以对应的其实是XML配置文件中的id = “spellChecker”的语句,如下图:

<bean id="spellChecker" class="com.example.demospringbean.SpellChecker">

其实对应的是这句话,所以这句话才是实际上把XML配置文件和真正的SpellChecker类关联起来的语句。
setter注入如上图,其实和构造器注入类似,区别就是:
构造器注入的语句是:constructor-arg
setter注入的语句是:property

总结

所以我们发现,实际上所谓的IOC和DI,其实就是一种编程中对象创建的思路,在Spring中广泛使用而已,并且XML注入中的构造器注入和setter注入,在单纯的代码结构上其实非常类似。在上述图片的demo中,还可以看到嵌套bean的注入还有javaCollection(有个自己创建的集合类)的注入,但是其实都是以setter为基础的一些拓展的注入方法,记住:只要看到XML配置文件中的注入方法中,只要是有property这个字段,就是以setter注入,至少是以setter注入为基础的注入(因为例如javaCollection(自己创建的一个集合类)的注入,注入的东西就是一个对象中包含集合,需要给集合里面赋值)。
所以通过以上示例,我们可以就可以比较清晰明确的看出来Spring中的对象的生成和属性的赋值是如何操作的。
我们也可以理解为,我们平时建立对象的时候,是主程序直接new一个类来建立对象,但是现在中间通过了Spring的XML配置文件当作中转站来建立。(或者可以通过注解的方式,注解的方式以后再讲)。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值