SpringBoot源码解析 AutoConfigure机制

前言

SpringBoot的自动配置确实方便了操作,简化了很多配置。然而作为一个有追求的人,我们既要知其然,也要知其所以然。所以接下来我就以Spring AOP Starter为例来说明下AutoConfigure机制是如何生效的。

Spring Framework和SpringBoot如何使用AOP

首先来回忆下Spring是如何使用AOP的。

  1. 引入相关jar
  2. 引入<aop:aspectj-autoproxy/>或者使用@EnableAspectJAutoProxy注解

SpringBoot是如何使用呢?引入如下依赖即可。

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

源码解析

知识复习完毕,让我们看下源码吧

spring-boot-starter-aop源码

打开源码后发现这个starter只有一个pom文件,里面都是什么内容呢?

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
   	<groupId>org.springframework.boot</groupId>
   	<artifactId>spring-boot-starters</artifactId>
   	<version>${revision}</version>
   </parent>
   <artifactId>spring-boot-starter-aop</artifactId>
   <name>Spring Boot AOP Starter</name>
   <description>Starter for aspect-oriented programming with Spring AOP and AspectJ</description>
   <properties>
   	<main.basedir>${basedir}/../../..</main.basedir>
   </properties>
   <dependencies>
   	<dependency>
   		<groupId>org.springframework.boot</groupId>
   		<artifactId>spring-boot-starter</artifactId>
   	</dependency>
   	<dependency>
   		<groupId>org.springframework</groupId>
   		<artifactId>spring-aop</artifactId>
   	</dependency>
   	<dependency>
   		<groupId>org.aspectj</groupId>
   		<artifactId>aspectjweaver</artifactId>
   	</dependency>
   </dependencies>
</project>

可以看到,其中有三个依赖。而spring-boot-starter这个是所有starter都会有的,其他的两个依赖则很明显是Spring AOP的两个依赖。

spring-boot-starter源码

接着打开spring-boot-starter源码看下,原来也只有一个pom.xml。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
   	<groupId>org.springframework.boot</groupId>
   	<artifactId>spring-boot-starters</artifactId>
   	<version>${revision}</version>
   </parent>
   <artifactId>spring-boot-starter</artifactId>
   <name>Spring Boot Starter</name>
   <description>Core starter, including auto-configuration support, logging and YAML</description>
   <properties>
   	<main.basedir>${basedir}/../../..</main.basedir>
   </properties>
   <dependencies>
   	<dependency>
   		<groupId>org.springframework.boot</groupId>
   		<artifactId>spring-boot</artifactId>
   	</dependency>
   	<dependency>
   		<groupId>org.springframework.boot</groupId>
   		<artifactId>spring-boot-autoconfigure</artifactId>
   	</dependency>
   	<dependency>
   		<groupId>org.springframework.boot</groupId>
   		<artifactId>spring-boot-starter-logging</artifactId>
   	</dependency>
   	<dependency>
   		<groupId>javax.annotation</groupId>
   		<artifactId>javax.annotation-api</artifactId>
   	</dependency>
   	<dependency>
   		<groupId>org.springframework</groupId>
   		<artifactId>spring-core</artifactId>
   	</dependency>
   	<dependency>
   		<groupId>org.yaml</groupId>
   		<artifactId>snakeyaml</artifactId>
   		<scope>runtime</scope>
   	</dependency>
   </dependencies>
</project>

spring-boot

这个jar打开看下,可以看到SpringApplication这个很熟悉的类,可以确定是Spring Boot的启动入口,此处不做展开。

spring-boot-autoconfigure

这个则是我们此次博文的主角。打开看下,可以看到诸如elasticsearch、redis、jdbc、web、mail等包。打开我们的aop看下,只有一个AopAutoConfiguration,代码如下:

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,
		AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = false)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
	public static class JdkDynamicAutoProxyConfiguration {

	}

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = true)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
	public static class CglibAutoProxyConfiguration {

	}

}

在这里,我们看到了熟悉的@Configuration@EnableAspectJAutoProxy。看样子SpringBoot就是在此处引入了AOP的支持。

生效条件

在这个类上,我们看到了两个条件:

  1. @ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,AnnotatedElement.class })
    这个比较直观,意思就是存在这些类的时候此配置才生效,其实际的作用在于检测是否存在对应的依赖
  2. @ConditionalOnProperty(prefix = “spring.aop”, name = “auto”, havingValue = “true”, matchIfMissing = true)
    这个则是spring.aop.auto为true才生效。注意matchIfMissing这个属性,从这个直白的命名上可以看出作用:如果此配置缺失则生效,等同于默认生效。

@ConditionalOnXX

打开org.springframework.boot.autoconfigure.condition包看下,有大量的此类注解,命名也比较直白。作用如下:

注解生效条件
ConditionalOnBeanBeanFactory存在对应实例
ConditionalOnClassclasspath中存在对应类文件
ConditionalOnCloudPlatform匹配指定云平台
ConditionalOnExpression满足对应表达式
ConditionalOnJavaJVM版本检测
ConditionalOnJndijndi检测
ConditionalOnMissingBeanBeanFactory不存在对应实例
ConditionalOnMissingClassclasspath中不存在对应类文件
ConditionalOnNotWebApplication非web环境
ConditionalOnProperty匹配属性
ConditionalOnResource匹配文件
ConditionalOnSingleCandidate指定Bean在容器中只有一个,或者虽然有多个但是指定首选Bean
ConditionalOnWebApplication匹配web容器

总结

最后总结下生效流程:

  1. 所有的starter都依赖于spring-boot-starter,而spring-boot-starter则依赖了spring-boot-autoconfigure。
  2. spring-boot-autoconfigure内置了众多的xxAutoConfiguration类。这些类会通过@ConditionalOnXX注解来检测是否满足生效条件,条件满足时配置就会生效。
  3. 当我们引入starter时就引入了其对应依赖,所以引入对应的starter就激活了对应的xxAutoConfiguration,进而进行了功能激活。

彩蛋

可能有人好奇,比如为什么引入db的支持一定要写成这样:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: xxxxxx

有这个疑问的同学可以打开DataSourceProperties这个类看一下,你的问题就会得到解答。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值