@SpringBootApplication
一、注解派生
- 根据官方文档,该注解用于激活,@EnableAutoConfiguration、@Configuration、@ComponentScan
- @ComponentScan:用于激活@Component的扫描,此注解属于spring framework
- @Configuration声明被标注为配置类
- @EnableAutoConfiguration:开启Spring boot自动装配机制。
- 针对@ComponentScan,使用了excludeFilters过滤掉了两种不同情况的类
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
- TypeExcludeFilter:用于查找BeanFactory中已经注册的TypeExcludeFilter Bean作为代理执行对象
@Override
//metadataReader spring中的类元信息
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
if (this.beanFactory instanceof ListableBeanFactory && getClass() == TypeExcludeFilter.class) {
//如果没有代理,就将此TypeExcludeFilterbean加入到spring中
for (TypeExcludeFilter delegate : getDelegates()) {
if (delegate.match(metadataReader, metadataReaderFactory)) {
return true;
}
}
}
return false;
}
//获取代理
private Collection<TypeExcludeFilter> getDelegates() {
Collection<TypeExcludeFilter> delegates = this.delegates;
if (delegates == null) {
delegates = ((ListableBeanFactory) this.beanFactory).getBeansOfType(TypeExcludeFilter.class).values();
this.delegates = delegates;
}
return delegates;
}
- AutoConfigurationExcludeFilter:用于排除其他同时标记@Configuration和@EnableAutoConfiguration的类
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
//如果标注了configuration标签和EnableAutoConfiguration标签就排除
return isConfiguration(metadataReader) && isAutoConfiguration(metadataReader);
}
private boolean isConfiguration(MetadataReader metadataReader) {
return metadataReader.getAnnotationMetadata().isAnnotated(Configuration.class.getName());
}
注解派生
- @ComponentScan仅仅关注@Component,然而由于@SpringBootConfiguration属于多层次的@Component派生注解,能够被ComponentScan识别。派生关系如下。
@Component
@Configuration
@SpringBootConfiguration
二、属性别名
- 作用,使用属性别名,可以在注解中,对其他注解的属性进行设置,桥接其他注解的属性,通过配置exclude属性的值,就可以设置EnableAutoConfiguration中该属性的值,进而实现,不对某些类进行自动加载
- 源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
@ConfigurationPropertiesScan
public @interface SpringBootApplication {
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
- 验证:最终导致的结果是访问controller方法访问不到
三、标注非引导类
- 引导类:指的是启动的类,带有main方法的类
- 可以将@SpringBootApplication注解放到非引导类中,在引导类中的run方法中指明带有@SpringBootApplication的类即可。
四、@SpringBootApplication“继承”@Configuration CGLIB提升
- 在@Configuration注解的类,生成的bean对象属于“完全模式”,会执行CGLIB提升的操作。 而对于使用@Bean标签标注的bean对象,不会进行提升,称为“轻量模式”
- CGLIB提升并非是为@Bean对象提供的,而是为@Configuration类准备的。
- 演示:
- 使用非@Configuration及派生注解,没有进行CGLIB提升
- 使用@Configuration或者派生注解,很显然得到了增强
理解自动装配机制
- 自动装配能够打包到外部的JAR文件中,并且被Spring boot装配。同时,自动装配也能被关联的starter中,这些starter提供自动装配的代码及关联的依赖。
- spring boot中,提供了大量的内建自动装配@Configuration,统一存放在org.springframework.boot.autoconfigurate包或子包下,同时这些类均配置在META-INF/spring.factories资源中。所以如果导入自己的自动装配类,需要在启动方法加上@EnableAutoConfiguration,同时在META-INF/spring.factories资源中,加上org.springframework.boot.autoconfigure.EnableAutoConfiguration=加上了@Configuration的类,即可实现自动装配,导入。
- 过程
- 识别META-INF目录中的配置
- 找到相关的配置类
- 导入相关的类,进行加载,启动spring容器,启动项目
- 找到相关的配置类
- 识别META-INF目录中的配置
- 示例
- 总体结构
- spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.book.firstspringboot.config.WebAutoConfiguration
- WebAutoConfiguration
@Configuration
@Import(WebConfig.class)
public class WebAutoConfiguration {
}
- WebConfig
@Configuration
public class WebConfig {
@Bean
public FirstController firstController(){
return new FirstController();
}
@Bean
public ApplicationRunner runner(BeanFactory beanFactory){
return args->{
System.out.println("当前FirstController bean实现类为:"+
beanFactory.getBean("firstController").getClass().getName());
System.out.println("当前WebConfig bean实现类为:"+
beanFactory.getBean(WebConfig.class).getClass().getName());
};
}
}
- 启动类
@EnableAutoConfiguration
public class FirstSpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(FirstSpringbootApplication.class, args);
}
}
总体流程
启动类通过@EnableAutoConfiguration开启自动装配
->spring 自动装配扫描,spring.factories,找到WebAutoConfiguration
-> 通过Import注解注入,真正的配置类,WebConfig
->通过bean标签,注入Controller对象,启动项目
注意,在配置类上,不加入@Configuration也可以将内部的bean对象进行注入,但是配置类为原来的配置类即没有进行CGLIB增强,具体原因,后续注意。
- 没有加@Configuration注解
- 加了@Configuration注解