三 Springboot入门详解

​ 在上一章,我们对Springboot进行了入门,接下来我们就来看一下一些细节。

3.1 pom.xml研究

  • 分析思路,只要是maven项目就先分析pom.xml
  • pom.xml中分析三个要素:依赖,插件,parent

3.1.1 父依赖 parent

  1. 父依赖代码

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
  2. 父依赖作用分析-资源过滤,插件管理

    <build>
        <!--资源配置-->
        <resources>
            <resource>
                <filtering>true</filtering>
                <directory>${basedir}/src/main/resources</directory>
                <!--此处包含了yml配置-->
                <includes>
                    <include>**/application*.yml</include>
                    <include>**/application*.yaml</include>
                    <include>**/application*.properties</include>
                </includes>
            </resource>
            ......
        </resources>
        <!--插件配置-->
        <pluginManagement> 
        	<plugins>
                ......
                打包插件配置
             	<plugin>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-maven-plugin</artifactId>
                  <executions>
                    <execution>
                      <id>repackage</id>
                      <goals>
                        <goal>repackage</goal>
                      </goals>
                    </execution>
                  </executions>
                  <configuration>
                    <mainClass>${start-class}</mainClass>
                  </configuration>
                </plugin>
            	......
        	</plugins>
        </pluginManagement>
    </build>
    
  3. 继续看一下父依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath>../../spring-boot-dependencies</relativePath>
      </parent>
     <!--进行了很多依赖的版本配置-->
    <properties>
        <activemq.version>5.15.11</activemq.version>
        <antlr2.version>2.7.7</antlr2.version>
        <appengine-sdk.version>1.9.78</appengine-sdk.version>
        <artemis.version>2.10.1</artemis.version>
        <aspectj.version>1.9.5</aspectj.version>
        <assertj.version>3.13.2</assertj.version>
        <atomikos.version>4.0.6</atomikos.version>
        <awaitility.version>4.0.2</awaitility.version>
        <bitronix.version>2.1.4</bitronix.version>
        <build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version>
        <byte-buddy.version>1.10.8</byte-buddy.version>
        <caffeine.version>2.8.1</caffeine.version>
        ....
    </properties>
    
    <!--进行了很多依赖管理,意味着我们以后要用是直接引用,不用加版本了。比如:
    		<dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot</artifactId>
                <version>2.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-test</artifactId>
                <version>2.2.5.RELEASE</version>
            </dependency>
            ......
        </dependencies>
    </dependencyManagement>
     
    
    
    

3.1.2 启动器

​ 在Springboot中,需要集成某个模块只需要引入对应场景启动器模块就ok,比如web支持spring-boot-starter-web,并且在parent已经配置了版本,直接引入就ok

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
....

3.1.3 打包插件配置

​ 由于在parent中对插件进行了配置,所以我们只需要以下方式引入就ok。

3.1.4 总结

总结:依赖spring-boot-starter-parent可以实现

  1. 引入这个之后相关的引入就不需要添加version配置,spring boot会自动选择最合适的版本进行添加。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
  2. 并且给我做了打包等插件的配置。以后只需声明插件就ok了,不需要设置版本。

    <build>
        <!--插件-->
        <plugins>
            <!--打包插件:将项目打成jar包或者war包-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    

    所以非常方便!

3.2 启动类分析

3.2.1 javaconfig介绍

  • 传统的XML形式 applicationContext.xml
<bean id="..." class="..." />
<import class="...">
<mvc:componentScan="">
  • 注解的配置形式 applicationContext
@Configuragtion
@import
@componentScan()
class applicationContext{
    //方法名就是xml中对应的id,返回值类型就是对应的class
    @Bean
    public User user(){
        
    }
}

3.2.2 启动类@SpringBootApplication

@SpringBootApplication  //一个注解
public class Springboot01HelloApplication {
  //一个方法
    public static void main(String[] args) {
        SpringApplication.run(Springboot01HelloApplication.class, args);
    }
}
  • @SpringBootApplication:代表这个类是一个启动类

  • 咱们进入这个注解,可以看到代码如下:

    ...
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(...) // 对应xml中的很多scan标签
    public @interface SpringBootApplication {
    ...
    }
    
  • @ComponentScan:扫描包,将扫描当前包及其子包中加了@Controller,@Service,@Component等注解的bean放到spring中去

  • @SpringBootConfiguration:就是一个配置类

    ...
    @Configuration //这是一个配置类
    public @interface SpringBootConfiguration {
    
    	boolean proxyBeanMethods() default true;
    
    }
    
    @Component //这是一个组件
    public @interface Configuration {
        ...
    }
    
  • @EnableAutoConfiguration:开启自动配置功能

    在这个下面我们可以看到代码里有两个注解

    @AutoConfigurationPackage  //自动包配置
    @Import(AutoConfigurationImportSelector.class) //导入一个配置注入选择器
    

在这里插入图片描述

①Springboot应用入口类通过@SpringBootApplication注解简介使用@EnableAutoConfiguration(是父注解)
②使用@EnableAutoConfiguration后,会扫描所有jar中的spring.factories文件,加载所有的配置类(加了  @Configuration的类)
③配置类(加了@Configuration的类)使用XxxProperties以@Bean的方式完成对应场景的配置
④XxxPropereis里面的配置信息有默认值,但是我们可以在application.properties/application.yml中获取

3.2.3 启动类中的run方法分析

  1. Tomcat配置分析

    项目中配置了
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    进去看
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-tomcat</artifactId>
         <version>2.2.5.RELEASE</version>
         <scope>compile</scope>
    </dependency>
    

    ServletWebServerFactoryConfiguration类中,TomcatServletWebServerFactory 会被作为bean被spring管理起来。根据注解@ConditionalOnClass。。条件,因为没有引入jetty相关的jar,spring中不会有JettyServletWebServerFactory这个bean。

    @Configuration(proxyBeanMethods = false)
    class ServletWebServerFactoryConfiguration {
    
    	@Configuration(proxyBeanMethods = false)
    	@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
    	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
    	static class EmbeddedTomcat {
    
    		@Bean
    		TomcatServletWebServerFactory tomcatServletWebServerFactory(
    				ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
    				ObjectProvider<TomcatContextCustomizer> contextCustomizers,
    				ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
    			TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    			factory.getTomcatConnectorCustomizers()
    					.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
    			factory.getTomcatContextCustomizers()
    					.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
    			factory.getTomcatProtocolHandlerCustomizers()
    					.addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
    			return factory;
    		}
    
    	}
    
    	/**
    	 * Nested configuration if Jetty is being used.
    	 */
    	@Configuration(proxyBeanMethods = false)
    	@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
    	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
    	static class EmbeddedJetty {
    
    		@Bean
    		JettyServletWebServerFactory JettyServletWebServerFactory(
    				ObjectProvider<JettyServerCustomizer> serverCustomizers) {
    			JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
    			factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));
    			return factory;
    		}
    
    	}
    
  2. 启动分析

    首先从main函数开始

//main 函数
@SpringBootApplication
public class Demo1Application {
 
	public static void main(String[] args) {
		SpringApplication.run(Demo1Application.class, args);
	}
 
}
 
//点击run
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}
//继续点击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 {
			//略。。。。。
			refreshContext(context);//点击进入。。。。。。。。。。。
			afterRefresh(context, applicationArguments);
			//略。。。。
		return context;
	}

点击refreshContext(context);方法

点击-->refresh(context);-->((AbstractApplicationContext) applicationContext).refresh();-->进入类AbstractApplicationContext的refresh方法
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 {
				//略。。。。
				onRefresh();//点击进入
                //略
 
				
		}

进入类ServletWebServerApplicationContext的onRefresh()方法

@Override
	protected void onRefresh() {
		super.onRefresh();
		try {
			createWebServer();//点击进入。。。。。。
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}
 
//点击createWebServer()方法
private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
            //点击进入
			ServletWebServerFactory factory = getWebServerFactory();
//点击进入
			this.webServer = factory.getWebServer(getSelfInitializer());
		}
		else if (servletContext != null) {
			try {
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context", ex);
			}
		}
		initPropertySources();
	}

getWebServerFactory() 会TomcatServletWebServerFactory。所以factory.getWebServer(getSelfInitializer())中的factory是指TomcatServletWebServerFactory,点击进入实现类TomcatServletWebServerFactory的getWebServer(getSelfInitializer())方法。
	public WebServer getWebServer(ServletContextInitializer... initializers) {
		Tomcat tomcat = new Tomcat();
		File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
		tomcat.setBaseDir(baseDir.getAbsolutePath());
		Connector connector = new Connector(this.protocol);
		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);
		}
        //TOmcat关联Spring容器
		prepareContext(tomcat.getHost(), initializers);
		return getTomcatWebServer(tomcat);//点击进入。。。。。。。。
	}
//点击进入getTomcatWebServer(tomcat)
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
		return new TomcatWebServer(tomcat, getPort() >= 0);//点击进入
	}
//点击new TomcatWebServer 
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
		Assert.notNull(tomcat, "Tomcat Server must not be null");
		this.tomcat = tomcat;
		this.autoStart = autoStart;
		initialize();//点击进入
	}
//点击进入
private void initialize() throws WebServerException {
		logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
		synchronized (this.monitor) {
			try {
				
				// 略。。。。。。。
				this.tomcat.start();//。。。。启动tomcat
 
				// We can re-throw failure exception directly in the main thread
				rethrowDeferredStartupExceptions();
 
				try {
					ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
				}
				//略。。。。。。。。。。。。。。
		}
	}

3.2.3 小结

​ 当运行run时,会创建Spring容器,并关联到内置tomcat,并完成Tomcat启动。

欢迎入群交流和获取源代码和视频资料。
Q群:1049572529 微信群:添加“liuhuaxinting1314”微信入群!发起请求请备注“csdn”!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值