SpringBoot
SpringBoot 自动装配
Spring Boot的自动装配是通过@EnableAutoConfiguration 实现的,可以将启动类下所有的component组件注册到容器中
,通过 SpringFactoriesLoader 最终加载外部jar包下面的META-INF/spring.factories
中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional
按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx
包实现起步依赖。
比如对于database属性,必须有username、password属性,如果没有则会连接不上数据源。在这种情况如果还进行数据源的装配,则会抛出异常,所以希望不装配数据源。使用Conditional注解,传入实现Condition接口,重写matches匹配的方法,返回true则进行装配,false则不装配。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // 允许在上下文中注册额外的 bean 或导入其他配置类
@EnableAutoConfiguration // 启用 SpringBoot 的自动配置机制
// 扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类,可以自定义不扫描某些 bean
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
@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 {};
}
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
}
public interface DeferredImportSelector extends ImportSelector {
}
// 获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中
public interface ImportSelector {
String[] selectImports(AnnotationMetadata var1);
}
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) { // 判断是否打开自动装配
return NO_IMPORTS;
}
// 获取所有需要装配的bean,会加载 META-INF/spring.factories里面的配置(每次启动不会加载所有的配置,会根据@ConditionalOnXXX 进行过滤)
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
SpringBoot 的启动流程
SpringBoot的启动执行的是SpringApplication.run方法,run方法里面实例化了SpringApplication 并调用了run方法。
@EnableCaching
@MapperScan("com.site.blog.my.core.dao")
@SpringBootApplication
public class MyBlogApplication {
public static void main(String[] args) {
SpringApplication.run(MyBlogApplication.class, args);
}
}
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
// 实例化SpringApplication 并执行run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
// 被执行的run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}