1、自动装配概述
Spring Boot 自动装配会尝试着装载开发人员在应用的Class Path下添加的JAR文件依赖,比如当HSQLDB存在于应用的Class Path时,开发人员不需要手动配置数据库连接的Beans,而是由Spring Boot自动装配一个内存型的数据库。
激活自动装配的注解是@EnableAutoConfigure和@SpringBootApplication。
2、@SpringBootApplication
2.1 理解@SpringBootApplication注解语义
2.1.1 @SpringBootApplication概述
官方解释@SpringBootApplication等价于@EnableAutoConfiguration、@ComponetScan和@Configuration。其中@EnableAutoConfiguration负责激活Spring Boot自动装配机制,@ComponetScan激活@Componet的扫描,@Configuration声明被标注为配置类。
案例:
重构first-springboot应用在项目引导类中将@SpringBootApplication注解替换为三注解声明方式,代码如下:
代码语言:javascript复制//@SpringBootApplication
@EnableAutoConfiguration//开启自动装配
@ComponentScan//包扫描
@Configuration//标识为配置类
public class FirstSpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(FirstSpringbootApplication.class, args);
}
}
2.1.2 查看@SpringBootAppliction源码
代码语言:javascript复制@Target(ElementType.TYPE) //表示此注解的标识范围为接口、类、枚举
@Retention(RetentionPolicy.RUNTIME) //元注解,表示注解不仅保存在class文件是,并且jvm加载class文件之后,仍然存在
@Documented //表示该注解会被javadoc工具记录
@Inherited //表示该注解会被子类继承
@SpringBootConfiguration //与@Configuration作用相似,标识为配置类
@EnableAutoConfiguration //开启自动装配
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })//从何处扫描Bean
public @interface SpringBootApplication {
@SpringBootApplication:@EnableAutoConfiguration、@ComponetScan和@SpringBootConfiguration的组合,不过@ComponetScan并非使用了默认值,而是添加了排除的TypeFilter实现:TypeExcludeFilter和AutoConfigurationExcludeFilter。
2.1.3 查看@SpringBootConfiguration源码
代码语言:javascript复制@Target({ElementType.TYPE}) //表示此注解的标识范围为接口、类、枚举
@Retention(RetentionPolicy.RUNTIME) //元注解,表示注解不仅保存在class文件是,并且jvm加载class文件之后,仍然存在
@Documented //表示该注解会被javadoc工具记录
@Configuration //标识为配置类
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
@AliasFor注解:能够将一个或多个注解的属性"别名"放在某个注解中。
2.2 @SpringBootApplication属性别名
@SpringBootApplication源码如下:
代码语言:javascript复制@Target(ElementType.TYPE) //表示此注解的标识范围为接口、类、枚举
@Retention(RetentionPolicy.RUNTIME) //元注解,表示注解不仅保存在class文件是,并且jvm加载class文件之后,仍然存在
@Documented //表示该注解会被javadoc工具记录
@Inherited //表示该注解会被子类继承
@SpringBootConfiguration //与@Configuration作用相似,标识为配置类
@EnableAutoConfiguration //开启自动装配
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) //从何处扫描Bean
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;
}
案例:
重构first-springboot将HelloController移动到com.tyschool包下,修改启动类使控制器能正常访问
启动类代码如下:
代码语言:javascript复制@SpringBootApplication(scanBasePackages = {"com.tyschool"})
public class FirstSpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(FirstSpringbootApplication.class, args);
}
}
3、 @SpringBootApplication标注非引导类
案例:
将启动类上的@SpringBootApplication去掉,添加非引导类,在非引导类上标注@SpringBootApplication注解,修改SpringApplication.run()方法中的class为非引导类
非引导类代码如下:
代码语言:javascript复制@SpringBootApplication(scanBasePackages = {"com.tyschool.firstspringboot.controller"})
public class WebConfig {
}
引导类代码如下:
代码语言:javascript复制public class FirstSpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(WebConfig.class, args);
}
}
4、 @SpringBootApplication “继承”@Configuration CGLIB提升特性
@SpringBootApplication 作为@Configuration的"派生"注解,同样继承其注解特性,其中最明显的是CGLIB提升。因为@Bean在@Componet类中与正常的Java对象语义相同,不存在CGLIB处理,而后在@Configuration中则执行了CGLIB提升
案例:
验证@SpringBootApplication CGLIB提升特性
WebConfig 代码如下:
代码语言:javascript复制@SpringBootApplication
public class WebConfig {
//定义路由,访问/helloworld,返回Hello,World
@Bean
public RouterFunction<ServerResponse> helloWorld() {
return RouterFunctions.route(RequestPredicates.GET("/helloWorld"),
request -> ServerResponse.ok().body(Mono.just("Hello,World"), String.class)
);
}
//项目启动时,打印相关信息
@Bean
public ApplicationRunner runner(BeanFactory beanFactory){
return args -> {
System.out.println("当前hello Bean实现类为:" beanFactory.getBean("helloWorld").getClass().getName());
System.out.println("当前 WebConfiguration Bean实现类为:" beanFactory.getBean(WebConfig.class).getClass().getName());
};
}
}