Spring02:Spring的ApplicationContext工厂

1.软件版本和环境搭建

1.1.软件版本

  1. JDK1.8+
  2. Maven 3.5+
  3. IDEA2019+
  4. SpringFramework 5.1.4

1.2.环境搭建:无外乎两个环节

1.相关的jar包

  • 1.1.因为现在是基于Maven的jar包管理,所以在这只需要设置pom依赖即可。通过Maven的中心仓库,来查找相关jar包的坐标,进而进行管理。
    在这里插入图片描述
  • 1.2.将找到的jar包坐标,复制到pom.xml文件中
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.4.RELEASE</version>
</dependency>
  • 1.3.Maven帮我们下载好jar包
    在这里插入图片描述
    虽然我们只导入一个spring-context的jar包坐标,但是按照Maven的依赖管理来说还依赖了aop,beans,core,expression,jcl等jar包

2.Spring的配置文件

我们以前使用框架开发的时候,作为任何一个框架来说,都会为我们提供一个对应的配置文件。

那么处理配置文件的过程中,有两个需要我们注意的细节

  • 1.配置文件的放置位置:项目的任意位置,没有硬性要求。
  • 2.配置文件的命名:也没有硬性要求,但是建议applicationContext.xml

3.思考:

既然Spring没有硬性规定配置文件的存放位置和命名名称,那么Spring怎么知道哪个是配置文件?配置文件又放在了哪呢?

所以需要我们主动告诉Spring这两个问题:进行配置文件的路径配置。

1.3.IDEA整合配置文件

IDEA是比较智能的,它在帮我们整合Spring框架的过程中,同时也帮我们整合了Spring的配置文件。所以要想在项目中引入Spring的配置文件,IDEA是可以非常方便的帮我们创建出来。我们来看看IDEA在使用的过程中,是怎么帮我们创建配置文件的。

1.按照Maven的习惯,配置文件是放在resources文件夹下的。
在这里插入图片描述

2.创建一个Spring的xml配置文件

在这里插入图片描述
IDEA生成的applicationContext.xml配置文件,其中已经存在了一写公共的标签,不用我们再去自己写了。
在这里插入图片描述

目前为止,Spring的环境搭建一个做好了。

1.4.小结

  • 1.jar包:Maven来完成的
  • 2.IDEA来生成配置文件:applicationContext.xml

2.Spring的核心API

核心API也称为核心类,是一个框架最核心的类型。我们编程时,主要就是利用这些类型来进行开发和使用。

之前我们在学习开源框架的时候,会导入与之对应的开源jar包。每个jar包中,都可能有成百上千个Java类。但是在我们开发的时候,并不会都使用到这些类型,只需要熟练使用一些常用的类即可。

2.1.Spring的工厂类

1.ApplicationContext是一个接口类型:

  • 作用:Spring提供的ApplicationContext这个工厂,主要就是用于对象的创建。
  • 好处:解耦合。
  • 注意:
    1.ApplicationContext是接口类型
    2.为什么要设计成接口:为了屏蔽实现的差异。考虑到Spring的这个工厂会用在不同的开发场景下,不同的开发场景有各自的特点。
      所以将这个工厂类ApplicationContext,设计成接口类型,屏蔽各自具体工厂实现的差异。
    

2.Sping主要提供了两种工厂实现类

  • 非web环境的工厂:ClassPathXmlApplicationContext

    非web环境主要指的是main,单元测试。这种情况是不用启动服务器的,所以是一个非web环境。
    
    所以以后在main函数中,junit单元测试中,可以用ClassPathXmlApplicationContext工厂类来创建对象。
    
  • web环境的工厂:XmlWebApplicationContext

3.我们来看看ApplicationContext这个工厂接口和它的具体实现的关系。

  • 找到这个ApplicationContext接口,看一下继承关系,找到了 非web环境的工厂实现类ClassPathXmlApplicationContext

在这里插入图片描述

  • 由于没有引入SpringWeb相关的依赖,所以没有找到web环境的工厂实现XmlWebApplicationContext

    引入SpringWeb相关的依赖:这个后面会在将SpringMVC的时候专门导这个包,现在先拿出来导一下。

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.4.RELEASE</version>
    </dependency>
    

    发现了web环境的工厂实现XmlWebApplicationContext

在这里插入图片描述

2.2.ApplicationContext是一个重量级资源。

对于一个类型,一个对象来讲,我们所说轻的或者重的,主要体现在内存的占用。如果一个对象对内存占用较多,我们就称为重量级资源;如果对内存占用较少,我们就称为轻量级资源。

重量及资源主要体现在下面这几个方面:

  • 1.ApplicationContext是一个重量级资源:

    那么ApplicationContext是一个重量级资源就说明,ApplicationContext工厂的对象会占用大量的内存。

  • 2.一个应用只会创建一个ApplicationContext工厂对象。

    所以我们需要注意的是:由于这个ApplicationContext是个重量级资源,占用内存比较多,所以我们不会频繁的创建这个对象,一个应用只会创建一个ApplicationContext工厂对象。

  • 3.是线程安全的:可以被多线程并发访问

    因为只会创建一个对象,所以A可能访问,B也可能访问。所以就可能出现并发访问的问题。
    需要注意的是,但凡是我们提到的这些重量级资源,如果都可以被多用户访问,且不会出现问题,就说明它是线程安全的。那么按照我们最朴树的想法,所谓的线程安全,这个工厂里面一定做了Synchronized锁的设置。

  • 所以一个重量级资源一般都会符合这些特点:内存占用大,只创建一次,线程安全的。

3.第一个Spring程序

我们知道Spring程序的最大特点,就是为我们提供了创建对象的工厂。我们可以使用这个工厂创建对象,很好的起到一个解耦合的效果。Spring的这个工厂和我们之前讲的通用工厂是没有本质的区别的。

3.1Spring程序的开发步骤

1.回顾一下我们之前学习的通用工厂的使用:

1.创建类型:想要什么对象,首先要有这个类。比如Person类。
2.配置文件的配置:applicationContext.xml
3.通过工厂,获得对象:ApplicationContext
	ClassPathXmlApplicationContext implements ApplicationContext
	XmlWebApplicationContext implements ApplicationContext
  • 1.创建类型:比如我想创建Person对象,先要有Person类

    package com.baizhiedu.basic.model;
    
    public class Person {
          
          
    
    }
    
  • 2.配置文件的配置:告诉Spring需要帮我生产的对象

    <bean id="person" class="com.baizhiedu.basic.model.Person"></bean>
    
    <bean/>标签的两个属性:
    	1.id:唯一标识
    	2.class:全限定类名
    
  • 3.通过工厂,获得对象

    1.获得Spring的工厂:指定配置文件,和配置文件的位置
    2.通过工厂类来获得对象:指定要获得的在配置文件中配置的bean的id

        /**
       * 用于测试Spring的第一个程序
       */
      @Test
      public void test3(){
          
          
          //1.获得Spring的工厂:指定配置文件,和配置文件的位置
          ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
          //2.通过工厂类来获得对象:指定要获得的在配置文件中配置的bean的id
          Person person = (Person)applicationContext.getBean("person");
      }
    

    至此,Person对象就通过Spring的方式创建出来了。

3.3.第一个Spring程序小结

1.创建类型:想要什么对象,首先要有这个类。比如Person类。

2.配置文件的配置:applicationContext.xml

3.通过工厂,获得对象:ApplicationContext

ClassPathXmlApplicationContext implements ApplicationContext
XmlWebApplicationContext implements ApplicationContext

4.一些细节分析

Spring工厂创建的对象,也可以叫做bean或者组件(component)

4.1.Spring工厂的一些相关的方法

1.applicationContext.getBean()的重载:

在这里插入图片描述

  • Person person = context.getBean("person", Person.class); 不用强转了
  • Person person1 = context.getBean(Person.class); 当前配置文件中只能有一个<bean/>标签是person类型的。

2.context.getBeanDefinitionNames();得到所有的bean定义的名字,返回一个数组。

即bean标签的id值,bean的名字。
	1.bean的定义:<bean id="person" class="com.baizhiedu.basic.model.Person"></bean>
	2.bean定义:id="person"

在这里插入图片描述
3.String[] namesForType = context.getBeanNamesForType(Person.class);获得所有Person类型的bean的id值。

4.context.containsBeanDefinition("person1");是否包含这个bean的id,返回一个boolean值。

在这里插入图片描述
5.context.containsBean("person");目前来讲和context.containsBeanDefinition("person1");作用是一样,具体的区别,后面再说。

4.2.Spring配置文件的细节:

4.2.1.< bean />标签只配置class属性,不设置id值。

1.<bean/>标签只配置class属性,不设置id值。

<bean class="com.baizhiedu.basic.model.Person"></bean>

这种语法也是支持的,而且Spring会为我们加上默认的id值:com.baizhiedu.basic.model.Person#0

测试代码:

    @Test
    public void test5(){
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
        
        //<bean/>标签只配置class属性,也能创建对象
        Person person = context.getBean(Person.class);
        
        //Spring会为bean加上默认的id=com.baizhiedu.basic.model.Person#0
        String[] definitionNames = context.getBeanDefinitionNames();
        System.out.println(Arrays.toString(definitionNames));
    }

测试结果:
在这里插入图片描述

应用场景:什么情况下我们不需要再bean标签中设置id值。

  • 如果这个bean只需要使用一次,那么就可以省略id值。
  • 如果这个bean回使用多次,或者被其他bean引用,则需要设置id值。

4.2.2.< bean/ >标签的name属性

1.<bean/>标签的name属性

作用:用于在Spring的配置文件中,为bean对象定义别名。id可以认为是这个bean对象的大名,在整个项目中是唯一的。

2.id和name属性两者的相同处:

  • 1.都可以这两个属性获得bean对象:
    <bean id="person" name="pppp" class="com.baizhiedu.basic.model.Person"></bean>
    
    public void test6(){
          
          
        ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
    
        //<bean/>标签的name属性属性,也能创建对象
        Person person = (Person)context.getBean("pppp");
        System.out.println(person);
        
        //<bean/>标签的id属性属性,也能创建对象
        Person person1 = (Person)context.getBean("person");
        System.out.println(person1);
    }
    
    • 2.这两个语句都可以定义一个bean标签
      <bean id="person" class="com.baizhiedu.basic.model.Person"></bean>
      <bean name="pppp" class="com.baizhiedu.basic.model.Person"></bean>
    

3.id和name属性两者的不同:

  • name属性可以在一个bean标签中定义多个:每个name别名属性都可以用来获取对象。
    <bean name="pppp, p1, p3" class="com.baizhiedu.basic.model.Person"></bean>
    
  • 两个<bean/>标签的name属性不能一样。
  • 原来xml中的id属性,必须以字母开头。name属性的命名没有要求。现在已经没有这些限制了。

4.2.3context.containsBeanDefinition()context.containsBean()

1.之前我们学习两者的作用都是:判断是否存在这个bean的id,返回一个boolean值。

2.区别:

  • context.containsBeanDefinition("person1")只能判断是否一个bean的id是否是person1;如果一个bean的id不是person1,但是name是person1,仍然返回false。
  • context.containsBean("person1")既可以判断id也可以判断name。如果一个bean的id是person1,返回true;如果一个bean的name是person1,也会返回true。

5.Spring工厂的底层实现原理(简易版)

我们暂时先从思想上分析一下Spring工厂的底层实现原理,不从源码分析。

1.通过工厂对象读取配置文件
2.根据配置文件中的全限定类名,反射创建对象
3.反射创建对象会调用无参构造:注意反射是可以调用一个类中的私有属性和方法(包里反射)。所以如果这个构造是私有的,也可以创创建bean对象。这也是Spring工厂的强大之处。
在这里插入图片描述

6.思考

1.问题:未来在开发中,是否所有的对象,都要交给Spring工厂来创建呢?

回答:不是,比如实体对象entity。因为实体对象的属性对应着表中的字段,我们得到实体对象不仅仅是要这个对象,还要这些属性,而这些属性必须通过操作数据库来得到。所以交由持久层框架来创建(结合业务sql语句)。

猜你喜欢

转载自blog.csdn.net/tttxxl/article/details/115220250
今日推荐