SpringBoot 源码解读Springboot 之前出现的问题 Spring 框架需要进行大量的配置 项目的依赖管理冲突 为什么是 SpringBoot Spring Boot 本身并不提供 Spring 框架的核心特性以及扩展功能 只是用于快速 敏捷地开发新一代基于 Spring 框架的应用程序 也就是说 它并不是用来替代 Spring 的解决方案 而是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具
Spring Boot提供了一种新的编程范式,能在最小的阻力下开发Spring应用程序。有了它,你可以更加敏捷地开发Spring应用程序,专注于应用程序的功能,不用在Spring的配置上多花功夫,甚至完全不用配置。实际上,Spring Boot的一项重要工作就是让Spring不再成为你成功路上的绊脚石。 ——《SpringBoot实战》
/ * Indicates that a class provides Spring Boot application * { @link Configuration @Configuration}. Can be used as an alternative to the Spring's * standard { @code @Configuration} annotation so that configuration can be found * automatically (for example in tests). * * Application should only ever include one { @code @SpringBootConfiguration} and * most idiomatic Spring Boot applications will inherit it from * { @code @SpringBootApplication}. * * @author Phillip Webb * @since 1.4.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { }
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { }
@Order(Ordered.HIGHEST_PRECEDENCE) static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImport(metadata).getPackageName()); } @Override public Set
/ * Programmatically registers the auto-configuration package names. Subsequent * invocations will add the given package names to those that have already been * registered. You can use this method to manually define the base packages that will * be used for a given {@link BeanDefinitionRegistry}. Generally it's recommended that * you don't call this method directly, but instead rely on the default convention * where the package name is set from your {@code @EnableAutoConfiguration} * configuration class or classes. * @param registry the bean definition registry * @param packageNames the package names to set
private void fireAutoConfigurationImportEvents(List
configurations,
Set
exclusions) {
List listeners = getAutoConfigurationImportListeners(); if (!listeners.isEmpty()) { AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions); for (AutoConfigurationImportListener listener : listeners) { invokeAwareMethods(listener); listener.onAutoConfigurationImportEvent(event); } } }
# Auto Configuration Import Listeners org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
protected List
getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List
configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
// 传入的factoryClass:org.springframework.boot.autoconfigure.EnableAutoConfiguration public static List
loadFactoryNames(Class
factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName(); try { Enumeration
urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION)
: ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); List
result = new ArrayList
();
while (urls.hasMoreElements()) { URL url = urls.nextElement(); Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url)); String factoryClassNames = properties.getProperty(factoryClassName); result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames))); } return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } } // 相关常量 public static final String FACTORIES_RESOURCE_LOCATION = // "META-INF/spring.factories";
Spring Boot对于@Conditional的扩展Spring Boot提供了一个实现了Condition接口的抽象类SpringBootCondition。这个类的主要作用是打印一些用于诊断的日志,告诉用户哪些类型被自动配置了。它实现Condition接口的方法:
@Override public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { String classOrMethodName = getClassOrMethodName(metadata); try { ConditionOutcome outcome = getMatchOutcome(context, metadata); logOutcome(classOrMethodName, outcome); recordEvaluation(context, classOrMethodName, outcome); return outcome.isMatch(); } catch (NoClassDefFoundError ex) { throw new IllegalStateException("Could not evaluate condition on " + classOrMethodName + " due to " + ex.getMessage() + " not " + "found. Make sure your own configuration does not rely on " + "that class. This can also happen if you are " + "@ComponentScanning a springframework package (e.g. if you " + "put a @ComponentScan in the default package by mistake)", ex); } catch (RuntimeException ex) { throw new IllegalStateException("Error processing condition on " + getName(metadata), ex); } } / * * Determine the outcome of the match along with suitable log output. * @param * context the condition context * @param metadata the annotation metadata * * @return the condition outcome */ public abstract ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata);
@SpringBootApplication public class DemoApplication {
public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
/ * Static helper that can be used to run a {@link SpringApplication} from the * specified sources using default settings and user supplied arguments. * @param primarySources the primary sources to load * @param args the application arguments (usually passed from a Java main method) * @return the running {@link ApplicationContext} */ public static ConfigurableApplicationContext run(Class
[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context); //调用之前准备好的ApplicationContextInitializer applyInitializers(context); listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } // Load the sources Set sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[0])); //将SpringApplication自己拥有的ApplicationListener加入到ApplicationContext,发送ApplicationPreparedEvent listeners.contextLoaded(context); }
# Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ // to report warnings for common misconfiguration,用来报告Spring容器的一些常见的错误配置的 org.springframework.boot.context.ContextIdApplicationContextInitializer,\//为ApplicationContext设置id
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/hz/127171.html