跳转至

Spring ApplicationContext 容器

1. 介绍

  Application Context 是 BeanFactory 的子接口,也被成为 Spring 上下文。 Application Context是spring中较高级的容器。和BeanFactory类似,它可以加载配置文件中定义的bean,将所有的bean集中在一起,当有请求的时候分配bean。另外,它增加了企业所需要的功能,比如,从属性文件中解析文本信息和将事件传递给所指定的监听器。这个容器在 org.springframework.context.ApplicationContext interface 接口中定义。

  ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。当然,BeanFactory 仍可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。

最常被使用的 ApplicationContext 接口实现:

  • FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径。
  • ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
  • WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。

案例

  创建spring项目。选择maven模式。

Person.class
package com.cmz.bean;

import java.util.Date;

/**
 * @author summer
 * @create 2020-02-28 18:43
 */
public class Person {
    private int id;
    private String name;
    private Integer age;
    private String gender;
    private Date date;

    public Person() {
    }

    public Person(int id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Person(int id, Integer age, String gender) {
        this.id = id;
        this.age = age;
        this.gender = gender;
    }

    public Person(int id, String name, Integer age, String gender, Date date) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.date = date;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public String getGender() {
        return gender;
    }

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

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", date=" + date +
                '}';
    }
}
Address.class
package com.cmz.bean;

/**
 * @author summer
 * @create 2020-02-28 18:24
 */
public class Address {
    private String province;
    private String city;
    private String town;

    public Address() {
        System.out.println("Address 被创建");
    }

    public Address(String province, String city, String town) {
        this.province = province;
        this.city = city;
        this.town = town;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getTown() {
        return town;
    }

    public void setTown(String town) {
        this.town = town;
    }

    @Override
    public String toString() {
        return "Address{" +
                "province='" + province + '\'' +
                ", city='" + city + '\'' +
                ", town='" + town + '\'' +
                '}';
    }
}
ioc.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--<bean id="person" class="com.cmz.bean.Person" scope="prototype">-->
    <!--根据属性值设置的时候,name的名字取决于set方法后面的参数首字母小写的名称-->
    <!--
    name: 表示参数列表的名称
    value: 表示实际的具体指
    type: 表示值的类型
    index: 表示值的下标,从0开始
    -->

    <bean id="person" class="com.cmz.bean.Person">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="20"></property>
        <property name="gender" value="男"></property>
        <property name="date" value="2020/02/28"></property>
    </bean>

    <!--使用构造器的方法赋值的生活,参数的name属性是由构造方法的参数名称决定的-->
    <bean id="person2" class="com.cmz.bean.Person">
        <constructor-arg name="id" value="2"></constructor-arg>
        <constructor-arg name="name" value="可可"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
        <constructor-arg name="gender" value="女"></constructor-arg>
        <constructor-arg name="date" value="2020/02/28"></constructor-arg>
    </bean>

    <!--使用构造器的方法赋值的生活,可以吧name的属性值不写,但是要注意
    必须要保证数值跟构造器的参数列表的顺序一致-->
    <bean id="person3" class="com.cmz.bean.Person">
        <constructor-arg value="3"></constructor-arg>
        <constructor-arg value="多多"></constructor-arg>
        <constructor-arg value="18"></constructor-arg>
        <constructor-arg value="女"></constructor-arg>
        <constructor-arg name="date" value="2020/02/28"></constructor-arg>
    </bean>


    <!--使用构造器的方法赋值的生活,可以吧name的属性值不写,但是要注意
    必须要保证数值跟构造器的参数列表的顺序一致,若是不一致的话
    ,可以通过index的下标方式来标注,从0开始
    -->
    <bean id="person4" class="com.cmz.bean.Person">
        <constructor-arg value="3"></constructor-arg>
        <constructor-arg value="女" index="3"></constructor-arg>
        <constructor-arg value="18"></constructor-arg>
        <constructor-arg value="嘻嘻" index="1"></constructor-arg>
        <constructor-arg name="date" value="2020/02/28"></constructor-arg>
    </bean>


    <bean id="person5" class="com.cmz.bean.Person">
        <constructor-arg value="3"></constructor-arg>
        <constructor-arg value="18" index="2"></constructor-arg>
        <constructor-arg value="嘻嘻" index="1"></constructor-arg>
        <constructor-arg value="女" index="3"></constructor-arg>
        <constructor-arg name="date" value="2020/02/28"></constructor-arg>
    </bean>

    <!--当有多个相同参数的构造方法存在的时候,默认情况下是覆盖的过程,后面的构造方式会覆盖前面的构造方法
    如果非要赋值给另一个构造方法的话,可以使用type的参数来执行指定
    -->
    <bean id="person6" class="com.cmz.bean.Person">
        <constructor-arg value="3"></constructor-arg>
        <constructor-arg value="多多"></constructor-arg>
        <constructor-arg value="18"></constructor-arg>
    </bean>

    <bean id="person7" class="com.cmz.bean.Person">
        <constructor-arg value="3"></constructor-arg>
        <constructor-arg value="多多"></constructor-arg>
        <constructor-arg value="18" type="java.lang.Integer"></constructor-arg>
    </bean>
    <!--总结: 在日常工作中,一般多用哪个name,value,其他很少用-->


    <!--命名空间-->
    <bean id="person8" class="com.cmz.bean.Person" p:id="5" p:name="王五" p:age="25" p:gender="男" p:date="2020/02/28"></bean>
</beans>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cmz</groupId>
    <artifactId>spring_study</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>

    </dependencies>

</project>

MyTest.class

import com.cmz.bean.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author summer
 * @create 2020-02-22 21:06
 */
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ioc.xml");
        // 根据bean标签id来获取对象
        Person person = context.getBean("person", Person.class);
        Person person1 = context.getBean("person", Person.class);
        System.out.println(person);
        System.out.println(person==person1);

        /*
        * 根据bean的类型来获取对象
        * 注意: 当通过类型进程获取的时候,如果存在两个相同的类型对象,
        * 此时将无法完成获取工作
        * */

//        Person bean = context.getBean(Person.class);
//        System.out.println(bean);

        ApplicationContext context2 = new ClassPathXmlApplicationContext("ioc.xml");
        Person person2 = context2.getBean("person2", Person.class);
        System.out.println(person2);


        ApplicationContext context3 = new ClassPathXmlApplicationContext("ioc.xml");
        Person person3 = context3.getBean("person3", Person.class);
        System.out.println(person3);

        ApplicationContext context4 = new ClassPathXmlApplicationContext("ioc.xml");
        Person person4 = context4.getBean("person4", Person.class);
        System.out.println(person4);
        ApplicationContext context5 = new ClassPathXmlApplicationContext("ioc.xml");
        Person person5 = context5.getBean("person5", Person.class);
        System.out.println(person5);

        ApplicationContext context6 = new ClassPathXmlApplicationContext("ioc.xml");
        Person person6 = context6.getBean("person6", Person.class);
        System.out.println(person6);
        ApplicationContext context7 = new ClassPathXmlApplicationContext("ioc.xml");
        Person person7 = context7.getBean("person7", Person.class);
        System.out.println(person7);

        //命名空间
        ApplicationContext context8 = new ClassPathXmlApplicationContext("ioc.xml");
        Person person8 = context8.getBean("person8", Person.class);
        System.out.println(person8);

        Person person9 = new Person();
        System.out.println(person9);
    }
}
运行结果
Person{id=1, name='张三', age=20, gender='男', date=Fri Feb 28 00:00:00 CST 2020}
true
Person{id=2, name='可可', age=18, gender='女', date=Fri Feb 28 00:00:00 CST 2020}
Person{id=3, name='多多', age=18, gender='女', date=Fri Feb 28 00:00:00 CST 2020}
Person{id=3, name='嘻嘻', age=18, gender='女', date=Fri Feb 28 00:00:00 CST 2020}
Person{id=3, name='嘻嘻', age=18, gender='女', date=Fri Feb 28 00:00:00 CST 2020}
Person{id=3, name='多多', age=18, gender='null', date=null}
Person{id=3, name='null', age=18, gender='多多', date=null}
Person{id=5, name='王五', age=25, gender='男', date=Fri Feb 28 00:00:00 CST 2020}
Person{id=0, name='null', age=null, gender='null', date=null}

注意

1. ClassPathXmlApplicationContext  是读取 src 目录下的配置文件
2. FileSystemXmlApplicationContext  即系统文件路径,文件的目录。
(注意:如果你的xml文件放在WEB-INF文件夹下,需要用这个,否则会找不到该文件)

第一步生成工厂对象。加载完指定路径下 bean 配置文件后,
利用框架提供的 ClassPathXmlApplicationContext API 去生成工厂 bean。
ClassPathXmlApplicationContext 负责生成和初始化所有的对象,
比如,所有在 XML bean 配置文件中的 bean。

第二步利用第一步生成的上下文中的 getBean() 方法得到所需要的 bean。 
这个方法通过配置文件中的 bean ID 来返回一个真正的对象。一旦得到这个对象,
就可以利用这个对象来调用任何方法。

以上先看着大概,接下来会慢慢解释。都是以这个例子讲解。