Spring学习笔记-IoC控制反转

Spring通过IOC容器来管理所有Java对象的实例化和初始化,控制对象与对象之间的依赖关系.将IoC容器管理的Java对象称之为Spring Bean,它与使用关键字new创建的Java对象没有任何区别.

IoC控制反转

IoC容器是Spring框架中最重要的核心组件之一.

在传统Java应用中,一个雷想要调用另一个类中的属性或方法,通常会现在其代码中通过new Object()的方式将后者的对象创建出来,然后才能实现属性或方法的调用.前者成为"调用者",后者称为"被调用者",也就是说,调用者掌握着被调用者的创建的控制权.

而在Spring中,Java的对象创建的控制权是掌握再IOC容器手里的.通过再XML配置文件,注解,Java配置类等方式,对Java对象进行定义;Spring启动时,IoC容器会自动根据对象定义,将这些对象创建并管理起来;当想要某个bean时,直接从IOC容器中获取,不需要手动通过代码创建.

IoC在代码层并没有多大的变化,是从思想层面发了"主从换位"的改变,云本调动着是主动的一方,需要什么资源主动自己创建.但在Spring应用中,IoC容器掌握着主动权,调用者则变成了被动的一方,等待IoC容器创建它所需要的对象(Bean).

依赖注入(DI)

在面向对象中,对象和对象之间是存在一种叫做"依赖"关系的.简单说,依赖关系是在一个对象中需要用到另外一个对象,即对象中存在一个属性,该属性是另外一个类的对象.

在对象创建过程中,Spring会自动根据依赖关系,将它依赖的对象注入到当前对象中,这就是所谓的"依赖注入".

IoC的工作原理

也是实现解耦的原理:由于对象的基本信息,对象之间的依赖关系都是在配置文件中定义的,并没有在代码中紧密耦合,即使对象发生改变,只需在配置文件中进行修改即可,无须对Java代码进行修改,这就是Spring IOC实现解耦的原理.

IoC底层通过工厂模式,Java反射机制,XML解析等技术,将代码的耦合度降到最低限度,其主要步骤如下:

(1).在配置文件中,对各个毒对象以及它们之间的依赖进行配置;

(2).把IoC容器当做一个工厂,Spring Bean是工厂的产品.容器启动时,会加载并解析配置文件,得到对象的基本信息以及它们之间的依赖关系;

(3).IOC利用反射机制,根据类名生成相应的对象,并根据依赖关系讲这个对象注入到依赖它的对象中.

IOC容器的两种实现

(1).BeanFactory

是IoC容器的基本实现,由org.springframework.beans.factory.BeanFactory接口定义.

BeanFactory才用懒加载机制,容器在加载配置文件时并不会创建Java对象,在程序获取这个对象时才会创建.

注意:BeanFactory是Spring内部使用接口,通常不提供给开发人员使用.

示例

 public static void main(String[] args) {
        BeanFactory context=new ClassPathXmlApplicationContext("application.xml");
        Example example = context.getBean("example", Example.class);
        System.out.println(example.toString());
    }

(2).ApplicationContext

ApplicationContext是BeanFactory接口的子接口,在BeanFactory的基础上增加了许多企业级功能,例如AOP,事务支持等.

ApplicationContext接口有两个常用的实现类,如下图所示

 示例

 public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("application.xml");
        Example example = context.getBean("example", Example.class);
        System.out.println(example.toString());
    }

Spring Bean定义

Spring配置文件有两种格式,即XML文件格式和properties文件格式:

(1).properties配置文件主要以key-value形式存在,不能进行其他操作,适用于简单配置.

(2).XML配置文件采用树形结构,结构清晰,相较于properties文件更加灵活,但XML配置比较繁琐,适合大型项目的复杂配置.

XML配置文件的根元素是<beans>,该元素包含多个子元素<bean>,一个<bean>元素都定义了一个Bean.

在XML配置的<bean>元素中可以包含多个属性或子元素,常用的属性或子元素如下图所示:

 Spring主要通过一下两种方式实现属性注入:

(1).构造函数注入:使用<constructor-arg>元素,对构造函数内的属性进行赋值,Bean的构造函数有多少个参数,就需要使用多少个<constructor-arg>元素.

示例:

实体类

package com.demo.pojo;

public class Student {
    private String name;
    private String gender;
    private int age;
    private String sno;
    private Class aclass;

    public Student(String name, String gender, int age, String sno, Class aclass) {
        this.name = name;
        this.gender = gender;
        this.age = age;
        this.sno = sno;
        this.aclass = aclass;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", sno='" + sno + '\'' +
                ", aclass=" + aclass +
                '}';
    }
}
package com.demo.pojo;

public class Class {
    private int floor;
    private String cno;

    public Class(int floor, String cno) {
        this.floor = floor;
        this.cno = cno;
    }

    @Override
    public String toString() {
        return "Class{" +
                "floor=" + floor +
                ", cno='" + cno + '\'' +
                '}';
    }
}

XML配置文件

    <bean id="student" class="com.demo.pojo.Student">
        <constructor-arg name="name" value="潇潇"/>
        <constructor-arg name="gender" value="女"/>
        <constructor-arg name="age" value="20"/>
        <constructor-arg name="sno" value="00000001"/>
        <constructor-arg name="aclass" ref="aclass"/>
    </bean>
    <bean id="aclass" class="com.demo.pojo.Class">
        <constructor-arg name="floor" value="5"/>
        <constructor-arg name="cno" value="0001"/>
    </bean>

测试

package com.demo.pojo;

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

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("application.xml");
        Student student = context.getBean("student", Student.class);
        System.out.println(student.toString());
    }
}

结果

 简化p命名空间注入

在<beans>元素中导入一下XML约束

xmlns:p="http://www.springframework.org/schema/p"

 导入约束后,通过一下形式实现属性注入

<bean id="Bean 唯一标志符" class="包名+类名" p:普通属性="普通属性值" p:对象属性-ref="对象的引用">

实体类和测试不变,改变XML配置文件

<bean id="student" class="com.demo.pojo.Student" p:name="盼盼" p:age="22" p:gender="女" p:sno="00000012" p:aclass-ref="aclass">
    </bean>
    <bean id="aclass" class="com.demo.pojo.Class" p:floor="8" p:cno="0001">
    </bean>

结果

(2).setter注入:使用<property>元素对各个属性进行赋值

 在Spring实例化Bean的过程中,IoC容器首先会调用默认的构造方法(无参构造方法)实例化Bean,然后通过Java的反射机制调用这个Bean的setXxx()方法,将属性值注入到Bean中.

示例:

实体类

package com.demo.pojo;

public class Student {
    private String name;
    private String gender;
    private int age;
    private String sno;
    private Class aclass;

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

    public void setGender(String gender) {
        this.gender = gender;
    }

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

    public void setSno(String sno) {
        this.sno = sno;
    }

    public void setAclass(Class aclass) {
        this.aclass = aclass;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", sno='" + sno + '\'' +
                ", aclass=" + aclass +
                '}';
    }
}
package com.demo.pojo;

public class Class {
    private int floor;
    private String cno;

    public Class(int floor, String cno) {
        this.floor = floor;
        this.cno = cno;
    }

    @Override
    public String toString() {
        return "Class{" +
                "floor=" + floor +
                ", cno='" + cno + '\'' +
                '}';
    }
}
或
package com.demo.pojo;

public class Class {
    private int floor;
    private String cno;

    public void setFloor(int floor) {
        this.floor = floor;
    }

    public void setCno(String cno) {
        this.cno = cno;
    }

    @Override
    public String toString() {
        return "Class{" +
                "floor=" + floor +
                ", cno='" + cno + '\'' +
                '}';
    }
}


XML配置文件

<bean id="student" class="com.demo.pojo.Student">
        <property name="name" value="胖墩"/>
        <property name="age" value="21"/>
        <property name="gender" value="男"/>
        <property name="sno" value="00000002"/>
        <property name="aclass" ref="aclass"/>
    </bean>

    <bean id="aclass" class="com.demo.pojo.Class">
        <constructor-arg name="floor" value="10"/>
        <constructor-arg name="cno" value="0004"/>
    </bean>
或
<bean id="aclass" class="com.demo.pojo.Class">
        <property name="floor" value="10"/>
        <property name="cno" value="0004"/>
    </bean>

测试

package com.demo.pojo;

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

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("application.xml");
        Student student = context.getBean("student", Student.class);
        System.out.println(student.toString());
    }
}

结果

 

 c命名空间注入

现在XML文件中导入约束

xmlns:c="http://www.springframework.org/schema/c"

实现属性注入形式:

<bean id="Bean 唯一标志符" class="包名+类名" c:普通属性="普通属性值" c:对象属性-ref="对象的引用">

实体类和测试不变,改变XML配置文件

<bean id="student" class="com.demo.pojo.Student" c:name="麻薯" c:age="20" c:gender="女" c:sno="00000022" c:aclass-ref="aclass">
   </bean>
   <bean id="aclass" class="com.demo.pojo.Class" c:floor="5" c:cno="0009">
   </bean>

结果

 

Spring内部注入Bean

将在<bean>元素的<property>或<constructor-arg>元素内部的Bean,称为内部Bean.

(1)setter方式注入内部Bean实体类

实体类

package com.demo.pojo;

public class Student {
    private String name;
    private String gender;
    private int age;
    private String sno;
    private Class aclass;

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

    public void setGender(String gender) {
        this.gender = gender;
    }

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

    public void setSno(String sno) {
        this.sno = sno;
    }

    public void setAclass(Class aclass) {
        this.aclass = aclass;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", sno='" + sno + '\'' +
                ", aclass=" + aclass +
                '}';
    }
}
package com.demo.pojo;

public class Class {
    private int floor;
    private String cno;


    public void setFloor(int floor) {
        this.floor = floor;
    }

    public void setCno(String cno) {
        this.cno = cno;
    }

    @Override
    public String toString() {
        return "Class{" +
                "floor=" + floor +
                ", cno='" + cno + '\'' +
                '}';
    }
}

XML配置文件

 <bean id="student" class="com.demo.pojo.Student">
        <property name="name" value="胖墩"/>
        <property name="age" value="21"/>
        <property name="gender" value="男"/>
        <property name="sno" value="00000002"/>
        <property name="aclass">
            <bean id="aClass" class="com.demo.pojo.Class">
                <property name="floor" value="10"/>
                <property name="cno" value="0004"/>
            </bean>
        </property>
    </bean>

测试

package com.demo.pojo;

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

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("application.xml");
        Student student = context.getBean("student", Student.class);
        System.out.println(student.toString());
    }
}

结果

 

(2)构造方法注入内部Bean实体类

实体类

package com.demo.pojo;

public class Student {
    private String name;
    private String gender;
    private int age;
    private String sno;
    private Class aclass;

    public Student(String name, String gender, int age, String sno, Class aclass) {
        this.name = name;
        this.gender = gender;
        this.age = age;
        this.sno = sno;
        this.aclass = aclass;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", sno='" + sno + '\'' +
                ", aclass=" + aclass +
                '}';
    }
}
package com.demo.pojo;

public class Class {
    private int floor;
    private String cno;

    public Class(int floor, String cno) {
        this.floor = floor;
        this.cno = cno;
    }

    @Override
    public String toString() {
        return "Class{" +
                "floor=" + floor +
                ", cno='" + cno + '\'' +
                '}';
    }
}

配置文件

<bean id="student" class="com.demo.pojo.Student">
        <constructor-arg name="name" value="二虎"/>
        <constructor-arg name="age" value="19"/>
        <constructor-arg name="gender" value="男"/>
        <constructor-arg name="sno" value="00000022"/>
        <constructor-arg name="aclass">
            <bean id="aClass" class="com.demo.pojo.Class">
                <constructor-arg name="floor" value="12"/>
                <constructor-arg name="cno" value="0002"/>
            </bean>
        </constructor-arg>
    </bean>

结果

 Spring注入集合

在Bean标签下的<property>元素中,使用以下元素配置Java集合类型的属性和参数.

标签说明
<list>用于注入list类型的值,允许重复
<set>用于注入set类型的值,不允许重复
<map>用于注入key-value的集合,其中key和value都可以是任意类型
<props>用于注入key-value的集合,其中key和value都是字符串类型

示例

实体类

package com.demo.pojo;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class JavaCollection {
    private String[] courses;
    private List<String> list;
    private Map<String,String> maps;
    private Set<String> sets;

    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }

    public void setSets(Set<String> sets) {
        this.sets = sets;
    }

    @Override
    public String toString() {
        return "JavaCollection{" +
                "courses=" + Arrays.toString(courses) +
                ", list=" + list +
                ", maps=" + maps +
                ", sets=" + sets +
                '}';
    }
}

XML配置文件

 <bean id="javaCollection" class="com.demo.pojo.JavaCollection">
        <property name="courses">
            <array>
                <value>Java</value>
                <value>C语言</value>
                <value>PS</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>张三</value>
                <value>张三丰</value>
                <value>张丰丰</value>
            </list>
        </property>
        <property name="maps">
            <map>
                <entry key="A" value="a"></entry>
                <entry key="B" value="b"></entry>
                <entry key="C" value="c"></entry>
            </map>
        </property>
        <property name="sets">
            <set>
                <value>电脑</value>
                <value>键盘</value>
                <value>鼠标</value>
            </set>
        </property>
    </bean>

测试

package com.demo.pojo;

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

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        JavaCollection javaCollection = context.getBean("javaCollection", JavaCollection.class);
        System.out.println(javaCollection.toString());
    }
}

结果

在集合中设置对象的值

 示例

实体类

package com.demo.pojo;

public class Student {
    private String name;
    private String gender;
    private int age;
    private String sno;

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

    public void setGender(String gender) {
        this.gender = gender;
    }

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

    public void setSno(String sno) {
        this.sno = sno;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", sno='" + sno + '\'' +
                '}';
    }
}
package com.demo.pojo;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.demo.pojo.Student;

public class JavaCollection {
    private Student[] courses;
    private List<String> list;
    private Map<String, String> maps;
    private Set<String> sets;

    public void setCourses(Student[] courses) {
        this.courses = courses;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }

    public void setSets(Set<String> sets) {
        this.sets = sets;
    }

    @Override
    public String toString() {
        return "JavaCollection{" +
                "courses=" + Arrays.toString(courses) +
                ", list=" + list +
                ", maps=" + maps +
                ", sets=" + sets +
                '}';
    }
}

XML配置

<bean id="student1" class="com.demo.pojo.Student">
        <property name="name" value="胖墩1"/>
        <property name="age" value="21"/>
        <property name="gender" value="男"/>
        <property name="sno" value="00000002"/>
    </bean>
    <bean id="student2" class="com.demo.pojo.Student">
        <property name="name" value="胖墩2"/>
        <property name="age" value="21"/>
        <property name="gender" value="男"/>
        <property name="sno" value="00000002"/>
    </bean>
    <bean id="student3" class="com.demo.pojo.Student">
        <property name="name" value="胖墩3"/>
        <property name="age" value="21"/>
        <property name="gender" value="男"/>
        <property name="sno" value="00000002"/>
    </bean>
    <bean id="javaCollection" class="com.demo.pojo.JavaCollection">
        <property name="courses">
            <array>
                <ref bean="student1"></ref>
                <ref bean="student2"></ref>
                <ref bean="student3"></ref>
            </array>
        </property>
        <property name="list">
            <list>
                <value>张三</value>
                <value>张三丰</value>
                <value>张丰丰</value>
            </list>
        </property>
        <property name="maps">
            <map>
                <entry key="A" value="a"></entry>
                <entry key="B" value="b"></entry>
                <entry key="C" value="c"></entry>
            </map>
        </property>
        <property name="sets">
            <set>
                <value>电脑</value>
                <value>键盘</value>
                <value>鼠标</value>
            </set>
        </property>
    </bean>

测试

package com.demo.pojo;

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

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        JavaCollection javaCollection = context.getBean("javaCollection", JavaCollection.class);
        System.out.println(javaCollection.toString());
    }
}

结果

 

Spring注入null值

配置文件

    <bean id="student" class="com.demo.pojo.Student">
        <property name="name" value="胖墩"/>
        <property name="age" value="21"/>
        <property name="gender" >
            <null/>
        </property>
        <property name="sno" value="00000002"/>
    </bean>

结果

Spring注入空字符串

配置文件

<bean id="student" class="com.demo.pojo.Student">
        <property name="name" value="胖墩"/>
        <property name="age" value="21"/>
        <property name="gender" value=""/>
        <property name="sno" value="00000002"/>
    </bean>

结果

Spring Bean作用域

默认情况下,所有的Spring Bean都是单例的,也就是说在整个Spring应用中,Bean的实例只有一个.

可在<bean>元素中添加scope属性来配置作用域.例如,每次获取Bean时,都需要一个新的Bean示例,可以把scope属性定义为prototype;如果Spring每次需要返回一个相同的Bean实例,应将Bean的scope属性定义为singleton.

scope共有六种作用域,如下图所示:

注意:这六种作用域中,除了singleton和prototype可以直接在常规的Spring IoC容器中使用外,剩下的都只能在基于Web的ApplicationContext实现中才能使用,否则会抛出一个IIIegalStateException的异常.

Spring Bean生命周期

Spring中Bean的生命周期比较复杂,可分为5个阶段:

        (1).Bean的实例化

        (2).Bean属性赋值

        (3).Bean的初始化

        (4).Bean的使用

        (5).Bean的销毁

Spring 生命周期流程

 自定义Bean的生命周期

Bean的生命周期回调方法主要有两种:

(1).初始化回调方法:在Spring Bean被初始化后调用,执行一些自定义的回调操作.

(2).销毁会回调方法:在Spring Bean被销毁前调用,执行一些自定义的回调操作.

可以通过三种方式自定义Bean的生命周期回调方法:

如果一个Bean中有多种生命周期回调方法时,优先级顺序为:注解>接口>XML配置.

(1).通过接口实现.

InitializingBean和DisposableBean接口指定Bean的生命周期回调方法.

 注意通常情况下,不建议使用这种方式指定生命周期回调方法,因为这种方式会导致代码的耦合度过高.

(2).通过XML配置实现.

通过<bean>元素中的inti-method和destory-method属性,指定Bean的生命周期回调方法.

(3).使用注解实现.

通过@PostConstructor和@PreDestroy注解,指定Bean的生命周期回调方法.

学习网址:Spring框架教程(非常详细)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值