為何選擇Spring Boot?

cnnbull發表於2021-09-09

原文連結:


作者注:本文概述不同的Spring配置方式並幫助你理解複雜的Spring應用配置。

Spring是一個非常流行的、基於Java語言的開發框架,常用於開發web和企業應用。不同於其它在某一領域特別出名的框架,Spring透過一系列的專案為不同的業務需求提供了許多特性。

Spring提供諸如XML、Annotations和JavaConfig等方式來提高配置java beans的靈活性。隨著Spring特性數量的不斷增加,其複雜性也不斷增加,這導致Spring應用的配置變得冗長且容易出錯。

Spring團隊建立SpringBoot專案來處理愈發複雜的配置問題。

在深入SpringBoot之前,我們先快速瀏覽一下Spring框架並理解SpringBoot試圖去解決的問題

本文將涉及如下內容:

  • Spring框架概述

  • 使用Spring MVC和JPA(Hibernate)的web應用

  • SpringBoot快速體驗

Spring框架概述

如果你是一名Java開發者,你很有可能聽說並且在你自己的專案中使用過Spring框架。Spring框架主要用於提供 依賴注入容器,但功能絕不限於此。

Spring流行的原因:

  • Spring的依賴注入方法鼓勵寫出可測試 的程式碼

  • 強大而且易用的資料庫事務管理能力

  • Spring易與諸如JPA/Hibernate ORM、Struts/JSF等web框架整合

  • 先進的Web MVC框架用於構建web應用

與Spring框架一起,還有許多Spring的專案用於構建滿足不同業務需求的應用:

  • Spring Data:簡單的關係型和NoSQL資料庫訪問框架

  • Spring Batch:批處理框架

  • Spring Security:安全框架

  • Spring Social:用於支援與Facebook、Twitter、LinkedIn、GitHub等社交網路站點的整合

  • Spring Integration:採用輕量級訊息框架和公開適配介面,用於與其他企業應用整合的整合框架

此外,還有許多用於滿足不同應用開發馮需求的專案,詳見:.

一開始的時候,Spring框架採用基於XML的方法進行java beans的配置。隨後,Spring又引入了基於XML的DSLs、Annotations和JavaConfig。

讓我們快速看一下這些方法的配置風格。

基於XML的配置方式


    
    
    
    
    
    

基於註解的配置方式

@Servicepublic class UserService{    private UserDao userDao;    @Autowired
    public UserService(UserDao dao){        this.userDao = dao;
    }
    ...
    ...
}
@Repositorypublic class JdbcUserDao{    private DataSource dataSource;    @Autowired
    public JdbcUserDao(DataSource dataSource){        this.dataSource = dataSource;
    }
    ...
    ...
}

基於JavaConfig的配置方式

@Configurationpublic class AppConfig{    @Bean
    public UserService userService(UserDao dao){        return new UserService(dao);
    }    @Bean
    public UserDao userDao(DataSource dataSource){        return new JdbcUserDao(dataSource);
    }    @Bean
    public DataSource dataSource(){
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("secret");        return dataSource;
    }
}

哇...Spring在bean配置一事上提供瞭如此多的方法,我們甚至可以在同一個應用中混用不同的方法。

如此靈活的配置方式是一把雙刃劍。Spring框架的初學者會對使用哪種方式感到困惑。現在Spring團隊建議使用基於JavaConfig的配置方式,因為這種方式提供了更高的靈活性。

但是,沒有哪種方式能夠適合所有型別的解決方案我們需要根據自己應用的需要選擇合適的配置方式。

好了,現在你已經瞭解到多種Spring配置beean的方式。

接下來,讓我們看一個典型的Spring MVC + JPA/Hibernate的web應用的配置。

使用Spring MVC和JPA(Hibernate)的web應用

在開始瞭解SpringBoot及其提供的特性之前,讓我們先看一個典型的Spring web應用程式的配置,看一下配置的痛點所在,然後我們將討論SpringBoot是如何解決這些問題的。

第一步:配置Maven依賴
我們需要做的第一件事是在pom.xml中配置所有需要的依賴。


    4.0.0
    com.sivalabs
    
  • 定義DataSource、JPA EntityManagerFactory和JpaTransactionManager為java bean

  • 配置DataSourceInitializer bean在應用啟動時透過data.sql指令碼初始化資料庫

  • application.properties中的配置資訊如下:

    jdbc.driverClassName=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/testjdbc.username=root
    jdbc.password=admin
    init-db=truehibernate.dialect=org.hibernate.dialect.MySQLDialect
    hibernate.show_sql=truehibernate.hbm2ddl.auto=update

    建立簡單的SQL指令碼data.sql將資料匯入USER表:

    delete from user;insert into user(id, name) values(1,'Siva');insert into user(id, name) values(2,'Prasad');insert into user(id, name) values(3,'Reddy');

    建立log4j.properties配置檔案如下:

    log4j.rootCategory=INFO, stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p %t %c{2}:%L - %m%n
    log4j.category.org.springframework=INFO
    log4j.category.com.sivalabs=DEBUG

    第三步:配置Spring MVC Web層beans

    配置Thymeleaf的ViewResolver,靜態ResouceHandlers和用於國際化i18n的MessageSource。

    @Configuration@ComponentScan(basePackages = { "com.sivalabs.demo"}) 
    @EnableWebMvcpublic class WebMvcConfig extends WebMvcConfigurerAdapter{    @Bean
        public TemplateResolver templateResolver() {
            TemplateResolver templateResolver = new ServletContextTemplateResolver();
            templateResolver.setPrefix("/WEB-INF/views/");
            templateResolver.setSuffix(".html");
            templateResolver.setTemplateMode("HTML5");
            templateResolver.setCacheable(false);        return templateResolver;
        }    @Bean
        public SpringTemplateEngine templateEngine() {
            SpringTemplateEngine templateEngine = new SpringTemplateEngine();
            templateEngine.setTemplateResolver(templateResolver());        return templateEngine;
        }    @Bean
        public ThymeleafViewResolver viewResolver() {
            ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
            thymeleafViewResolver.setTemplateEngine(templateEngine());
            thymeleafViewResolver.setCharacterEncoding("UTF-8");        return thymeleafViewResolver;
        }    @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry)
        {
            registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
        }    @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer)
        {
            configurer.enable();
        }    @Bean(name = "messageSource")    public MessageSource configureMessageSource()
        {
            ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
            messageSource.setBasename("classpath:messages");
            messageSource.setCacheSeconds(5);
            messageSource.setDefaultEncoding("UTF-8");        return messageSource;
        }
    }

    在WebMvcConfig.java類中,我們做了如下操作:

    • 使用@Configuration註解將其標註為Spring配置類

    • 使用@EnableWebMvc註解啟用基於Spring MVC的註解

    • 透過註冊TemplateResolver、SpringTemplateEngine和ThymeleafViewResolver,配置Thymeleaf的ViewResolver

    • 註冊資源處理bean來標明來自URI/resources/**的請求會訪問位於/resources/目錄的資源

    • 配置MessageSource載入類路徑上的messages-{country-code}.properties為i18n訊息

    現在我們沒有配置任何訊息,那就在src/main/resources資料夾下建立一個空的messages.properties檔案。

    第四步:註冊Spring MVC 前端控制servlet-DispatcherServletf
    Servlet 3.x之前的版本我們需要在web.xml中註冊servlet或者filter。Servlet 3.x及其之後的版本我們可以使用ServletContainerInitializer註冊Servlet和filter。
    Spring  MVC提供了一個方便的類:AbstractAnnotationConfigDispatcherServletInitializer用來註冊DispatcherServlet。

    public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{    @Override
        protected Class>[] getRootConfigClasses()
        {        return new Class>[] { AppConfig.class};
        }    @Override
        protected Class>[] getServletConfigClasses()
        {        return new Class>[] { WebMvcConfig.class };
        }    @Override
        protected String[] getServletMappings()
        {        return new String[] { "/" };
        }    @Override
        protected Filter[] getServletFilters() {       return new Filter[]{ new OpenEntityManagerInViewFilter() };
        }
    }

    在SpringInitializer.java類中我們做了如下事情:

    • 配置AppConfig.class作為RootConfirationClasses,它是包含所有子上下文(DispatcherServlet)bean定義的父ApplicationContext。

    • 配置WebMvcConfig.class作為ServletConfigClasses,它是包括WebMvc bean定義的子ApplicationContext。

    • 配置ServletMapping為"/",讓DispatcherServlet處理所有請求。

    • 註冊OpenEntityManagerInViewFilter過濾器,用於展開檢視時懶載入JPA實體集合。

    第五步:建立JPA實體和Spring Data JPA repository
    建立JPA實體User.java和User實體對應的Spring Data JPA repository。

    @Entitypublic class User{    @Id @GeneratedValue(strategy=GenerationType.AUTO)    private Integer id;    private String name;    //setters and getters}
    public interface UserRepository extends JpaRepository{
    }

    第六步:建立Spring MVC控制器
    建立SpringMVC控制器來處理"/"URL請求並返回使用者列表。

    @Controllerpublic class HomeController{    @Autowired UserRepository userRepo;    @RequestMapping("/")    public String home(Model model)
        {
            model.addAttribute("users", userRepo.findAll());        return "index";
        }
    }

    第七步:建立Thymeleaf檢視:/WEB-INF/views/index.html來展示使用者列表

    html>Home
        
                                                                                                                                                                    
    IdName
    IdName

    我們準備好執行程式啦。但在此之前,我們需要下載和配置諸如Tomcat或者Jetty或者Wilddfly等容器。

    你可以下載Tomcat 8並在你喜歡使用的IDE中配置並執行。然後開啟瀏覽器訪問。你可以看到user的詳細列表。
    耶...我們做到了。

    但是等等..僅僅從資料庫獲取資料並顯示使用者列表需要如此繁雜的工作嗎?

    讓我們誠實而公正的看待這個問題。所有的配置工作不都是為了這個簡單的用例。這些配置內容同樣是應用程式配置的一部分。

    但是,在迅速啟動和執行之前仍有許多工作要做。

    還有一個問題,假設你想使用相同的技術棧開發基於Spring MVC的另一個程式 。你複製黏貼配置並調整程式碼。但是記住一件事情:如果你必須重複做同樣的事情,你應該去尋找一種自動化的方法。

    除了重複寫同樣的配置,你還發現其他問題了嗎?

    好了,下面列出我發現的問題。

    • 你需要尋找依賴的特定版本的spring庫檔案並配置它們。

    • 我們配置DataSource、EntitymanagerFactory和TransactionManager等beans的工作,有95%的可能性是相同的,假如Spring可以自動配置的,那樣會不會更酷?

    • 我們用相同的方法配置許多SpringMVC bean,如ViewResolver、MessageSource等。

    如果Spring可以為我自動做這些工作,那該有多酷!!!

    設想一下,如果spring能夠自動配置bean會發生什麼?如果你可以使用簡單的配置化檔案定製自動規則會發生什麼?

    例如,你想把url的模式從"/"變更為"/app/",你想把"/WEB-INF/views"資料夾下的Thymeleaf
    展示檔案放到"/WEB-INF/templates/"資料夾下。

    因此,你需要Spring即能夠自動化配置又能夠用簡單的方式提供預設配置上的靈活的可配置性。

    好了,你可以進入可以讓你夢想成真的Spriing Boot的世界了。

    Spring Boot快速嚐鮮
    歡迎來到Spring Boot,它正是你在尋找的技術。它可以為你自動化配置並且允許你覆蓋預設配置。

    我選擇用具體的例項來介紹Spring Boot,而不是理論知識。

    因此,讓我們使用spring boot來實現與上面相同的應用。

    第一步:建立基於Maven的Spring Boot專案
    建立Maven專案餅配置如下依賴:

    
        4.0.0
        com.sivalabs
        hello-springboot
        jar
        1.0-SNAPSHOT
        hello-springboot
        
            org.springframework.boot
            spring-boot-starter-parent
            1.3.2.RELEASE
        
        
            UTF-8
            1.8
        
        
            
                org.springframework.boot
                spring-boot-starter-test
            
            
                org.springframework.boot
                spring-boot-starter-data-jpa
            
            
                org.springframework.boot
                spring-boot-starter-web
            
            
                org.springframework.boot
                spring-boot-starter-thymeleaf
            
            
                org.springframework.boot
                spring-boot-devtools
            
            
                mysql
                mysql-connector-java
            
        

    哇,我們的pom.xml瞬間變小了很多。

    第二步:在applicationroperties中配置Datasource資料來源/JPA配置檔案

    spring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/testspring.datasource.username=root
    spring.datasource.password=admin
    spring.datasource.initialize=truespring.jpa.hibernate.ddl-auto=update
    spring.jpa.show-sql=true

    你可以複製data.sql放入src/main/resources資料夾。

    第三步:建立JPA實體和spring data JPA repository介面
    建立與使用Spring MVC專案一樣的fUserva/UserRepositoryva和HomeController.java。

    第四步:建立展示使用者列表的Thymeleaf檢視
    複製springmvc-jpa-demo應用中的/WEB-INF/views/index.html到新工程的src/main/resources/templates資料夾。

    第五步:建立Spring Boot入口類
    建立含有main方法的應用入口類,如下:

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

    現在執行Application.java的main方法,開啟瀏覽器訪問。你會看到使用者列表,酷吧!!!

    好了,我彷彿聽見了你再說:發生了什麼事情???我來介紹下發生了什麼。

    1.簡單的依賴管理

    • 最顯而易見的是我們使用了許多spring-boot-starter-*的依賴。還記得我說的95%的配置都是相同的嗎?所以當你新增springboot-starter-web依賴時,你將會新增依賴到spring-webmvc、jackson-json、validation-api和tomcat等公共依賴庫。

    • 我們新增了spring-boot-starter-data-jpa依賴。這將拉去所有spring-data-jpa依賴並且新增Hibernate庫,因為應用使用Hibernate作為JPA實現。
      2.自動配置

    • 不僅能顧透過spring-boot-starer-web新增所有依賴庫,而且諸如DispatcherServlet、ResourceHandlers和MessageSource等通用註冊帶的beans也能透過預設的方式自動配置。

    • 我們新增spring-boot-starter-Thymeleaf不僅新增所有Thymeleaf庫依賴,而且自動配置ThymeleafViewResolver。

    • 我們沒有定義諸如DataSource、EntityManagerFactory、TransactionManager等beans但是工程會自動建立它們。如何做到的?如果我們使用記憶體資料庫驅動(如H2或者HSQL),透過預設配置SpringBoot會自動建立記憶體資料來源並註冊EntityManagerFactory、TransactionManager。但我們使用的是MySQL,因此我們需要明確提供MySQL連線的詳細資訊。我們在application.properties檔案中配置MySQL連線資訊,然後SpringBoot透過該配置檔案建立DataSource。
      3.內建Servelet容器支援
      最重要和令人稱奇的是我們透過@SpringAplication註解一個簡單java類,然後執行該java類的main方法後就可以訪問

    servlet容器從何來而?我們新增spring-boot-starter-web依賴會自動拉取spring-boot-starter-tomcat依賴,當我們執行main()方法時,Tomcat會作為一個內建容器啟動,因此我們不必將我們的應用部署到外部的tomcat容器中。

    另外,你是否發現我們pom.xml中的打包型別是jar而不是war額嗎?多麼棒的一件事情。

    好了,如果我想用Jetty代替Tomcat怎麼辦呢?從spring-boot-starter-web中排除spring-bootstarter-tomcat幷包含spring-boot-starter-jetty。

    只需要做這些,這是多麼的奇妙!

    我們設想你在想什麼。你在想SpringBoot看上去如此酷並能自動為我做很多事情。但是我還是不太明白它背後是如何工作的,對嗎?

    我能理解。看魔術表演很有趣,但是軟體開發則不然。別擔心,在將來的文章中,我將逐步介紹每件事並詳細介紹表象後面發生的具體事情。但是,我不打算在本文中將一切內容和盤托出,因為這會壓垮你。

    總結
    本文中我們快速瀏覽了不同Spring配置風格並理解了配置Spring應用的複雜性。同時,我們透過一個簡單的web應用快速體驗了SprngBoot。



    來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2524/viewspace-2802967/,如需轉載,請註明出處,否則將追究法律責任。

    相關文章