成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

自己動手實現精簡版SpringBoot原來如此簡單

開發 前端
Spring Boot是一個強大而簡單的框架,它讓開發者能夠快速創建和運行應用程序。無論你是初學者還是有一定經驗的開發者,Spring Boot都能夠為你提供便利和高效的開發體驗。

環境:Spring5.3.23

1. 概述

Spring Boot是一個開源的非常流行的Java框架,由Pivotal團隊開發,用于簡化Spring應用程序的創建和部署。它遵循約定優于配置的原則,讓開發者能夠快速搭建和運行應用程序。Spring Boot通過自動配置和內置的依賴管理,簡化了Spring應用程序的初始搭建以及開發過程。

Spring Boot為開發者提供了許多有用的功能,包括:

  1. 自動配置:Spring Boot會自動配置應用程序所需的各種組件,減少了手動配置的工作量。
  2. 嵌入式Web服務器:Spring Boot內置了Tomcat和Jetty等Web服務器,使得應用程序能夠快速啟動和運行。
  3. 約定優于配置的原則:Spring Boot遵循約定優于配置的原則,讓開發者能夠使用默認的配置,而無需過多地關注底層技術實現。
  4. 強大的依賴管理:Spring Boot提供了強大的依賴管理功能,能夠自動管理應用程序所需的依賴項。
  5. 安全性:Spring Boot提供了安全性功能,包括身份驗證和授權等,確保應用程序的安全性。

總之,Spring Boot是一個強大而簡單的框架,它讓開發者能夠快速創建和運行應用程序。無論你是初學者還是有一定經驗的開發者,Spring Boot都能夠為你提供便利和高效的開發體驗。在接下來的文章中,我們將通過自己動手寫一個簡單的Spring Boot應用程序來揭示這個過程原來如此簡單。讓我們一起開始這個項目吧!

提示:本篇文章需要你對Spring啟動流程有一點的了解。

2. 動手實現

2.1 自定義Web類型的ApplicationContext

我們需要在自定義的ApplicationContext合適的方法中去啟動內嵌的Tomcat。

public class PackAnnotationApplicationContext extends GenericWebApplicationContext {


  public PackAnnotationApplicationContext() {
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this);
  }


  @Override
  protected void onRefresh() {
    super.onRefresh();
    try {
      // 創建WebServer
      createWebServer() ;
    } catch (Exception e) {
      throw new ApplicationContextException("Unable to start web server", e) ;
    }
  }


  @Override
  protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    beanFactory.addBeanPostProcessor(new PackServletContextAwareProcessor(this)) ;
    super.postProcessBeanFactory(beanFactory);
  }


  private void createWebServer() throws Exception {
    final int PORT = 8088 ;


    Tomcat tomcat = new Tomcat() ;
    // 獲取Server節點 ---》 server.xml 【Server節點】
    Server server = tomcat.getServer() ;
    // 獲取Service節點 ---》 server.xml 【Server---> Service節點】
    Service service = server.findService("Tomcat") ;


    // 配置Connector ---》 server.xml 【Server---> Service--->Connector節點】
    Http11NioProtocol protocol = new Http11NioProtocol() ;
    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()) ;
    // 配置Connector ---》 server.xml 【Server---> Service--->Executor節點】
    protocol.setExecutor(executor) ;
    protocol.setConnectionTimeout(20000);
    Connector connector = new Connector(protocol) ;
    // 設置訪問端口
    connector.setPort(PORT) ;
    connector.setURIEncoding("UTF-8") ;
    service.addConnector(connector) ;


    // 配置Engine ---》 server.xml 【Server--->Service--->Engine】
    StandardEngine engine = new StandardEngine() ;
    // 這里的設置的默認host要和下面StandardHost設置的name一致
    engine.setDefaultHost("localhost");
    // 配置Engine ---》 server.xml 【Server--->Service--->Engine--->Host】
    StandardHost host = new StandardHost() ;
    host.setName("localhost") ;
    host.setAppBase(System.getProperties().getProperty("user.home")) ;
    engine.addChild(host) ;
    service.setContainer(engine) ;


    // 配置Context ---》 server.xml 【Server--->Service--->Engine--->Host--->Context】
    StandardContext context = new StandardContext() ;
    // 如果不配置這個,則會有這個錯誤:One or more components marked the context as not correctly configured
    context.addLifecycleListener(new FixContextListener()) ;
    // 訪問路徑
    context.setPath("");
    // Context節點添加到Host節點
    host.addChild(context) ;


    context.addServletContainerInitializer(new ServletContainerInitializer() {
      @Override
      public void onStartup(Set<Class<?>> c, ServletContext servletContext) throws ServletException {
        // 這個的主要作用是,當一個Bean實現了ServletContextAware接口時,用來注入該ServletContext對象
        PackAnnotationApplicationContext.this.setServletContext(servletContext) ;
        DispatcherServlet dispatcherServlet = PackAnnotationApplicationContext.this.getBean(DispatcherServlet.class) ;
        Dynamic dynamic = servletContext.addServlet("dispatcherServlet", dispatcherServlet) ;
        dynamic.setLoadOnStartup(0) ;
        dynamic.addMapping("/*") ;
      }
    }, null);
    tomcat.start();
  }
}

如上,我們做了2件非常重要的事:1. 重寫onRefresh方法。2. 創建內嵌的Tomcat服務。

2.2 自定義啟動類程序PackSpringApplication

該類就是用來模擬SpringBoot中的SpringApplication對象。

public class PackSpringApplication {


  private Class<?>[] primarySources ;


  public PackSpringApplication(Class<?>[] primarySources) {
    this.primarySources = primarySources ;
  }


  public ConfigurableApplicationContext run(String[] args) {
    ConfigurableApplicationContext context =  new PackAnnotationApplicationContext() ;
    prepareEnvironment(context, args) ;
    prepareContext(context) ;
    refreshContex(context) ;
    return context ;
  }
  // 刷新上下文,核心就是調用AbstractApplicationContext#refresh方法
  private void refreshContex(ConfigurableApplicationContext context) {
    context.refresh() ;
  }
  // 注備上下文環境,這里簡單處理了命令行參數
  private void prepareEnvironment(ConfigurableApplicationContext context, String[] args) {
    ConfigurableEnvironment environment = new StandardEnvironment() ;
    PropertySource<?> propertySource = new SimpleCommandLinePropertySource(args) ;
    environment.getPropertySources().addFirst(propertySource) ;
    context.setEnvironment(environment) ;
  }
  // 準備上下文
  private void prepareContext(ConfigurableApplicationContext context) {
    BeanDefinitionRegistry registry = getBeanDefinitionRegistry(context) ;
    BeanNameGenerator generator = new DefaultBeanNameGenerator() ; 
    for (Class<?> clazz : primarySources) {
      AbstractBeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(clazz).getBeanDefinition() ;
      registry.registerBeanDefinition(generator.generateBeanName(definition, registry), definition) ;
    }
  }


  private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
    if (context instanceof BeanDefinitionRegistry) {
      return (BeanDefinitionRegistry) context;
    }
    if (context instanceof AbstractApplicationContext) {
      return (BeanDefinitionRegistry) ((AbstractApplicationContext) context).getBeanFactory();
    }
    throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
  }
  public static ConfigurableApplicationContext run(Class<?> primarySource, String[] args) {
    return new PackSpringApplication(new Class<?>[] {primarySource}).run(args) ;
  }
}

以上大致模擬的就是Spring Boot啟動執行流程的步驟。

2.3 定義Web請求相關的配置

@Configuration
public class WebConfig {


  @Bean
  public DispatcherServlet dispatcherServlet() {
    DispatcherServlet dispatcherServlet = new DispatcherServlet();
    dispatcherServlet.setDispatchOptionsRequest(true) ;
    dispatcherServlet.setDispatchTraceRequest(true) ;
    dispatcherServlet.setThrowExceptionIfNoHandlerFound(true) ;
    dispatcherServlet.setPublishEvents(true) ;
    dispatcherServlet.setEnableLoggingRequestDetails(true) ;
    return dispatcherServlet ;
  }
}

這里為了讓你更加清晰的認識到SpringMVC相關的內容,就不使用@EnableWebMvc該注解。

有了上面的配置,接下來就可以寫個測試程序進行測試

2.4 測試

測試Controller接口

@RestController
@RequestMapping("/demo")
public class DemoController {


  @GetMapping("/index")
  public Object index() {
    return "index......" ;
  }
  @GetMapping("/body")
  public User body() {
    return new User(1, "測試") ;
  }
}

測試啟動類

@Configuration
@ComponentScan({"com.pack.main.programmatic_tomcat_04"})
public class DemoApplication {


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

測試第一個接口:/demo/index

圖片圖片

測試第二個接口:/demo/body

圖片圖片

返回406狀態碼,程序出錯了,這是因為在默認情況下,SpringMVC會使用系統默認提供的RequestMappingHandlerAdapter對象進行目標Controller的調用。但是默認的HandlerAdapter對象并不能處理返回值是這種對象類型。而默認支持支如下4中類型:

  1. ByteArrayHttpMessageConverter
  2. StringHttpMessageConverter
  3. SourceHttpMessageConverter
  4. AllEncompassingFormHttpMessageConverter
     

所以,這里我們需要自定義RequestMappingHandlerAdapter。在WebConfig中定義該Bean對象,設置

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
  RequestMappingHandlerAdapter handlerAdapter = new RequestMappingHandlerAdapter() ;
  List<HttpMessageConverter<?>> messageConverters = new ArrayList<>() ;
  messageConverters.add(new StringHttpMessageConverter());
  messageConverters.add(new MappingJackson2HttpMessageConverter()) ;
  handlerAdapter.setMessageConverters(messageConverters) ;
  return handlerAdapter ;
}

再次測試

圖片圖片

責任編輯:武曉燕 來源: Spring全家桶實戰案例源碼
相關推薦

2010-08-25 21:50:36

配置DHCP

2009-04-29 01:39:57

破解美萍萬象

2024-07-25 09:20:00

地圖場景

2010-09-17 17:41:54

2012-07-04 13:36:08

無線網絡H3C

2010-06-12 17:12:21

PPPOE協議

2023-03-10 10:47:06

Xubuntu發行版

2010-09-16 08:14:00

2010-05-20 14:46:34

2018-01-05 12:39:23

網吧電腦故障

2022-01-12 23:42:48

網頁復制鼠標

2020-12-27 10:57:30

QQ谷歌 Play移動應用

2020-03-09 17:46:49

AMD7nmN7P

2010-09-17 15:36:21

2011-09-02 13:38:56

PhoneGap插件Android

2023-06-06 07:08:27

網絡防火墻應用網關

2011-08-12 10:46:57

Linux

2022-09-27 07:00:58

QoS服務帶寬

2017-09-15 18:13:57

機器學習深度學習語音識別

2020-10-27 11:01:40

5G網絡移動
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 少妇精品久久久久久久久久 | 成人老司机 | 毛片久久久| 99久久婷婷国产综合精品电影 | 久久精品亚洲精品 | 无码一区二区三区视频 | 成人精品在线观看 | 高清人人天天夜夜曰狠狠狠狠 | 韩日一区| 色婷婷av一区二区三区软件 | 欧美精品综合 | 欧美日韩一二三区 | 国产精品久久久久久吹潮 | 中文字幕精品一区 | 久久伊人精品一区二区三区 | 精品久久久久久久久久久久 | 国产精品18久久久 | 国产美女黄色 | 日本 欧美 三级 高清 视频 | 国内精品视频在线 | 日本特黄a级高清免费大片 国产精品久久性 | 在线天堂免费中文字幕视频 | 国产日韩欧美一区二区在线播放 | ririsao久久精品一区 | 欧洲精品久久久久毛片完整版 | 精品国产一区二区三区免费 | 91av亚洲| 日韩在线免费播放 | 在线观看日韩 | 久久久成人精品 | 亚洲精品国产电影 | 亚洲精品66| 中文字幕国产第一页 | aa级毛片毛片免费观看久 | 奇米久久 | 992tv人人草 久久精品超碰 | 国产一区二区三区免费 | 日韩成人久久 | 成人国产精品久久久 | 日韩在线不卡视频 | 成人av网站在线观看 |