2、SpringBoot 与 Spring 的千丝万缕

想要深入了解 SpringBoot,必须知道 Spring。我们可以从其命名 SpringBoot 中的关键字“boot”上,可以管中窥豹。“boot” 英文意思:启动。也就是说 SpringBoot 这个微服务框架设计的初衷,就是为了快速启动一个 Spring 应用。

自始至终,SpringBoot 框架都是为了能够帮助使用 Spring 框架的开发者高效快速的构建一个个基于 Spring以及 Spring 生态体系的应用解决方案。

所以要深刻理解 SpringBoot 框架,我们需要深刻理解 Spring 框架。

0、Spring 框架的起源

这一段我不想浪费笔墨过多赘述。例如:黑暗的 EJB 时代、基于各种容器和J2EE规范的统治时代等等。

这里着重介绍一个人:Rod Johnson。就是他和他的那本书给Java的开发迎来了曙光。

感兴趣的朋友,可以自己 Google 查询。

1、对 Spring 中IoC(控制反转)和DI(依赖注入) 的理解

Java日常的开发中,一个对象在需要其他的合作对象时,程序猿都要将合作对象创建出来(比如 new 对象),这个合作对象是由自己主动创建出来的。创建合作对象的主动权在自己手上,需要时候就主动创建,这样耦合性很高。(耦合性:A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起)。

但是在使用了Spring之后就不一样了,创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后存储到一个容器里面,当A对象需要使用B对象时,Spring就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用,至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题,A得到Spring给我们的对象之后,两个人一起协作完成要完成的工作即可。

基于以上观点,得出控制反转IoC(Inversion of Control)是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。

IoC其实有两种实现方式:

①DI(Dependency Injection):当前软件实体被动接受其依赖的其他组件被 IoC 容器注入。

②DL(Dependency Lookup):当前软件实体主动去某个服务注册地查找其依赖的那些服务。

通常提到的 Spring Ioc ,实际上是指 Spring框架提供的Ioc容器实现,而使用 Spring IoC容器的一个典型代码片段如下:

public class Application {
    public static void main(String[] args) {
        ApplicationContext context=new FileSystemXmlApplicationContext("....");
        MockService mockService = context.getBean(MockService.class);
        mockService.doSomething();
    }
}

任何一个使用 Spring 构建的独立 Java 应用,通常都会存在一行类似于“context.getBean(MockService.class);”的代码,实际上这段代码做的就是 DL 的工作,而构建的任何一种 IoC容器背后(BeanFactory 或者 ApplicationContext)发生的事情,则更多指的是 DI 的过程。

2、Spring 中IoC实现原理

Spring 的 IoC 容器中发生的可以总结为两个阶段:

① 收集和注册

此阶段可以认为是构建和收集 bean 定义的阶段,在这个阶段可以通过 XML 或者 Java 代码的方式定义一些 bean ,然后通过手动组装或者让容器基于某些机制自动扫描,将这些 bean 定义收集到 IoC 容器中,例如:

通过 XML 配置收集并注册单一的 bean

<bean id="mockService" class="com.rookie.MockServiceImpl">
   ...
</bean>

如果嫌逐个收集 bean 定义比较麻烦,想批量收集并注册到 IoC 容器中,可以通过 XML Schema 形式的配置进行批量扫描并采集和注册:

<context:component-scan base-package="com.rookie"/>

② 分析和组装

当收集和注册阶段完成后,可以暂且认为 IoC容器中充斥着一个个独立的 bean。实际上,它们之间是有依赖关系的,所以IoC 容器在第二个阶段就是分析这些已经存在于 IoC 容器中的 bean,根据它们之间的依赖关系先后组装它们。

如果 IoC 容器发现某个 bean 依赖另外一个 bean,它就会将这个bean注入给依赖它的bean,直到所有 bean 的依赖都注入完成,所有 bean 都“整装待发”,整个 IoC 容器的工作即算完成。

3、了解 JavaConfig

Java 5的推出,让我们可以基于纯注解进行依赖注入。

①表达式层面

基于 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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd
	http://www.springframework.org/schema/tx
	http://www.springframework.org/schema/tx/spring-tx.xsd">

	<!-- bean 的定义-->
    
</beans>

基于 JavaConfig 的配置方式如下:

@Configuration
public class MockConfiguration{

	// bean 的定义
}

②注册 bean 定义层面

基于 XML 的配置形式是如下:

<bean id="mockService" class="com.rookie.MockServiceImpl">
   ...
</bean>

基于 JavaConfig 的配置方式如下:

@Configuration
public class MockConfiguration{
	
    @Bean
    public MockService mockService(){
        
        return new MockServiceImpl();
    }
}

任何一个标注了 @Bean 的方法,其返回值将作为一个 bean 定义注册到 Spring 的 IoC 容器,方法名将默认成为该 bean 定义的 id。

③表达依赖注入关系层面

如果 bean 与 bean 之间有依赖关系,在 XML 形式中一般是如下形式:

<bean id="dependencyService" class="com.rookie.DependencyServiceImpl"/>

<bean id="mockService" class="com.rookie.MockServiceImpl">
	<property name="dependencyService" ref="dependencyService"/>
</bean>

JavaConfig中则是这样表达的:

@Configuration
public class MockConfiguration{
	
    @Bean
    public MockService mockService(){
        
        return new MockServiceImpl(dependencyService());
    }
    
    @Bean
    public DependencyService dependencyService(){
        
        return new DependencyServiceImpl();
    }
}

也就是说如果一个bean的定义依赖其他bean,则直接调用对应的 Javaconfig 类中依赖 bean 的创建方法即可

4、高人气的 Annotation

① @ComponentScan

@ComponentScan对应XML配置形式为<context:component-scan base-package="xxxxx"/>,配合比如 @Component、@Repository 等,即可将这些元信息注解的 bean 定义批量采集到 Spring 的 IoC 容器中。

base-package=“xxxxx”,是指自动扫描的范围。

@ComponentScan 亦是 SpringBoot 中一个很重要的组件。

② @PropertySource 和 @PropertySources

@PropertySource 用于从某些地方加载 *.property 文件内容,并将其中的属性加载到 IoC 容器中,以便于填充一些 bean 定义属性的占位符

@Configuration
@PropertySource("classpath:2.property")
@PropertySource("classpath:1.property")
@PropertySource(".....")
public class LoadConfiguration {
    ......
}

如果想声明多个 PropertySource ,则可以使用 @PropertySources

@Configuration
@PropertySources({
        @PropertySource("classpath:2.property"),
        @PropertySource("classpath:1.property")
        ....
})
public class LoadConfiguration {
    ......
}

③ @Import 和 @ImportResource

XML 形式配置中,可以通过的形式将多个分开的容器配置合到一个配置中,如果使用 JavaConfig ,可以如下所示:

@Configuration
@Import(MockConfiguration.class)
public class LoadLoadConfiguration {

	.........
}

@Import 只负责引入 JavaConfig 形式定义的 IoC 容器配置,如果有一些遗留的配置或者遗留系统需要以 XML 形式来配置,可以使用@ImportResource将其一起合并到当前 JavaConfig 配置的容器中。

@Configuration
@Import(MockConfiguration.class)
@ImportResource(".......")
public class LoadLoadConfiguration {

	.........
}

5、总结

此章内容回顾了 Spring 的框架一些基本内容,为下次 SpringBoot 的深入打基础。

参考文章如下:

浅谈对Spring IOC以及DI的理解:https://blog.csdn.net/luoyepiaoxue2014/article/details/72426666

如果只用过 SpringBoot 而没有使用过 Spring 搭建过环境的朋友,可以参考我以前的文章,可以对比下,以前的配置多么繁琐。

SSM基本配置:https://blog.csdn.net/CC1014524900/article/details/81713572

posted @ 2020-03-16 19:27  RookieMZL  阅读(255)  评论(0编辑  收藏  举报