简介:
springBoot是spring团队为了整合spring全家桶中的系列框架做研究出来的一个轻量级框架。随着spring4.0推出而推出,springBoot可以説是J2SEE的一站式解决方案。在springboot之前如果需要开发一个大型的spring项目,可能需要掌握很多spring全家桶中的知识,但是springBoot出现后,开发人员只需要少量的配置就能实现项目的开发,因为springBoot已经帮我们把一些常用的配置集合封装好了,开发人员只需要非常少的代价就能打开J2EE企业级的大门。- 简化Spring应用开发的一个框架;
- 整个Spring技术栈的一个大整合;
- J2EE开发的一站式解决方案;
优点:
- 快速创建独立运行的Spring项目以及与主流框架集成
- 使用嵌入式的Servlet容器,应用无需打成WAR包
- starters自动依赖与版本控制
- 大量的自动配置,简化开发,也可修改内部配置的默认值
- 无需配置XML,无代码生成,开箱即用
- 准生产环境的运行时应用监控 与云计算的天然集成
缺点:
入门容易精通难
微服务:
微服务是一种架构风格,强调在开发一个应用的时候,这个应用应该是一个小型服务的集合,每个小型服务运行在自己的进程内,这些小型服务通过http方式进行通信。
之前存在一种一个单体应用,即将所有的应用放在一个工程中,然后将它打成jar包,部署到服务器上(tomcat),这种开发测试简单,部署也简单,水平扩展也很容易。但是有一个最致命的问题就是牵一发动全身,虽然后来出现的分布式,,通过多个服务器复制单体进行扩展,但是并没有解决根本问题。并且随着需求的越来越大,每个小的应用也越来越大,所有的应用都集成到一起将会非常的庞大,所以开始有了微服务架构。
微服务可以通过各个应用的动态组合实现不同的工程功能,比如有的应用比较重要,可能需要在每一个服务器上都进行构建,但是有的应用并不重要可能值部署到其中一台服务器上。
每一个功能元素最终都是一个可独立替换和独立升级的软件单元;
微服务中的每个功能元素都是一个完整的功能单元,可能每一个功能项目都需要整合各种场景,一旦整个工程项目非常庞大,需要很多的功能单元,那每一功能单元都需要进行项目的创建与环境整合,如果按照以前的创建项目的方式,我们将会浪费很长时间去创建项目,但是SpringBoot出现之后,就可以应用SpringBoot来进行构建,SpringBoot是一个轻量级框架。每个小的应用元素使用springBoot进行快速创建,各个元素之间使用springCloud进行连接整合,进行网上互连互调,把整个工程的应用模式做出来,那么在整个分布式中间可能需要数据的流式计算批处理等,就可以应用到SpringCloud Data Flow。
所以应用springBoot可以快速的构建一个微服务单元。
入门:
项目搭建详情见博客:SpringBoot项目搭建
解析内部
依赖说明
1. 父项目
依赖中导入父项目:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
查看源码可知这个父项目的父项目是:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath>../../spring‐boot‐dependencies</relativePath>
</parent>
dependencies:这是一个springBoot的版本仲裁中心,以后我们导入的jar包依赖默认是不写版本的(没有在dependencies中管理的依赖还是需要声明版本)
2. 启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
</dependency>
spring-boot-starter:是spring-boot场景启动器;帮我们导入了web模块正常运行所依赖的组件;
Spring Boot将所有的功能场景都抽取出来,做成一个个的starters(启动器),只需要在项目里面引入这些starter相关场景的所有依赖都会导入进来,相关技术的大部分配置将会消除。要用什么功能就导入什么场景的启动器。
这些starters几乎涵盖了javaee所有常用场景,Spring Boot对这些场景依赖的jar也做了严格的测试与版本控制。我们不必担心jar版本合适度问题。
具体需要的启动器可参考:启动器
入口类执行原理
/**
* @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
*/
@SpringBootApplication
public class SpringBootMainApplication {
public static void main(String[] args) {
//spring应用启动起来
SpringApplication.run(SpringBootMainApplication.class,args);
}
}
1. @SpringBootApplication
该注解是SpringBoot应用注解,它标注在某个类上说明这个类就是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
注意:主方法内部应用springApplication方法来加载运行类,一定要把标注该注解的类文件作为参数传进去。
@SpringBootApplication注解按照源码点击进去后会发现其内部也标注了很多注解,即该注解是一个复合注解,使用一个相当于使用其内部三个注解的功能:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
其中前四个注解就是我们非常熟悉的元注解(标识该类是作为一个注解使用,并写明相关属性):
@Target 注解:指明了修饰的这个注解的使用范围,即被描述的注解可以用在哪里。
ElementType 的取值:
- TYPE:类,接口或者枚举;
- FIELD:域,包含枚举常量;
- METHOD:方法;
- PARAMETER:参数;
- CONSTRUCTOR:构造方法;
- LOCAL_VARIABLE:局部变量;
- ANNOTATION_TYPE:注解类型;
- PACKAGE:包;
@Retention 注解:指明修饰的注解的生存周期,即会保留到哪个阶段。
RetentionPolicy 的取值:
- SOURCE:源码级别保留,编译后即丢弃。
- CLASS:编译级别保留,编译后的class文件中存在,在jvm运行时丢弃,这是默认值。
- RUNTIME:运行级别保留,编译后的class文件中存在,在jvm运行时保留,可以被反射调用。
@Documented 注解:表示该注解是否可以生成到 API文档中,在该注解使用后,如果导出API文档,会将该注解相关的信息可以被例如javadoc此类的工具文档化。
@Inherited注解:允许子类继承父类中的注解。
假设一个注解在定义时,使用了@Inherited,然后该注解在一个类上使用,如果这个类有子类,那么通过反射我们可以从类的子类上获取到同样的注解。
后三个注解,@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan是@SpringBootApplication注解继承来的,下面单独讲解其功能;
2. @SpringBootConfiguration
这个注解类上有@Configuration注解标识,@Configuration是Spring 3.0时添加的一个注解(该配置类也是容器中的一个组件),用来代替 applicationContext.xml 配置文件,所有这个配置文件里面能做到的事情都可以通过这个注解所在类来进行注册。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
@SpringBootConfiguration继承自@Configuration,二者功能也一致,标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名。
3. @EnableAutoConfiguration
该注解是一个核心注解,用于开启自动配置功能,其内部提供了强大的自动依赖功能,是SpringBoot这么方便的大功臣。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
这个注解也是一个复合注解。
(1) AutoConfigurationPackage
翻译成人话就是自动配置包,把入口类所在包下的所有文件进行扫描匹配,装进spring容器:
该注解主要的功能实现是由@Import({Registrar.class})来实现的。
Import注解也是Spring的底层注解,它用来给spring容器中导入一个组件,导入的组件由Registrar.class内部指定。
Registrar.class这个类中有一个非常重要的静态内部类,用来将主配置类(@SpringBootApplication标注的类)所在包及下面所有子包里面的所有组件扫描到Spring容器中;
(2) @Import({AutoConfigurationImportSelector.class})
他存在的作用就是给容器中导入一些组件,具体哪些组件由AutoConfigurationImportSelector.class选择(spring对J2EE中整合好的组件)。
AutoConfigurationImportSelector的意思就是开启自动配置类的导包的选择器(导入哪些组件的选择器)
那么到底需要导入哪些配置类,代码运行是怎么知道的呢(也就是上面图片中的configurations参数内容) ,这就用到了该类中的另一个方法getCandidateConfigurations。
该方法中调用了SpringFactoriesLoader类中的loadFactoryNames方法:
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader)
它的作用总结就是:
1、扫描所有jar包类路径下 META‐INF/spring.factories。
2、把扫描到的这些文件的内容包装成properties对象。
3、从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中。
Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将
这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;以前我们需要自己配置的东西,自动配置类都帮我们;
J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-1.5.9.RELEASE.jar;
自动配置原理
以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理。
@Configuration
@EnableConfigurationProperties(HttpProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
1. Configuration
表明这是一个配置类,和以前编写的配置文件一样,可以给容器中添加组件
@EnableConfigurationProperties
启动指定类的ConfigurationProperties功能,这里开启的是HttpProperties类的ConfigurationProperties功能。将配置文件中对应的值和HttpEncodingProperties绑定起来。
所有的配置文件(这里只的是yml文件)中能配置的属性都是在xxxxProperties类(这里是HttpProperties.class)中封装着,配置文件能配置什么 就可以参照某个功能对应的这个属性类。
2. @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
spring底层有一个@Conditional注解,它会根据不同条件判断,如果满足指定的条件,整个配置类就会生效。
在这里判断的是当前应用是否是web应用,如果是,当前配置类生效。
3. @ConditionalOnClass(CharacterEncodingFilter.class)
判断当前项目有没有CharacterEncodingFilter这个类,这个类是springmvc中进行乱码解决的过滤器。
4. @ConditionalOnProperty(prefix = “spring.http.encoding”, value = “enabled”, matchIfMissing = true)
判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的;
即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
@Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
@EnableConfigurationProperties(HttpProperties.class)//启动指定类的ConfigurationProperties功能;
将配置文件中(本类中)对应的值和HttpProperties绑定起来;并把HttpProperties加入到ioc容器中。
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)//Spring底层@Conditional注解(Spring注解版),根据不同的条件,如果
满足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnClass(CharacterEncodingFilter.class)//判断当前项目有没有这个类CharacterEncodingFilter;
SpringMVC中进行乱码解决的过滤器。
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
//判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的。
//即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
public class HttpEncodingAutoConfiguration {
//他已经和SpringBoot的配置文件映射了
private final HttpProperties.Encoding properties;
//只有一个有参构造器的情况下,参数的值就会从容器中拿
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
@Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取
@ConditionalOnMissingBean //判断容器有没有这个组件
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
根据当前不同的条件判断,决定这个配置类是否生效。一但这个配置类生效;这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
5. 精髓
1.SpringBoot启动会加载大量的自动配置类
2.我们看我们需要的功能有没有SpringBoot默认写好的自动配置类;
3.我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了)
4.给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值;
xxxxAutoConfigurartion:自动配置类;给容器中添加组件;
xxxxProperties:封装配置文件中相关属性;
6. 细节
@Conditional派生注解:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;自动配置类必须在一定的条件下才能生效;
我们怎么知道哪些自动配置类生效?我们可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;
=========================
AUTO‐CONFIGURATION REPORT
=========================
Positive matches:(自动配置类启用的)
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
DispatcherServletAutoConfiguration matched:
‐ @ConditionalOnClass found required class
'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find
unwanted class (OnClassCondition)
‐ @ConditionalOnWebApplication (required) found StandardServletEnvironment
(OnWebApplicationCondition)
Negative matches:(没有启动,没有匹配成功的自动配置类)
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
ActiveMQAutoConfiguration:
Did not match:
‐ @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory',
'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)
AopAutoConfiguration:
Did not match:
‐ @ConditionalOnClass did not find required classes
'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (OnClassCondition)
使用Spring Initializer快速创建
IDE都支持使用Spring的项目创建向导快速创建一个Spring Boot项目;
选择我们需要的模块;向导会联网创建Spring Boot项目;
默认生成的Spring Boot项目;
主程序已经生成好了,我们只需要我们自己的逻辑;
resources文件夹中目录结构:
static:保存所有的静态资源; js css images;
templates:保存所有的模板页面;(Spring Boot默认jar包使用嵌入式的Tomcat,默认不支持JSP页面);可以使用模板引擎(freemarker、thymeleaf);
application.properties:Spring Boot应用的配置文件;可以修改一些默认设置;