主要内容
对于Java开发者来说,Spring就是。。
- 对于没有研究过Spring源码的选手,就算Spring Boot和Cloud用到飞起也只是漂亮的空中阁楼。
- 遂对Spring主要组件的源码进行学习,在使用Spring的相关框架时,对自己的写的代码要心知肚明,毕竟根基不牢地动山摇。
关于Spring Framework
它是做什么的
- 就是方便Java EE(企业级开发)的,具体看(Spring Framework)中的Features条目。
- 凡是一些常用和繁琐的功能都加一层封装好,就给个接口供开发者调用。
- 还有一些抽象的概念比如:IoC,DI,容器,AOP等概念,之后有遇到再细说。
- 还有什么发展历史,比如EJB哪些,感兴趣自行了解。
环境搭建
导入如下依赖,以方便进行Spring技术的研究
"org.springframework:spring-core:5.3.14.RELEASE",
"org.springframework:spring-aop:5.3.14.RELEASE",
"org.springframework:spring-beans:5.3.14.RELEASE",
"org.springframework:spring-context:5.3.14.RELEASE" ,
"org.springframework:spring-context-support:5.3.14.RELEASE",
"org.springframework:spring-web:5.3.14.RELEASE",
"org.springframework:spring-orm:5.3.14.RELEASE",
"org.springframework:spring-aspects:5.3.14.RELEASE",
"org.springframework:spring-webmvc:5.3.14.RELEASE"
"org.springframework :spring-jdbc:5.3.14.RELEASE",
"org.springframework:spring-instrument:5.3.14.RELEASE",
"org.springframework:spring-tx:5.3.14.RELEASE",
Spring是一个容器
- 在Spring中,对象一般称之为Bean,Spring可以管理和实例化对象。
- 总的来说,在企业级开发中有蛮蛮多类需要被实例化,单靠人为的去new,由于数量庞大,八成是会错乱的。所以Spring帮你new,你只需要取你想要的对象进行使用即可。
- 即你只要担心你需要的,而其它的就可以忽略了。
样例
- 以下为本次目录结构
先从最基础的xml模式开始
先把类定义好
- bean
/*
POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,也可以说是没有功能的对象
*/
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- xml文件
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.spring.bean.Student">
<property name="name" value="法外狂徒" />
<property name="age" value="23" />
</bean>
</beans>
- 在xml中给Student类中的属性赋值了,即将Student数据存在了xml文件中
- main方法所在的类
public class SpringClient {
public static void main(String[] args) {
Resource resource = new ClassPathResource("applicationContext.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(factory);
beanDefinitionReader.loadBeanDefinitions(resource);
Student student = (Student) factory.getBean("student");
System.out.println(student.getName() +"\n" + student.getAge() );
}
}
Spring所涉及的思想
所有信息都称之为资源(Resource)
- 资源包含很多内容:类路径下面的资源,文件系统中的文件,xml文件,HTTP,url。。。
- 所以
Resource resource = new ClassPathResource("applicationContext.xml");这行代码的出现就是理所应当了。要将资源准备好。 - 对于ClassPath是什么,简单说就是java文件编译成class文件后,class文件所在的目录就是,
String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
System.out.println("path = " + path);//得到的就是classpath
Spring之所以叫容器是因为它帮我们管理(实例化)了Bean对象
- 如何实例化?当然是经典的工厂模式。
- 工厂模式简单说就是对外隐藏new关键字,调用工厂方法获取实例化对象。
- 只要告诉工厂正确的配方(Resource),它就能帮你造出对象来。
- 当需要对象时,直接管工厂要就行了。
- 所以
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();这行代码的出现就是理所应当了。
如何将工厂和资源关联起来?
- 首先,工厂是存放和创建对象的地方,对于资源解析和读取的功能工厂肯定是没有的。
- 所以对资源的解析就由Bean的定义读取器(BeanDefinitionReader)来完成,当然还要让它和工厂发生关系。
- 所以
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(factory);这行代码的出现就理所应当了。因为资源是xml的格式,所以用XmlBeanDefinitionReader BeanDefinitionReader还有解析资源的功能,将解析到的bean信息告诉工厂,工厂就会将一个个bean存起来,之后要使用bean的话,直接从工厂拿即可。- 所以
beanDefinitionReader.loadBeanDefinitions(resource);就出现了。 - 万事俱备,可以从工厂中拿对象了
Student student = (Student)factory.getBean("student"); - 别忘记告诉工厂bean的唯一标识,就是xml文件中的id。这样活灵活现的对象就出来了。
- 总之, Spring管理Bean的流程如下:
- 先准备好定义Bean内容的资源(Resource)。
- 需要一个工厂来管理和创建Bean。
- 需要一个第三者,即BeanDefinitionReader来解析资源中Bean的定义,顺便将解析后的信息告诉工厂。
- 这样,算是使用Spring提供的组件将容器搭建好了。
可以说一说IoC和DI了
- IoC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。
- 曾经,对象的创建都是要程序员手动去new,现在用Spring反而不需要了,对象的创建都由Spring完成,往细了说,都由工厂去创建 ,创建对象的控制权由程序员变成了spring中的工厂。
别忘了,工厂也是对象,创建对象的控制权从人类转移到了工厂手上。即由对象创建和管理对象。
- 是程序主动去创建依赖对象;
- DI—Dependency Injection,即依赖注入,控制反转是通过依赖注入实现的,其实它们是同一个概念的不同角度描述。
- 组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。
- 下面的代码就是老师(Teacher)依赖学生(Student)。
public class Teacher {
private Student student;
}
Teacher需要使用Student对象提供的属性和方法,那student就必须实例化,所以Spring容器会将创建好的student对象注入到Teacher中。这样,Teacher中所依赖的student,Teacher就可以正常使用student了。
再次说明关于spring容器管理Bean的过程以及加载模式
- 需要将bean的定义信息声明在spring的配置文件当中。
- 需要通过spring抽象出的各种Resource来指定对应的配置文件。
- 需要显式声明一个spring工厂,该工厂用来掌控我们在配置文件中所声明的各种bean以及bean之间的依赖关系与注入关系
- 需要定义一个配置信息读取器(BeanDefinitionReader),该读取器用来读取之前所定义的bean配置文件信息。
- 读取器的作用是读取我们所声明的配置文件信息,并且将读取后的信息装配到之前所声明的工厂当中。
- 需要将读取器与工广以及资源对象进行相应的关联处理。
- 工厂所管理的全部对象装配完毕,可以供客户端直接调用,获取客户端想要使用的各种bean对象。