前言
如果需要了解Springboot 那么自动配置是少不了的,自从有了 SpringBoot 之后,各种零配置自动在加载,今天我们就一起来讨论一下 SpringBoot 自动配置原理。
预备知识
这里的预备知识主要关注@Import 注解,@Import主要支持三种类的导入
a、直接导入普通的 Java 类。
b、 ImportSelector 的实现类 使用。
c、ImportBeanDefinitionRegistrar 实现类。
这里写一个demo来验证一下对应内容。
1、一个普通类
public class OrdinaryObject {
public void printMessage(){
System.out.println("OrdinaryObject invoke printMessage");
}
}
2、ImportSelector 的实现类(通过selectImports接口注入想要注册的类,这里注入ImportSelectorPrintObject这样一个类)
public class ImportSelectorObject implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.yin.demo.service.impl.ImportSelectorPrintObject"};
}
}
class ImportSelectorPrintObject {
public void printMessage() {
System.out.println("ImportSelectorPrintObject invoke printMessage");
}
}
3、ImportBeanDefinitionRegistrar 实现类(通过registerBeanDefinitions 接口注入想要注册的类,这里注入ImportBeanDefinitionRegistrarPrintObject 这样一个类)
public class ImportBeanDefinitionRegistrarObject implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(ImportBeanDefinitionRegistrarPrintObject.class);
registry.registerBeanDefinition("definitionRegistrar", rootBeanDefinition);
}
}
class ImportBeanDefinitionRegistrarPrintObject {
public void printMessage() {
System.out.println("ImportBeanDefinitionRegistrarPrintObject invoke printMessage");
}
}
4、用一个类通过@Import 将其注入
@Import(value = {OrdinaryObject.class, ImportBeanDefinitionRegistrarObject.class, ImportSelectorObject.class})
public class ConfigTest {
}
5、测试当前类的注入效果
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(ConfigTest.class);
OrdinaryObject ordinaryObject = context.getBean(OrdinaryObject.class);
ordinaryObject.printMessage();
ImportSelectorPrintObject importSelectorPrintObject = context.getBean(ImportSelectorPrintObject.class);
importSelectorPrintObject.printMessage();
ImportBeanDefinitionRegistrarPrintObject definitionRegistrarPrintObject = context.getBean(ImportBeanDefinitionRegistrarPrintObject.class);
definitionRegistrarPrintObject.printMessage();
}
打印结果:
OrdinaryObject invoke printMessage
ImportSelectorPrintObject invoke printMessage
ImportBeanDefinitionRegistrarPrintObject invoke printMessage
可以看到想要注册的类都注入成功,后续主要用到 ImportSelector 的实现类 方式来对需要类进行注入。
源码解析
由上图可以看到springboot 启动之后 中@SpringBootApplication 包含 @EnableAutoConfiguration 自动配置这个注解,在@EnableAutoConfiguration 注解中@Import 这个对AutoConfigurationImportSelector.class 进行注入,通过预备知识可以得知。这个时候会加载public String[] selectImports(AnnotationMetadata annotationMetadata) 中返回的内容。
再对getAutoConfigurationEntry 中对返回配置好的AutoConfigurationEntry 对象。
后续步骤就是从META-INF/spring.factories 中加载对象进行注册。
实践
一、模块的构建
在项目中建立一个modules 模块spring.factories 中内容为:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.yin.common.LogAspect
注解log为:
/**
* 系统日志注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
/**
* 日志内容
*
* @return xx
*/
String value() default "";
}
LogAspect 实现的具体类:
/**
* 操作日志
*
*/
@Aspect
public class LogAspect {
@Around("@annotation(log)")
public Object around(ProceedingJoinPoint point, Log log) throws Throwable {
String className = point.getTarget().getClass().getName();
String methodName = point.getSignature().getName();
Object proceed = point.proceed();
System.out.println("className:" + className + "methodName:" + methodName + "result:" + proceed);
return proceed;
}
}
maven.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
二、 对子模块引入依赖
<dependency>
<groupId>com.yin</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
对请求方法打上@Log注解
对该接口进行请求
可以看出我们可以通过spring.factories 对需要内容进行自动配置