成人免费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-05-20 14:46:34

2010-09-16 08:14:00

2020-12-27 10:57:30

QQ谷歌 Play移動應用

2018-01-05 12:39:23

網吧電腦故障

2022-01-12 23:42:48

網頁復制鼠標

2010-09-17 15:36:21

2011-09-02 13:38:56

PhoneGap插件Android

2023-06-06 07:08:27

網絡防火墻應用網關

2020-03-09 17:46:49

AMD7nmN7P

2011-08-12 10:46:57

Linux

2017-09-15 18:13:57

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

2022-09-27 07:00:58

QoS服務帶寬

2020-10-26 07:03:35

機器學習算法
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 男人天堂网av | 久久久久久久久99 | 91文字幕巨乱亚洲香蕉 | 精品欧美一区免费观看α√ | 久久久久久国产精品免费免费狐狸 | 日本三级做a全过程在线观看 | 国产一区二区三区在线视频 | 美女视频一区二区三区 | 97精品超碰一区二区三区 | 国产精品久久久久久中文字 | 国产成人精品一区二区三区四区 | 欧美成人猛片aaaaaaa | av一级毛片| 久久夜色精品国产 | 亚洲欧美精 | 第一色在线 | 亚洲最大的黄色网址 | 91观看| 久久久久se | 一区欧美 | 日韩国产精品一区二区三区 | 激情网站| 91偷拍精品一区二区三区 | 日韩成人在线电影 | 老司机深夜福利网站 | 久久综合国产精品 | 91n成人 | 国产一区二区 | 久久综合九色综合欧美狠狠 | 91亚洲一区| 亚洲一区二区三区四区五区午夜 | 中国一级特黄毛片大片 | 久久久久亚洲精品 | 天天爽一爽 | 自拍偷拍中文字幕 | 九九热精品视频 | 国产成人综合一区二区三区 | 午夜影视在线观看 | 国产精品久久久久久久久久三级 | 91久久精品一区二区二区 | 欧美精品综合在线 |