1.软件版本和环境搭建
1.1.软件版本
- JDK1.8+
- Maven 3.5+
- IDEA2019+
- 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>
- 2.这两个语句都可以定义一个
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语句)。