@AutoConfiguration
属于springboot
当中autoconfigure
包下的注解。springboot
给我们提供了好多AutoConfiguration
,例如关于缓存cache
的有CacheAutoConfiguration
,关于定时任务quartz
的有QuartzAutoConfiguration
,这些AutoConfiguration
你会发现基本上都会拿@AutoConfiguration
来修饰。本篇来彻底了解@AutoConfiguration
到底有什么作用,以及到底如何应用他。
源码当中有三个元注解:
除了元注解外还有三个注解:
@Component
注解的扩展注解,同@Controller、@Service
等几个注解的功能是一样的,只要在类上添加了该注解,然后在springboot
的扫描范围内,启动项目的时候会将该注解修饰的类通过无参构造器创建出来,然后存入spring容器当中。@Configuration
使用,主要用于修饰在类上,然后可以指定该类 在 某类之前进行加载到容器。@AutoConfigureBefore
功能一样,他是指定该类 在 某类 之后进行加载到容器当中。具体的用法请看下面的示例!
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration(
proxyBeanMethods = false
)
@AutoConfigureBefore
@AutoConfigureAfter
public @interface AutoConfiguration {
@AliasFor(
annotation = Configuration.class
)
String value() default "";
@AliasFor(
annotation = AutoConfigureBefore.class,
attribute = "value"
)
Class<?>[] before() default {};
@AliasFor(
annotation = AutoConfigureBefore.class,
attribute = "name"
)
String[] beforeName() default {};
@AliasFor(
annotation = AutoConfigureAfter.class,
attribute = "value"
)
Class<?>[] after() default {};
@AliasFor(
annotation = AutoConfigureAfter.class,
attribute = "name"
)
String[] afterName() default {};
}
@AutoConfiguration其实就是一个组合注解。因为一个自动配置类往往需要加很多注解,于是乎springboot就将一些经常用到的注解,给组合到一块,这样就可以做到一个注解拥有三个注解的功能。具体他是如何做到注解聚合到一块的呢,原因是依赖于@AliasFor
注解,@AliasFor注解就是起到一个注解传值的作用。想深入了解@AliasFor可以看我的这一篇文章:
https://blog.csdn.net/weixin_43888891/article/details/126962698?spm=1001.2014.3001.5501
@Configuration
注解我们经常用,但是我们很少这样用@Configuration(proxyBeanMethods = false)
,这里的proxyBeanMethods
默认是true
,但是这里却设置为了false
,那么这个属性到底有什么作用?
@Configuration
属于spring
当中的注解,感兴趣的可以看一下spring源码当中的解释:https://github.com/spring-projects/spring-framework/blob/main/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java
源码当中解释不是中文,再者一般的也看不懂,我们直接通过代码试验来得出结论:
当他为true的时候,我们在容器中获取到的对象总是同一个,即便是我们调用了创建对象的方法,那获取到的还是同一个。但是当是多例的时候,如果我们调用了创建对象的方法,那就不是同一个了。
(1)自定义一个类,用于测试
public class TestBean1 {
@Override
public String toString() {
return super.toString() + "--我是TestBean1";
}
public TestBean1() {
System.out.println("TestBean1构造器执行了");
}
}
(2)添加配置类
@Configuration(proxyBeanMethods = true)
public class Myconfig {
@Bean
public TestBean1 testBean1() {
return new TestBean1();
}
}
(3)添加测试类
@RestController
public class CommonController {
@Autowired
private Myconfig myconfig;
@Autowired
private TestBean1 testBean1;
@RequestMapping("/import")
public void printImportBeanInfo() {
System.out.println(testBean1);
System.out.println(myconfig.testBean1());
}
}
(4)访问接口,得出从容器里面取和直接访问testBean1方法得出来的对象是一个对象,这就是所谓的被代理了
(5)设置为false@Configuration(proxyBeanMethods = false)
很显然已经不是一个对象了
(1)自定义两个配置类
@Configuration
public class Config1 {
public Config1() {
System.out.println("Config1构建了");
}
}
@Configuration
public class Config2 {
public Config2() {
System.out.println("Config2构建了");
}
}
(2)启动项目测试:默认是先创建的Config1后创建的Config2
现在是有个需求要求让@Config2先加载,可能这时候有人该说了@Order注解不就可以了吗,其实不是的,@Order值可能会影响注入点的优先级,但请注意,它不会影响单例启动顺序。关于@order我专门整理了一篇文章,供参考学习!
https://blog.csdn.net/weixin_43888891/article/details/127481825
(3)使用@AutoConfigure相关注解的前提是必须是自动配置类,可能有时候走了狗屎运给你一种错觉还真的配置成功了。
在autoconfigure包下就有spring.factories,这个文件配置了自动配置类,springboot会读取这个文件的,我们也可以在自己项目上定义spring.factories,这样我们的配置类对于@AutoConfigureAfter注解就可以生效了。
第一行是固定的,后面的就是全类名,虽然只有Config2使用了注解,但是需求是和Config1进行排序,所以这两个都得加。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.gzl.cn.springbootcache.config.Config2,\
com.gzl.cn.springbootcache.config.Config1
(5)测试,成功解决
@AutoConfigureAfter和@AutoConfigureBefore其实是一样的,我这里就不演示了哈,感兴趣的可以自己参照上面进行练习一下。
这种也是可以的!当然前提也是需要配置spring.factories
@Configuration
@AutoConfigureOrder(2)
public class Config1 {
public Config1() {
System.out.println("Config1构建了");
}
}
@Configuration
@AutoConfigureOrder(1)
public class Config2 {
public Config2() {
System.out.println("Config2构建了");
}
}
其实关键的代码还是在AutoConfigurationImportSelector中,将自动配置类从spring.factories加载出来之后会根据条件排序,在selectImports()方法中最后一行代码如下:
紧接着会走到这个地方,实际上是分了三步排序:
从上面配置的顺序可以知道,最终决定权还是在@AutoConfigureAfter、@AutoConfigureBefore这两个注解。
当我们不设置spring.factories的时候,这里面压根都没有这两个类!