且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

spring5系列(三) | 初识spring

更新时间:2022-09-20 14:06:14

经过了前面几篇文章的铺垫,从本章开始我们正式进入spring的学习。我们提到过spring的两大核心思想分别是IOC和AOP, 且spring和核心目的就是简化我们的开发和解耦合。 而简化我们开发的核心就是spring的工厂,spring提供了一个工厂,可以帮我我们完成对象的创建和实例化以及依赖注入的过程,那么我们本篇文章就来介绍下,spring工厂是如何帮我们管理类的。

一.spring的工厂和应用上下文

在基于spring的应用各种,你的应用对象生存于spring容器(container)中。spring容器负责创建对象,装配他们,配置值他们并管理他们的整个生命周期,从生存到死亡。

容器是spring框架的核心。spring容器使用DI管理 构成应用的组件,它会创建相互协作的组件之间的关联。 spring容器并不是只有一个。spring自带了多个容器实现。可以归为两种不同的类型。Bean工厂(org.springframework.beans.factory.BeanFactory 接口定义)是最简单的容器,提供基本的DI支持。应用上下文(org.springframework.context.ApplicationContext)接口定义,是基于BeanFactory构建(继承了BeanFactory),并提供了应用框架级别的服务,例如从属性文件解析文本信息及发布应用事件给感兴趣的事件监听者。一般我们经常使用应用上下文。

常见的应用上下文:

  • ClassPathXmlApplicationContext: 从类路径下读取spring配置文件,加载上下文定义,做对象的创建。用于非web应用
  • XmlWebApplicationContext: 在web应用使用,web项目的应用上下文
  • AnnotationConfigApplicationContext: 基于注解和java配置类的应用上下文
  • AnnotationConfigWebApplicationContext: 基于web项目,注解和java配置类的应用上下文。

这里提到的应用上下文,大家就可以把它们理解成就是spring的工厂(或者说容器),他们可以帮我们管理对象的整个生命周期。好了,接下来我们就来体验一下。

二. Hello World (spring)

2.1 代码演示

介绍完了spring的工厂,接下来我们就来体验一下,我们就来简单体验一下spring的用法。

我们先来进行环境搭建:我们采用如下环境配置 JDK 1.8, Maven 3.x, Spring 5.x

这个环境我们就不具体细说了,干过开发的应该都了解,那我我们首先引入spring的依赖

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.1.14.RELEASE</version>
</dependeny>

然后我们就开始spring的使用 我们首先创建一个类: com.spring.User

package com.spring;
public class User{
  
  private Integer id;
  
  private String name;
  
//get set方法省略
}

这样就创建了一个简单单单的普通类,在不同spring的情况下,如果我们想要创建类的对象直接通过new的方式即可:

User user = new User();

而有了spring之后,对象的创建就交给了spring的工厂,那么该如何操作呢,spring 要想帮我们创建对象,我们必须得告诉他类在哪,同时创建好了之后,我们后续肯定是需要使用他,那么也需要定义一个名称,方便我们从spring工厂中获取,因为spring的工厂不可能只管理 一个对象。 所以spring最原始的方式的就是通过配置文件,在配置文件中定义好类的位置和名称,他就可以帮我们创建了。

我们在resources目录下,创建一个配置文件:applicationContext.xml ,配置内容如下

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmmls:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schemabeans/ http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="user" class="com.spring.User" />
</beans>      

我们在spring的配置文件中,添加了一个标签, 就代表这个类交给spring去管理,这个时候当我们启动spring的时候,spring就会帮我们创建这个类的对象,同时在使用的时候也可以直接从spring工厂中获取这个对象。 那么我们应该怎么来启动spring呢,其实也就是如果创建spring的工厂呢,这个就需要上篇文章我们提到的工厂了,而由于是非web项目,同时又是通过xml配置文件的方式启动工厂,所以我们需要使用的是XmlClassPathApplicationContext. 那么接下来我们通过程序演示如何创建工厂并获取对象。

public class SpringTest{
  // 程序启动的入口
  public static void main(String[]args){
  //指定spring配置文件并创建工厂
    ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
  
// 根据配置文件中的id值获取对象  
  User user = (User)ctx.getBean("user");
    
  }  
}

通过上面的步骤,我们就可以获取到对应的类的对象了,也就省去了我们new的过程。 这样一看可能部分人又会觉得,这也没简单啊,相比我们自己new怎么反而更麻烦了呢,这大家要注意,这里只是给大家演示spring的简单用法和原理,我们真正的开发过程中是不会自己去用这样的方式创建工厂的。大家先明白原理。

2.2 注意细节

好了在说一下使用上面方式的一些细节:

  1. 配置文件的名称,一定要和resources目录下的文件名保持一致,否则读取不到配置信息就无法创建对象
  2. user对象的创建其实是在工厂创建的时候,也就是第一行代码执行完毕的时候就已经创建出来了。
  3. getBean() 括号里的参数一定要和配置文件中的id保持一致,获取的类型是Object,想要具体的对象类型需要进行强制类型转换。
  4. 配置文件中的class要写类的全路径,注意不要写错
  5. 配置文件中可以配置多个类,只需要写多个bean标签即可,同时注意id值必须唯一,不能重复。
  6. 除了id以外,也可以使用name代表类的别名,通过别名也可以获取类的对象
  7. id值可以省略,如果省略,会生成缺省id值:全类名#0,其中#0是一个计数形式,用来区分相同类型的其他bean.

2.3 spring工厂中的其他方法

刚刚我们使用的工厂中的getBean(String beanName) 方法,还有一些其他方法我也了解一下

名词解释: bean/component: spring工厂创建的对象

spring工厂的相关方法:

Person p = ctx.getBean("person", Person.class);

Person p = ctx.getBean(Person.class); // 配置文件中只能有一个Person类型的标签 String[] names = ctx.getBeanDefinitionNames(); // persion, person1. 所有bean标签的id

Stringn[] names = ctx.getBeanNamesForType(Person.class);// 根据类型获取名字,所有Person类型

boolean res = ctx.containsBeanDefinition("person");// 是否存在指定id对应标签 boolean res = ctx.containsBean("person");// 是否存在指定id对应标签

大家可以尝试一下。

三.浅析底层实现

上面我们通过一个简短的小程序验证了spring工厂装配一个bean的过程。大概总结为以下4步:

  1. 创建一个类
  2. 创建spring配置文件
  3. 在配置文件中通过标签指定类的id和路径
  4. 创建spring工厂,指定配置文件,通过工厂获取对象

步骤相对而言比较简单,那么我们来简单思考一下,这一切在spring的底层是如何实现的呢。其实主要应用的就是反射。通过读取配置文件我们就可以对配置文件进行解析。从而得到这个类的全类名,有了全类名,我们就可以通过反射获取对象了。大概步骤如下:

Class clazz = Class.forName("com.spring.User");
Object user = clazz.newInstance();

同时我们又指定了id, 我们可以简单理解有一个Map<String,Object> 的数据接口就相当于spring的工厂,id作用key,对象作为value, 这样通过id我们就可以得到对象了。

这里要注意,通过反射创建的对象是要调用类的构造方法的,默认是调用无参构造。当然私有的也是可以的,因为私有的构造方法也是可以通过反射创建出对象的。如果想尝试一下,可以直接在构造方法中打印一句话,在执行spring工厂创建的代码是,就会发现这句话能够打印出来。就验证上面的结论。同时也可以验证,对象到底是在工厂创建的时候创建还是在获取对象的时候创建的。

四. 总结

好了,本篇文章我们主要介绍了spring的初级用法,说实话比较简单,主要带大家回顾一下。这些内容我想学过spring的肯定都知道。没学过的,主要掌握bean标签的用法和工厂的创建即可。因为后续内容我们都会从这类进行展开。

参考资料:

Spring IN Action(第四版) 中国邮电出版社

孙帅spring详解:www.bilibili.com/video/BV185…