SpringBoot编程思想
Spring Boot的特性
1)、创建独立的Spring应用
2)、直接嵌入Tomcat、Jetty或Undertow等Web容器(不需要部署WAR文件)
3)、提供固化的starter依赖,简化构建配置和依赖管理
4)、当条件满足时自动地装配Spring或第三方类库
5)、提供运维(Production-Ready)特性,如指标信息(Metrics)、健康检查及外部化配置
6)、绝无代码生成,并且不需要XML配置
即约定大于配置,简化开发。
为什么说是独立的Spring应用?
SpringBoot应用无需再向传统的JavaEE应用那样,将应用打包成WAR文件或者JAR文件,并部署到JavaEE容器中运行(虽然其也支持)。
SpringBoot应用采用嵌入式Web容器,独立于外部容器,对应用生命周期拥有完全自主的控制。
在传统的Spring应用中,外置容器需要启动脚本将其引导(如ContextLoaderListener),随其生命周期回调执行Spring上下文的初始化。比较代表性的是Spring Web中的
ContextLoaderListener和Web MVC中的DispatcherServlet,前者利用ServletContext生命周期构建Web ROOT Spring应用上下文,后者结合Servlet生命周期创建DispatcherServlet
的Spring应用上下文。无论何种方式,均属于被动的回调执行,这也是为什么它们没有完整的应用主导权的原因。
当Spring Boot出现嵌入式容器启动方式后,嵌入式容器则称为应用的一部分,从本质上来说,它属于Spring应用上下文的组件Beans,这些组件和其他组件均由自动装配
特性Spring Bean定义(BeanDefinition),随Spring应用上下文启动而注册并初始化。而驱动Spring应用上下文启动的核心组件则是Spring Boot核心API SpringApplication,
所以是Spring应用,也可以称为SpringBoot应用。
理解自动装配
SpringBoot引导类:
//@ImportResource 导入xml配置文件
@SpringBootApplication public class SpboApplication { public static void main(String[] args) { SpringApplication.run(SpboApplication.class, args); } }
@SpringBootApplication注解:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Configuration @EnableAutoConfiguration @ComponentScan //SpringBoot会自动扫描当前类的同级包以及下级包里的Bean,并自动注入到Spring容器中 public @interface SpringBootApplication { /** * Exclude specific auto-configuration classes such that they will never be applied. * @return the classes to exclude */ Class<?>[] exclude() default {}; /** * Exclude specific auto-configuration class names such that they will never be * applied. * @return the class names to exclude * @since 1.3.0 */ String[] excludeName() default {}; /** * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses} * for a type-safe alternative to String-based package names. * @return base packages to scan * @since 1.3.0 */ @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; /** * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to * scan for annotated components. The package of each class specified will be scanned. * <p> * Consider creating a special no-op marker class or interface in each package that * serves no purpose other than being referenced by this attribute. * @return base packages to scan * @since 1.3.0 */ @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class<?>[] scanBasePackageClasses() default {}; }
可以看到@SpringBootApplication注解是一个组合注解
相当于@Configuration、@EnableAutoConfiguration、@ComponentScan的累加
@EnableAutoConfiguration:激活Spring Boot自动装配机制
@ComponentScan:激活@Component的扫描
@Configuration:声明被标注为注解类
同时,其属性方法带有@AliasFor注解,用于桥接其他注解的属性。
@EnableAutoConfiguration注解可以帮我们自动载入应用程序所需要的所有默认配置
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { /** * Exclude specific auto-configuration classes such that they will never be applied. * @return the classes to exclude */ Class<?>[] exclude() default {}; /** * Exclude specific auto-configuration class names such that they will never be * applied. * @return the class names to exclude * @since 1.3.0 */ String[] excludeName() default {}; }
此注解有两个重要的注解:
@Import:向Spring容器中导入了EnableAutoConfigurationImportSelector组件
@AutoConfigurationPackage:自动配置包
1):@AutoConfigurationPackage:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { }
发现还是依靠Import注解导入了AutoConfigurationPackages.Registrar组件,其代码为:
/** * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing * configuration. */ @Order(Ordered.HIGHEST_PRECEDENCE) static class Registrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, ClassUtils.getPackageName(metadata.getClassName())); } }
其作用是将主配置类(@SpringBootApplication)的所在包及其子包里面的组件扫描到Spring容器中。比如带有@Entity注解的组件,由
@AutoConfigurationPackage扫描并加载,而平时常用的@Controller/@Service/@Component/@Repository这些注解是由ComponentScan
来扫描并加载的。
2):EnableAutoConfigurationImportSelector组件
会在Spring启动的时候扫描所有jar路径下的META-INF/Spring.factories,然后筛选出以EnableAutoConfiguration为key的数据,加载到IOC
容器中,最后会默认加载113个默认的配置类,实现自动配置功能。
理解约定大于配置
即通过约定来减少配置。约定优于配置是一个简单的概念。系统、类库、框架应该假定合理的默认值,而非要求提供不必要的配置。
大部分情况下,使用框架提供的默认值会让你的项目开发起来效率更快。如:
在Spring Boot中,当我们导入一个spring-boot-starter-web后。就会自动地帮我们导入Spring MVC的相关依赖(包括Json支持的Jackson和数据校验的HibernateValidator)
和一个内置的Tomcat容器,这使得开发阶段可以直接通过main方法或者JAR包独立运行一个WEB项目。因为Spring Boot约定,当你导入了一个spring-boot-starter-web后,
就约定了你是一个web开发环境。
获取属性配置文件的Properties
在常规的Spring环境下,注入properties文件里的值要通过@PropertySource指明properties文件的位置,然后通过@Value注入值,在SpringBoot里,只需要在application.properties
定义属性,直接使用@Value注入即可。但是如果我们的配置比较多的话,则@Value会注入很多次。所以SpringBoot还提供了基于类型安全的配置方式,通过@Configurationproperties
将properties属性和一个Bean及其属性关联,从而实现类型安全的配置。
// 将前缀为self的属性配置和bean关联起来,使用时直接依赖注入此bean即可 @Component @ConfigurationProperties(prefix = "self") public class SelfProperties { private String name; private Long age; get set... }