欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

SpringBoot核心注解原理

时间:2023-06-08

SpringBoot的启动类代码

@SpringBootApplicationpublic class MyblogApplication { public static void main(String[] args) { SpringApplication.run(MyblogApplication.class, args); }}

首先在启动类这段代码中,我们点进 @SpringBootApplication

@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) })public @interface SpringBootApplication {}

除了元注解外,最核心的注解有:

@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan

首先我们来说 @SpringBootConfiguration @EnableAutoConfiguration这两个注解

@SpringBootConfiguration 点进去之后

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@documented@Configurationpublic @interface SpringBootConfiguration {}

除了元注解外,就只有一个 @Configuration,也就是说或这个注解相当于@Configuration,所以这两个注解作用是一样的,什么作用呢?就是能够注册一些额外的Bean,并且导入一些额外的配置。@Configuration还有一个作用就是把该类变成一个配置类,不需要进行额外的XML配置。所以@SpringBootConfiguration相当于@Configuration。

继续看 @EnableAutoConfiguration,官网说这个注解是 让Spring自动去进行一些配置

点进去看

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@documented@Inherited@AutoConfigurationPackage@import(AutoConfigurationimportSelector.class)public @interface EnableAutoConfiguration {}

可以看到它是由@AutoConfigurationPackage 和 @import(AutoConfigurationimportSelector.class) 组成,@AutoConfigurationPackage,作用是:让包中类以及子包中的类能够被自动扫描到Spring容器中。自动配置?它是如何配置的呢?和@import(AutoConfigurationimportSelector.class)相关

从@import(AutoConfigurationimportSelector.class) ,我们点进去看

public class AutoConfigurationimportSelector implements DeferredimportSelector, BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {@Overridepublic String[] selectimports(Annotationmetadata annotationmetadata) {if (!isEnabled(annotationmetadata)) {return NO_importS;}AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationmetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}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;}}

这个AutoConfigurationimportSelector  类中有一个方法  selectimports(Annotationmetadata annotationmetadata) ,它可以帮助扫描那些类自动去添加到程序当中。

里面还有一个方法是 getCandidateConfigurations(),它的作用是引入系统已经加载好的一些类,到底是哪些类呢?

"No auto configuration classes found in meta-INF/spring.factories、If you " + "are using a custom packaging, make sure that file is correct."

从这句话中,可以看到 这个类会去找一个目录为 meta-INF/spring.factories,也就是说它会帮你加载让你去使用,也就是在meta-INF/spring.factories目录装配的,它在哪呢?

 点进去看

可以发现它搬我们配置了很多类的全路径,比如WebMvc

 可以看到它已经帮我们引入了进来,拿几个过来看

org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,

@EnableAutoConfiguration主要作用就是帮你自动去配置,但并不是所有都是创建好的,是根据你的程序去进行决定。那我们继续来看

接着看@ComponentScan注解

@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

扫描包,放入Spring容器,它在SpringBoot做了什么呢?

它帮助我们做了一个排除策略,在这里它结合@SpringBootConfiguration去使用,为什么是排除?因为不可能一上来就全部加载,内存有限。

总结@SpringBootApplication:就是说 它已经把很多东西准备好,具体是否使用取决于我们的程序或者说配置,那我们用不用?继续看这一行代码

public class MyblogApplication { public static void main(String[] args) { SpringApplication.run(MyblogApplication.class, args); }}

来看run方法有没有用到哪些自动配置的东西,比如说内置tomcat,

我们点进去 SpringApplication

class SpringApplication{ public ConfigurableApplicationContext run(String..、args) { //计时器StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection 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); //预刷新contextprepareContext(context, environment, listeners, applicationArguments, printedBanner); //刷新contextrefreshContext(context); //刷次之后的contextafterRefresh(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;}}

我们关注的就是  refreshContext(context);  刷新context,点进去看

private void refreshContext(ConfigurableApplicationContext context) {if (this.registerShutdownHook) {try {context.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments.}}refresh((ApplicationContext) context);}

追踪  refresh((ApplicationContext) context);

public class SpringApplication { @Deprecatedprotected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);refresh((ConfigurableApplicationContext) applicationContext);} protected void refresh(ConfigurableApplicationContext applicationContext) {applicationContext.refresh();}}

它调用了 refresh();点进去这个方法看

protected void refresh(ConfigurableApplicationContext applicationContext) {applicationContext.refresh();}

追踪refresh()

来到了  ConfigurableApplicationContext 接口

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable { void refresh() throws BeansException, IllegalStateException;}

实现该接口,重写该方法的几个类中,

点进去第一个看看

@Overridepublic 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();}}}

发现,这个代码很熟悉,就是一个spring的bean的加载过程,解析SpringIOC加载过程的时候也含有这些方法,如果你看过Spring源码的话 ,应该知道这些方法都是做什么的。现在我们不关心其他的,我们来看一个方法叫做 onRefresh();方法

protected void onRefresh() throws BeansException {// For subclasses: do nothing by default.}

找它的实现

 我们既然要找Tomcat那就肯定跟web有关,我们可以看到有个ServletWebServerApplicationContext

@Overrideprotected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); }}

可以看到 有一个  createWebServer() 方法,它是用来创建web容器的,而tomcat不是web容器,那它是怎么创建的呢?继续看 该方法 

private void createWebServer() {WebServer webServer = this.webServer;ServletContext servletContext = getServletContext();if (webServer == null && servletContext == null) {ServletWebServerFactory factory = getWebServerFactory();this.webServer = factory.getWebServer(getSelfInitializer());getBeanFactory().registerSingleton("webServerGracefulShutdown",new WebServerGracefulShutdownLifecycle(this.webServer));getBeanFactory().registerSingleton("webServerStartStop",new WebServerStartStopLifecycle(this, this.webServer));}else if (servletContext != null) {try {getSelfInitializer().onStartup(servletContext);}catch (ServletException ex) {throw new ApplicationContextException("Cannot initialize servlet context", ex);}}initPropertySources();}

中间一行中 factory.getWebServer(getSelfInitializer());他是通过工厂的方式创建的

追踪进去

@FunctionalInterfacepublic interface ServletWebServerFactory {WebServer getWebServer(ServletContextInitializer..、initializers);}

找它的实现类,要找tomcat如何创建,找tomcat相关的

 进去之后,找到创建tomcat的方法

@Overridepublic WebServer getWebServer(ServletContextInitializer..、initializers) {if (this.disableMBeanRegistry) {Registry.disableRegistry();}Tomcat tomcat = new Tomcat();File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");tomcat.setbaseDir(baseDir.getAbsolutePath());Connector connector = new Connector(this.protocol);connector.setThrowonFailure(true);tomcat.getService().addConnector(connector);customizeConnector(connector);tomcat.setConnector(connector);tomcat.getHost().setAutoDeploy(false);configureEngine(tomcat.getEngine());for (Connector additionalConnector : this.additionalTomcatConnectors) {tomcat.getService().addConnector(additionalConnector);}prepareContext(tomcat.getHost(), initializers);return getTomcatWebServer(tomcat);}

该过程,就是我们要找的内置tomcat以及创建tomcat的过程。

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。