结束了JVM的学习后,要进入的是JavaEE进阶的学习了。JavaEE进阶学习内容很多很丰富,并且也很有难度。今天我们就从Spring开始讲起。
目录
在讲Spring之前,我们讲讲为什么要学习框架。
框架总结出来就是三点:易用、简单、高效。
之前学习的Servlet,就是一个框架。我们接下来要学习的SpringBoot也是一个框架。相比于Servlet,SpringBoot就要方便很多了。
Servlet痛点:
1. 添加外部 jar 不方便,容易出错,比如添加了?个不匹配的外部 jar 版本;
2. 运行和调试的时候需要配置 tomcat 不方便;
3. 发布不方便,servlet 项?必须依靠外置的 tomcat(外置的 web 容器)运行。
4. 路由配置不方便,?个访问地址对应?个 Servlet 类。?
这一些问题可能也不是什么大问题,但是某些方面是很影响效率的,一处不方便,处处不方便。
接下来我们学习的新知识就可以一步一步解决掉这一些痛点。
- 先从基础框架 Spring 开始(工具箱)
- Spring Boot 快速开发 Spring 脚手架
- MyBatis 快速操作数据库
- 其他:日志、事务、拦截器...
介绍完了框架,我们就从最基础的Spring讲起。
我们通常所说的 Spring 指的是 Spring Framework(Spring 框架),它是?个开源框架,有着活跃而庞大的社区,这就是它之所以能长久不衰的原因。Spring ?持广泛的应用场景,它可以让 Java 企业级 的应用程序开发起来更简单。
用一句话来概括Spring:
Spring是包含了众多工具方法的IoC容器。
容器,是用来容纳某种物体的。之前我们接触的容器有哪些?
List/Map:数据存储容器
Tomcat:Web容器
那么Spring也是一个容器,是一个IoC容器。
IoC,翻译过来就是“控制反转”。也就是说Spring是一个控制反转的容器。
传统程序:
我们现在要构造一辆车(Car Class),而车需要依赖车身(Framework Class),车身需要依赖底盘(Bottom Class),底盘需要依赖轮胎(Tire Class),最终实现的代码:
可以看到,通过方法的层层调用,最后才实现Tire中的结果。这样的坏处就是,代码之间高度耦合,如果需要修改底层代码,整个调用链上的代码都需要修改。
我们把调用汽车的程序示例改造?下,把创建子类的方式,改为注入传递的方式,具体实现代码如下:
代码经过以上调整,无论底层类如何变化,整个调用链是不用做任何改变的,这样就完成了代码之间的解耦。
在传统的代码中对象创建顺序是:
Car -> Framework -> Bottom -> Tire
改进之后解耦的代码的对象创建顺序是:
Tire -> Bottom -> Framework -> Car
我们发现了?个规律:通用程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了 Framework,Framework 创建并创建了 Bottom,依次往下,从改进之后的控制权发生的反转,不再是上级对象创建并控制下级对象了,而是下级对象把注入将当前对象中,下级的控制权不再由上级类控制 了,这样即使下级类发生任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。
既然 Spring 是?个 IoC(控制反转)容器,重点还在“容器”二字上,那么它就具备两个最基础的功 能:
- 将对象存入到容器
- 从容器中取出对象
也就是说,学Spring最核心的功能,就是如何将对象存到Spring中,并且再从Spring中取出来。
那么Spring是一个IoC容器,说的就是对象的创建和销毁都交给Spring来管理,同时Spring又具备了存储对象和获取对象的能力。
DI,就是依赖注入。
是由 IoC 容器在运行期间,动态地将某种依赖关系注入到对象之中。所以,依赖注入(DI)和控制反转(IoC)是从不同的?度的描述的同?件事情,就是指通过引入?IoC 容 器,利用依赖关系注?的方式,实现对象之间的解耦。
IoC和DI之间的区别是什么呢?
IoC是一种思想,而DI是实现这种思想的具体方法。
Spring项目的创建用Maven的方式。当导入相关的包后,就说明有了Spring的依赖,也就可以使用Spring相关的操作了。
在IDEA的设置中(当前项目设置和新项目设置)都要修改相关的用户设置文件。
首先是因为Spring的仓库在国外,我们把相关的配置源改成阿里云或者网易云。这样下载依赖的时候就不会因为网络环境报错了。
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
?在pom.xml中也需要添加相关的spring依赖。
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version>
</dependency>
以前的对象我们是自己new出来的,现在的对象我们称为bean对象,让Spring来帮助我们生产bean对象。
在resources中新建一个xml文件,作为spring的配置文件。
在配置文件中添加如下代码:
<?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">
</beans>
我们先在Student类中创建student对象。
package com.spring.demo;
public class Student {
public void sayhi() {
System.out.println("hi");
}
}
假设我们需要一个student这样一个Bean对象,只需要把这个对象添加到配置文件中。
<?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.demo.Student"></bean>
</beans>
也就是最后一句代码。这代表着id为student,class为student所在类注册到bean中。
Spring的上下文对象可使用ApplicationContext来获取:
ApplicationContext context = new ClassPathXmlApplicationContext("spring_config.xml");
其中最后需要保证配置文件的名称和之前创建的相同。通过ApplicationContext来获取到Spring上下文。
同时还可以使用BeanFactory来作为Spring的上下文:
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring_config.xml"));
ApplicationContext 和 BeanFactory 效果是?样的,ApplicationContext 属于 BeanFactory 的? 类,它们的区别如下:
继承关系和功能方面来说:Spring 容器有两个顶级的接口:BeanFactory 和 ApplicationContext。其中 BeanFactory 提供了基础的访问容器的能力,而ApplicationContext 属于 BeanFactory 的子类,它除了继承了 BeanFactory 的所有功能之外,它还拥有独特的特性, 还添加了对国际化支持、资源访问支持、以及事件传播等方面的?持。
从性能方面来说:ApplicationContext 是?次性加载并初始化所有的 Bean 对象,而BeanFactory 是需要那个才去加载那个,因此更加轻量。
对于我们使用来说,ApplicationContext会在启动的时候把所有的Bean实例化,而BeanFactory是惰性加载,只有从容器中拿Bean的时候才会去实例化。
ApplicationContext context = new ClassPathXmlApplicationContext("spring_config.xml");
Student student = (Student) context.getBean("student");
ApplicationContext context = new ClassPathXmlApplicationContext("spring_config.xml");
Student student = context.getBean("Student.class");
ApplicationContext context = new ClassPathXmlApplicationContext("spring_config.xml");
Student student = context.getBean("student",Student.class");
三种方式获取到Bean对象。
第一种,虽然是最简单最好理解的,但是需要强制类型转换(从Object转成Student),可能会出现某些bug,毕竟叫做强制类型转化,强制过来的终归有些不好。
第二种和第三种,区别在于:如果有一个类型被重复注册到xml中时,只能根据第三种获取。
直接使用对象的方法:
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring_config.xml");
Student student = (Student) context.getBean("student");
student.sayhi();
}
关于这部分内容,我们下一篇文章再详细讲解。