<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在日常開發中只需要引入下面的依賴就可以開發Servlet進行存取了。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
那這是怎麼做到的呢?今天就來一探究竟
首先新建一個maven專案rick-spring-boot,並建立兩個子專案分別是spring-boot和user,其中spring-boot專案就是模擬手寫一個簡單springboot,user就是用來測試手寫的spring-boot的。
user專案-測試工程
user專案包含pom.xml、UserController和UserService
<dependencies> <dependency> <groupId>com.rick.spring.boot</groupId> <artifactId>spring-boot</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
@RestController public class UserController { @Autowired private UserService userService; @GetMapping("/user") public String getUser() { return userService.getUser(); } } @Service public class UserService { public String getUser() { return "rick"; } }
以及user專案的啟動類RickApplication,而RickSpringApplication.run()是需要手寫的啟動類以及@RickSpringBootApplication註解,都是需要在spring-boot專案實現。
import com.rick.spring.boot.RickSpringApplication; import com.rick.spring.boot.RickSpringBootApplication; @RickSpringBootApplication public class RickApplication { public static void main(String[] args) { RickSpringApplication.run(RickApplication.class); } }
首先來看RickSpringApplication.run(RickApplication.class)方法需要做的事情:
(1)建立spring容器,並將傳入的class註冊到spring容器中
(2)啟動web服務,如tomcat,用來處理請求,並通過DispatchServlet將請求分發到Servlet進行處理。
public class RickSpringApplication { public static void run(Class clz) { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(clz); context.refresh(); start(context); } public static void start(WebApplicationContext applicationContext) { System.out.println("start tomcat"); Tomcat tomcat = new Tomcat(); Server server = tomcat.getServer(); Service service = server.findService("Tomcat"); Connector connector = new Connector(); connector.setPort(8081); Engine engine = new StandardEngine(); engine.setDefaultHost("localhost"); Host host = new StandardHost(); host.setName("localhost"); String contextPath = ""; Context context = new StandardContext(); context.setPath(contextPath); context.addLifecycleListener(new Tomcat.FixContextListener()); host.addChild(context); engine.addChild(host); service.setContainer(engine); service.addConnector(connector); tomcat.addServlet(contextPath, "dispatcher", new DispatcherServlet(applicationContext)); context.addServletMappingDecoded("/*", "dispatcher"); try { tomcat.start(); } catch (LifecycleException e) { e.printStackTrace(); } } }
RickApplication是被@RickSpringBootApplication註解修飾的,從如下程式碼可以看出RickApplication是設定類,在被註冊到spring容器後,spring就會解析這個類。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Configuration @ComponentScan public @interface RickSpringBootApplication { }
啟動user專案RickApplication的main方法,
存取UserController
至此一個簡單的spring-boot專案就整合完成了。
實現tomcat和jetty的切換
在使用springboot時,如果我們不想使用tomcat作為請求處理服務,而是jetty或者其他的web服務,通常只需要將相關的tomcat依賴進行排除,然後引入jetty的依賴就可以了,這就是springboot的自動裝配的機制。接下來看看是如何實現的
定義一個WebServer介面和兩個實現類(tomcat和jetty),並寫好啟動tomcat和jetty服務的程式碼
public interface WebServer { void start(); } public class JettyServer implements WebServer{ @Override public void start() { System.out.println("start jetty"); } }
public class TomcatServer implements WebServer, ApplicationContextAware { private WebApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = (WebApplicationContext) applicationContext; } @Override public void start() { System.out.println("start tomcat"); ... tomcat.addServlet(contextPath, "dispatcher", new DispatcherServlet(applicationContext)); context.addServletMappingDecoded("/*", "dispatcher"); try { tomcat.start(); } catch (LifecycleException e) { e.printStackTrace(); } } }
定義AutoConfiguration介面,用來標識需要自動裝配的類。再定義一個WebServerAutoConfiguration類,它被表示為spring的一個設定類,最終我們需要匯入這個類由spring來解析它,隨後spring會解析@Bean註解的方法來載入Bean。注意這裡下面兩個方法還定義了@RickConditionalOnClass註解來決定是否需要解析這個bean,如果滿足條件則進行解析,即應用記憶體在Tomcat或者Server的Class,會解析對應方法的Bean,
public interface AutoConfiguration { } @Configuration public class WebServerAutoConfiguration implements AutoConfiguration { @Bean @RickConditionalOnClass("org.apache.catalina.startup.Tomcat") public TomcatServer tomcatServer() { return new TomcatServer(); } @Bean @RickConditionalOnClass("org.eclipse.jetty.server.Server") public JettyServer jettyWebServer() { return new JettyServer(); } }
來看@RickConditionalOnClass註解:當spring解析被@RickConditionalOnClass註解的方法時,spring就知道它被@Conditional修飾,並會在解析時執行RickOnClassConditional的match()方法,來判斷是否滿足載入bean的條件。match()會嘗試載入傳入的類路徑名,如果應用內引入相關的jar則會載入成功返回true,反之,返回false。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Conditional(RickOnClassConditional.class) public @interface RickConditionalOnClass { String value(); } public class RickOnClassConditional implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Map<String, Object> annotation = metadata.getAnnotationAttributes(RickConditionalOnClass.class.getName()); try { context.getClassLoader().loadClass((String) annotation.get("value")); } catch (ClassNotFoundException e) { return false; } return true; } }
引入WebServerAutoConfiguration,最簡單粗暴的方式就是通過@Import(WebServerAutoConfiguration.class)匯入該類。但是spring-boot不可能這麼做,成千上百的自動設定寫在程式碼裡肯定不好。spring通過SPI機制,在resources目錄下建立如下目錄和檔案
定義一個類實現DeferredImportSelector介面,並實現selectImports(),通過JDK的ServiceLoader載入以上檔案中的類。通過@Import(WebServerImportSelector.class)註解匯入該類spring在解析設定類的時候就會執行selectImports(),從而將WebServerAutoConfiguration匯入到spring容器中,spring就會解析這個設定類。
public class WebServerImportSelector implements DeferredImportSelector { @Override public String[] selectImports(AnnotationMetadata metadata) { ServiceLoader<AutoConfiguration> load = ServiceLoader.load(AutoConfiguration.class); List<String> list = new ArrayList<>(); for (AutoConfiguration loader : load) { list.add(loader.getClass().getName()); } return list.toArray(new String[list.size()]); } }
至此,springboot就做到了只需要修改user工程的maven依賴就能切換tomcat和jetty服務了
<dependency> <groupId>com.rick.spring.boot</groupId> <artifactId>spring-boot</artifactId> <version>1.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> <version>9.4.43.v20210629</version> </dependency>
重啟user專案
通過手寫模擬springboot,加深對springboot底層原理的理解,對於開發和使用更加得心應手。springboot本章小結:
1、springboot主要是整合spring框架和內嵌web伺服器的框架
2、springboot通過條件註解、實現spring DeferredImportSelector介面和JDK自帶的SPI機制實現了自動裝配的功能
到此這篇關於SpringBoot超詳細深入講解底層原理的文章就介紹到這了,更多相關SpringBoot底層原理內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45