SpringBoot自动配置原理解析 | 京东物流技术团队
1: 什么是SpringBoot自动配置
首先介绍一下什么是SpringBoot,SpringBoost是基于Spring框架开发出来的功能更强大的Java程序开发框架,其最主要的特点是:能使程序开发者快速搭建一套开发环境。SpringBoot能将主流的开发框架(例如SpringMVC,Dubbo,Mybatis,Redis等),做到像Maven导入Jar包一样的简洁快速,做到开箱即用。其中最关键的技术就是SpringBoot定制的各种Starter,通Maven引入Starter就能快速搭建开发环境。
2: SpringBoot Starter自动装配案例
在以前单独使用SpringMVC Web编程框架时,我们需要单独配置DispatcherServlet和Tomcat,使用SpringBoot之后,我们只需要引入SpringBoot-Starter-Web就能直接开始编写Controller等Web相关的代码,这就是SpringBoot为们提供的开箱即用的便捷能力,下面就以SpringBoot-Starter-Web来说明SpringBoot自动配置的关键原理
3: SpringBoot自动装配案例源码解析
3.1 DispatcherServlet的自动配置原理
首先我们定位到SpringBoot自动配置的Maven依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>${spring-boot.version}</version> </dependency>
在依赖的Jar包中我们可以在META-INF/spring.factories中找到自动配置类:
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
在这个类中存在有一个静态内部类:
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration.DispatcherServletConfiguration
下图是这个配置类的主要源码和解析:
下面将上图中关键的注解功能,分别进行功能说明
3.1.1:@EnableConfigurationProperties({WebMvcProperties.class})注解解析
这个注解表示使WebMvcProperties.class类上的@ConfigurationProperties这个注解生效,同时@ConfigurationProperties这个注解是将application.xml中以spring.mvc开头的配置参数自动注入到WebMvcProperties.class类的字段中
3.1.2:@Conditional({DefaultDispatcherServletCondition.class}注解解析
该注解的原理就是将满足特定条件情况下的Bean自动加载到Spring容器中,该注解对应的Spring接口就是org.springframework.context.annotation.Condition这个接口
public interface Condition { boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2); }
3.1.3:@ConditionOnClass注解解析
@ConditionOnClass这个注解是在当程序代码环境classpath下存在xxx.class的情况下条件成立,同时最终也会调用到matches方法中,其中关键的源码如下:
protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException { return classLoader != null ? Class.forName(className, false, classLoader) : Class.forName(className); }
从上面可以看到,代码利用Class.forName方法加载classpath下的xxx.class类,如果加载成功条件就会成立。最后,在满足了所有@ConditionOnal注解条件后,SpringBoot就会自动为我们在Spring容器中注入DispatcherServlet了,无需单独配置了,直接引入spring-boot-starter-webr即可开始使用web相关功能。
3.1.4:总结
我们以DispatcherServlet是如何自动配置到容器中为例,探究了SpringBoot Starter的自动配置原理,其中涉及了几个关键的注解和步骤:
第一步:涉及到了配置文件的读取和个性化配置,这里就涉及到了下面这两个注解
@ConfigurationProperties @EnableConfigurationProperties
第二步:设计到了在什么条件下才自动配置的注解
@Conditional @ConditionalOnClass
第三步:约定了自动配置类的加载路径
/META-INF/spring-factories org.springframework.boot.autoconfigure.EnableAutoConfiguration=自动配置类全路径名称
在我们了解到了SpringBoot自动配置的原理之后,我们就可以自定义一个SpringBoot Starter来快速搭建我们的开发环境了
4:自定义一个打印输入输出日志的Starter
4.1 首先定义一个标记需要打印出入参日志的注解@PrintLog
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface PrintLog { }
4.2 定义一个存放打印日志配置的实体类
//自动注入application配置文件中已log.switch开头的配置参数 @ConfigurationProperties("log.switch") public class LogProperties { //是否启用打印日志功能 private Boolean enabled = false; //是否打印调用者ip private Boolean printIp = false; //是否打印调用者url private Boolean printUrl = false }
4.3 定义一个@PrintLog注解的切面类
@Aspect public class LogAspect { private static final Log LOGGER = LogFactory.getLog(LogAspect.class); private LogProperties logProperties; @Pointcut("@annotation(com.zl.annotation.PrintLog)") public void Log(){} @Around("Log()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); String methodName = method.getName(); //打印调用url if (Boolean.TRUE.equals(logProperties.getPrintUrl())){ LOGGER.info("URL:" + request.getRequestURL().toString()); } //打印ip if (Boolean.TRUE.equals(logProperties.getPrintIp())) { LOGGER.info("IP :" + request.getRemoteAddr()); } //打印方法 LOGGER.info("method :" + methodName); //打印参数 LOGGER.info("parameter :" + Arrays.toString(joinPoint.getArgs())); Object result = joinPoint.proceed(); //打印返回结果 LOGGER.info("return :" + JSON.toJSONString(result)); return result; } }
4.4 定义一个打印日志的自动配置类
@Configuration @EnableConfigurationProperties({LogProperties.class}) //表示在application配置文件中必须配置log.switch.enabled = true才启动自动配置 @ConditionalOnProperty(prefix = "log.switch", value = "enabled", havingValue = "true") public class LogAutoConfigure { @Bean //Advice.class是aop切面中关键的切面方法类(@Before,@After等) //程序中有Advice.class类说明需要使用切面功能,这时才加载自定义的切面类 @ConditionalOnClass(Advice.class) public LogAspect webLogAspect(LogProperties logProperties){ return new LogAspect(logProperties); } }
@ConditionalOnProperty表示在application配置文件中必须存在相应的配置才能使条件成立
4.5 配置自定义配置类的加载路径
META-INF/spring.factories org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.zl.autoConfigure.LogAutoConfigure
4.6 Maven打包部署
maven install
5:开始使用自定义的Starter
5.1 在项目中引入Starter
<dependency> <groupId>com.zl.demo</groupId> <artifactId>LogStarter</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
5.2 在application.yml中配置参数
log: switch: enabled: true //启用打印日志功能 printIp: true //打印请求ip printUrl: true //打印请求url
经过上面两个步骤就,打印日志的功能就已经开启了,接下来就可以进行编码测试了
5.3 定义一个Controller并标上打印日志的注解
@RestController @RequestMapping("/test") public class HelloWorldController { @PrintLog @RequestMapping("/hello") public String helleWorld(String test){ return "hello world!"; } }
5.4 启动项目开始测试
com.zl.aspect.LogAspect : URL:http://localhost:8080/test/hello com.zl.aspect.LogAspect : IP :0:0:0:0:0:0:0:1 com.zl.aspect.LogAspect : method :helleWorld com.zl.aspect.LogAspect : parameter :[test] com.zl.aspect.LogAspect : return :"hello world!"
可以看到上面的入参和返回值都已经打印出来了,说明了自定义的starter已经生效了。
6:总结
SpringBoot自动配置功能带给我们的是开箱即用,快速便捷的功能,自动配置为我们研发人员带来的优点,我主要总结为以下两点:
1:提高研发效率。我们可以快速构建开发环境,对于开发中使用到的开源组件和中间件,我们直接引入对应的Starter就可以直接开发了,例如Redis和Mybatis等,可以直接引入对应的spring-boot-starter-data-redis就可以直接使用RedisTemplate来操作Redis了,这样可以极大的提高研发的效率,无需再进行复杂的起步配置了和各种版本依赖管理了。
2:标准模块复用。对于业务开发中的一些标准模块,例如常用的一些三方服务,我们可以利用Starter直接配置好,在需要使用的项目中直接引入这个starter就可以立即使用了,无需再去引入Jar包和编写配置文件等,同样的,对于一些标准非业务强耦合的功能,例如监控,鉴权等,也可以定义一个Starter,需要使用鉴权和监控功能的项目就可以直接复用了,无需再次开发。
作者:京东零售 钟磊
来源:京东云开发者社区 自猿其说Tech 转载请注明来源

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Java类加载机制详解 | 京东云技术团队
一.类加载器及双亲委派机制 类加载器 加载类 备注 启动类加载器(Bootstrap ClassLoader) JAVA_HOME/jre/lib 无上级,无法直接访问 由jvm加载 拓展类加载器(Extension ClassLoader) JAVA_HOME/jre/lib/ext 父加载器为 Bootstrap,显示为 null 。该类由Bootstrap加载 应用类加载器(Application ClassLoader) classpath 父加载器上级为 Extension,该类由Bootstrap加载 自定义类加载器 自定义路径 父加载器为 Application,该类由Application ClassLoader加载 1.类加载器继承结构 2. 类加载器的核心方法 方法名 说明 getParent() 返回该类加载器的父类加载器 findClass(String name) 查找名字为name的类,返回的结果是java.lang.Class类的实例 loadClass(String name) 加载名为name的类,返回java.lang.Class类的实...
- 下一篇
生成式 AI 如何释放开发者的生产力?
生成式 AI 可以将程序员的开发速率提高两倍。技术管理者有望通过 AIGC 应用,大幅缩短四类关键开发任务的完成时间,进而提升组织生产力。 ——麦肯锡《通过生成式 AI 释放开发者生产力》 01 生成式 AI 将如何影响研发效能? 麦肯锡最近的一项实证研究发现,生成式 AI 工具可以显著提升程序员的开发速率,进而显著提升组织生产力。 该研究对来自美国和亚洲各地的 40 余名开发者展开了观察和实验。参与者们需要执行三种常见的开发任务——代码生成、代码重构和文档编写,而开发者特征、任务的完成时间和复杂性,以及代码质量等数据被科学地记录下来。 研究结果表明,在生成式 AI 的辅助下,可维护性代码文档可以在一半的时间内完成,新代码生成效率提升近一倍,而代码重构类任务的完成时间也节省近三分之一。在新工具和流程的推动下,结合正确的技能提升和企业赋能,这些速度的提升可以转化为生产力的提高,并超越过去工程生产力的进步。 不过,任务完成时间的减少也可能会因开发任务的复杂性和开发者经验而有所差异。对于高复杂度任务,由于开发者缺乏必要的背景知识,其时间节省不足 10%。此外,在某些情况下,使用了 AIGC ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS8编译安装MySQL8.0.19
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Hadoop3单机部署,实现最简伪集群
- CentOS关闭SELinux安全模块
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题