为什么有了Spring还需要SpringBoot?
那是因为Spring的编码需要配置很多模板化的配置,这些配置千篇一律。所以就诞生了SpringBoot,它很多配置都是约定俗称的。因此也有约定优于配置的说法。
在学习SpringBoot的时候碰到的障碍,其实都是Spring的障碍,因为SpringBoot是在Spring的基础上发展起来的。所以我们要排查这些障碍就需要了解Spring的发展过程。
Spring在2004年就出现,知道2014年Springboot才出现。这10年中Spring从纯配置文件到注解的方式是如何一步步变化的呢?下面来分解
它是全配置的一种方式来配置一个Application.xml的方式来配置扫描的路径、Bean类等等
这是时候出现了注解@Component @Controller 等等 。 通过这个注解可以简化我们Bean的编写方式,不用再配置文件中去配置了。当时这个是好我们的项目还是需要配置项目扫描的路径,因此在2.0的时候还是未能脱离配置文件的方式,只是简化了配置。
在3.0阶段可以开始脱离配置文件的方式。因为这个时候提供了一个@Configuration注解。这个注解相当于配置文件。在这个Config类中可以注入我们需要的Bean以及其他。但是这个阶段还是不能完全脱离配置文件,因为我们还是不能清除项目是从哪里开始扫描注解路径的。 因为还是需要借助于配置文件的Contest的compostscan。
这个阶段就是配置类+配置文件混合的一种方式,但是这个阶段提供了一个@import注解来进行过渡。
@Import注解提供了三种用法
@Import(MyClass.class)
public class ImportConfig {}
下面这两种方式可以实现动态加入的方式。因为我们可以加if…else的方式来加入对应的bean
public class MyImportRegistry implements ImportBeanDefinitionRegistrar{@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {RootBeanDefinition bd = new RootBeanDefinition();bd.setBeanClass(MyClassRegistry.class);registry.registerBeanDefinition("myClassRegistry", bd);}
}
public class MyImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[] {MyClassImport.class.getName()};}}
这个时候多了一个@ComponentScan注解,用来描述扫描的路径。不指定packages的话,默认是当前包以及子包下的路径。
因此在这个版本spring基本可以脱离配置文件的方式。
在这个阶段还提供了一些@Enablexxxx的注解以及@Conditionxxx的注解。第一个注解是将对应的Bean注入到容器中,而@ConditionXXX则是在满足条件的情况下才加入到容器中,否则不加入IOC容器。
当我们的Spring项目越来越大的时候,我们需要加快启动的方式,这个时候引入了一个新的注解@index 这个注解的方式需要配合Spring-Contex依赖才能生效,它会生成一个索引文件。用来启动的时候加快大型项目的启动。
上面将的就是Spring的一个发展过程,它的发展其实就是配置全面的向注解的过程。使得我们不再需要配置繁琐的模板化配置的。开发项目更加方便。
SPI全称Service Provider Interface,它是JDK内置的一种可以动态发现服务的机制。通过这种方式,可以方便地将服务提供者与第三方实现客户端解耦。它主要包含三个基本组件:服务接口,提供者注册API以及服务访问API。
Java SPI实际上就是“面向接口编程+策略模式+配置文件”组合实现动态加载机制,多用于各种框架中,通过暴露扩展点,实现对框架特定的点进行定制,提升框架灵活性。
public interface ProgramLanguage {String hello();
}
public class Chinese implements Language {@Overridepublic String hello() {return "你好";}
}public class English implements Language {@Overridepublic String hello() {return "Hello";}}
这里其实是两个项目中继承的类的方式来实现,以及编写第三部配置文件的操作。
创建/resources/META-INF/services,并在services文件夹下创建以接口全限定名称命名的文件,并在文件中写入实现类的全限定名
public class App {public static void main(String[] args) {ServiceLoader loader = ServiceLoader.load(Language.class);for (Language language : loader) {System.out.println(language.hello());}}
}
测试的时候引入的类是第二部中项目。
以上是深入了解SpringBoot的一些前置知识,在后续解读SpringBoot项目源码的时候能够一马平川。