@SpringBootApplication注解分析 :
被@SpringBootApplication注解的类,会被识别为SpringBoot的启动类,它是一个自定义的注解。
@Target({ElementType.TYPE})//规定该注解用于类上
@Retention(RetentionPolicy.RUNTIME)//规定该注解能保留到运行时,这样才能被反射获取注解信息
@Documented
@Inherited//规定了被@SpringBootApplication注解的类的子类也默认被@SpringBootApplication注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
。。。。。。。省略了注解里的元数据定义。。。。。。。。。。
}
源码里前四个注解都是元注解,@ComponentScan是个扫描注解。@SpringBootConfiguration和
@EnableAutoConfiguration才是@SpringBootApplication的关键
总结:@SpringBootApplication是@SpringBootConfiguration和
@EnableAutoConfiguration的复合注解
(1)@SpringBootConfiguration源码分析
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
结论:@SpringBootConfiguration就是一个@Configuration注解
@Configuration源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
@Configuration是一个@Component注解,而@Component仅仅表明这个类是一个组件,是Spring的一个Bean,可以作用于任何层。
总结:@SpringBootConfiguration归根到底就是一个@Component注解,它仅仅表明这个启动类是Spring容器里的一个bean。
(2) @EnableAutoConfiguration源码分析
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
@EnableAutoConfiguration是一个复合注解,由@AutoConfigurationPackage和
@Import({AutoConfigurationImportSelector.class})组成(其余四个是元注解)。其中@Import注解导入了一个AutoConfigurationImportSelector.class类,这是一个自动配置的选择器,这个类是通过反射的机制获取某些类的注解元数据,通过元数据来实现特定的功能。SpringBoot启动后,并不会加载所有的配置,它会通过AutoConfigurationImportSelector.class来选取部分配置加载。
@AutoConfigurationPackage其实也是一个@Import注解,它导入的是Registrar.class,它是AutoConfigurationPackages抽象类的静态内部
总结:@EnableAutoConfiguration注解的作用主要就是导入了两个类对象,分别为AutoConfigurationImportSelector.class和Registrar.class,关键是AutoConfigurationImportSelector.class。
提示:这里描述项目中遇到的问题:
例如:数据传输过程中数据不时出现丢失的情况,偶尔会丢失一部分数据
APP 中接收数据代码:
@Override
public void run() {
bytes = mmInStream.read(buffer);
mHandler.obtainMessage(READ_DATA, bytes, -1, buffer).sendToTarget();
}
启动类里run方法分析
run方法源码
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
它返回的是一个 ConfigurableApplicationContext类型的对象, ConfigurableApplicationContext是一个接口,同时也是 ApplicationContext的子类。而 ApplicationContext却是我们熟悉的Spring容器,是一个管理所有Bean的容器。
现在我们来通过代码验证一下:
跟往常一样,编写一个简单的SpringBoot项目。
Controller类:
@RestController(value = "test")
public class test {
@RequestMapping("/test")
public void test(){
System.out.println("我被Spring容器调用了!!!");
}
}
test类是一个中规中矩的接受前端请求的一个接口类。
启动类:
@SpringBootApplication
public class BootClass {
public static void main(String[] args){
ConfigurableApplicationContext applicationContext = SpringApplication.run(BootClass.class,args);
test t = (test)applicationContext.getBean("test");
t.test();
}
}
在启动类的主函数中我用applicatContext来获取了run返回的对象,前面我说了run返回的其实就是一个Spring容器,通过Spring容器的getBean方法,我获取了id为test的这个bean,也就是@RestController(value = “test”)注解里的元数据。通过这些操作我就获取了test对象,从而执行了它的方法。
最后执行成功: