Spring 起步
一、Spring容器理解
1、Spring的核心是提供了一个容器(container),也就是通常所称的Spring应用上下文(Spring application context)。他会帮你创建组件,以及管理组件之间的关系并实现自动装配,并且管理它们的整个生命周期。组件也称为bean,也就是类的实例。
2、为什么需要Spring容器帮你自动创建和自动装配组件?
我们自己也可以new一个啊,为什么要用Spring容器来创建呢?其实和数据库链接池一样,我们自己也可以创建数据库链接啊,为什么现在都是要用数据库链接池来管理呢?Spring容器其实就相当于类的实例池,他可以帮你来管理实例的整个生命周期。
大部分情况下,系统里面的每个类都只需要实例化一次即可,如果你自己创建,你就需要判断那个要用的Object有没有,没有才创建。但有时,对于一些Object可能每次都需要一个新的实例。两种策略之间,也许是某种“池化Object“的特定的逻辑,比如连接池只能有100个Connection Object。每个对象要初始化,获取一些资源,也可能某些时候释放一些资源。这些都是对Object生命周期管理的逻辑。如果没有注入机制,那么这些逻辑会散播到整个系统每一个角落,带来巨大的维护问题。
3、Spring依赖注入本质
用Spring写的程序启动时会优先启动Spring的一个加载器,加载器会自动识别依赖关系,按照树形结构依次创建那些Bean。万一发生了依赖循环,Spring能自己检测出来并报错。这就把程序员关于系统里Object怎么初始化,管理和相互引用的工作量降到最低。
Spring的依赖注入本质其实就是一个全局的大KV,K是类名,V是new出来的实例。具体的创建过程如下:
1)创建这个大KV
2)根据类的依赖关系创建第一个没有任何依赖的Object,并记录到大KV里
3)创建其他Object,如果创建时需要依赖已经创建好的Object,就从KV里取出来直接用
4)所有的Object都创建完了,服务就可以启动了
使用spring进行动态依赖注入的好处:在初始化实例的过程中可以绕开访问权限,直接注入private成员,方便编码和测试;动态产生代码以实现AOP;还有最玄幻的AutoConfiguration。Spring能根据当前能加载的Bean有哪些来决定如何初始化一些业务功能。比如启动时,如果classpath里有HSQLDB,而开发者并没有手工配置数据源的类型,那么Spring就会帮你创建一个HSQLDB的内存数据源,来应对那些需要注入DataSource的地方。Spring会用类似的办法帮你决定controller的返回是变成json还是xml,mvc里到底用哪套模版引擎,监控数据到底输出哪些metrics等等。
4、Spring动态依赖注入的bean只能以单例模式存在吗?
Spring默认都是以单例模式实例化的,就是说在整个Spring应用中,bean的实例只有一个。当然也可以通过@Scope注解实现多实例模式。甚至还还可以借助org.springframework.beans.factory.config.Scope接口用于定义scope的行为。具体的scope类型有如下几种:
1)singleton 每个 Spring 容器一个实例(默认值)
2)prototype 允许 bean 可以被多次实例化(使用一次就创建一个实例)
3)request 定义 bean 的 scope 是 HTTP 请求。每个 HTTP 请求都有自己的实例。只有在使用有 Web 能力的 Spring 上下文时才有效
4)session 定义 bean 的 scope 是 HTTP 会话。只有在使用有 Web 能力的 Spring
ApplicationContext 才有效
5)application 定义了每个 ServletContext 一个实例
6)websocket 定义了每个 WebSocket 一个实例。只有在使用有 Web 能力的 Spring ApplicationContext 才有效
参考: blog.csdn.net/m0_38125704… waylau.com/custom-scop…
5、哪些情况下依旧需要自己创建和销毁实例?
如果需要自己处理有状态的实例,比如并发情况下的处理,那就需要自己进行管理。
6、Spirng自动扫描、自动配置的代码实现
自动扫描:只需要在类上面加注解即可,Spring会自动发现加了@Component、@Controller、@Service这些注解的类,并将它们注册到Sring容器中。
自动配置:只需要在类的成员变量上面加@Autowire注解即可,Spring在初始化这个类的时候就会自动地将相关的类注入进来。
早期需要通过xml配置文件或者configuration配置类方式硬编码各个类之间的注入关系,但是现在基本上不需要显示配置依赖关系了,spring boot已经能够基于类路径中的关系、环境变量和其他因素合理判断需要配置的组件并将它们装配在一起。
二、Spring boot应用程序创建
1、Maven构件引入
1)Spring boot提供了spring-boot-starter-parent父构件,在POM文件的parent标签引入,此构件指定版本号后,后续其他spring-boot-starter相关的构件在引入时都不需要指定版本号,maven会根据spring-boot-starter-parent里面指定的相关依赖关系和版本号进行处理。spring-boot-starter-parent的版本号一般取当前maven仓库里面的最大版本号即可。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
</parent>
2)maven仓库地址:mvnrepository.com/
进入后,在搜索框输入构件名称,可以进行模糊查询,点击某一版本的构件后,可以提供maven构件依赖的引入内容,直接复制到代码里面黏贴即可,注意在启用了spring-boot-starter-parent版本号管理后去掉具体具体每一个构件的版本号。
3)常用的spring-boot-starter构件有:
<!-- web网站或者restful接口访问需要 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 单元测试需要 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
注意:spring-boot-starter构件本身并不包含库代码,而是传递性的拉取其依赖的其他代码,这样的好处是方便管理实现一个功能需要依赖的所有构件,依赖的库代码显著减少;另外可以根据starter的名称来迅速了解具体用途;而且其传递性引入的构件版本肯定是兼容的,不需要考虑各个构件的版本兼容性问题。
4)最后还需要引入一个Spring boot插件。 该插件提供了一个Maven goal,允许使用maven来运行应用;另外它会在jar中生成一个manifest文件,将引导类申明为可执行的jar主类(一般是main方式所在类)。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.0.RELEASE</version>
</plugin>
</plugins>
</build>
- 应用启动引导类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringTestApplication {
public static void main(String[] args){
SpringApplication.run(SpringTestApplication.class,args);
}
}
注意:
1)@SpringBootApplication是一个组合注解,包含了@SpringBootConfiguration(声明为配置类)、@ComponentScan(启用组件扫描)、@EnableAutoConfiguration(启用自动装配)。
2)SpringApplication是Spring的一个启动类,其中的静态方法run会执行如下操作:
3. **单元测试实现**