Spring 是一個非常流行的基於Java語言的開發框架,此框架用來構建web和企業應用程式。與許多其他僅關註一個領域的框架不同,Spring框架提供了廣泛的功能,通過其組合項目滿足現代業務需求。 Spring框架提供了以多種方式配置bean的靈活性,例如XML,註解和JavaConfig。隨著功能 ...
Spring 是一個非常流行的基於Java語言的開發框架,此框架用來構建web和企業應用程式。與許多其他僅關註一個領域的框架不同,Spring框架提供了廣泛的功能,通過其組合項目滿足現代業務需求。
Spring框架提供了以多種方式配置bean的靈活性,例如XML,註解和JavaConfig。隨著功能數量的增加,複雜性也會增加,配置Spring應用程式變得乏味且容易出錯。
Spring團隊創建了Spring Boot來解決配置的複雜性。
但在深入瞭解SpringBoot之前,我們將快速瀏覽一下Spring框架,看看SpringBoot試圖解決的問題是什麼。
在本文中,我們將介紹:
- Spring框架概述
- 使用Spring MVC和JPA(Hibernate)的Web應用
- 快速試用SpringBoot
Spring 框架概述
如果你是 Java 開發人員,那麼你多半聽說過 Spring 框架,甚至可能在項目中使用過這一框架。Spring 框架主要起源於一個依賴註入容器,但它遠不止於此。
Spring 之所以流行,是因為:
- Spring 的依賴註入方法支持編寫可測試的代碼
- 強大且易用的資料庫事務管理能力
- Spring 非常容易與其它 Java 框架集成,如 JPA/Hibernate ORM、Struts、JSF等。
- 使用前沿的 MVC 框架構建 Web 應用
Spring 除了框架之外,還有很多姊妹項目可以助力構建滿足現代業務需求的應用程式:
- Spring Data:為訪問關係型資料庫或 NoSQL 資料庫提供便利。
- Spring Batch:強大的批處理框架。
- Spring Security:為安全應用而生的強健的安全框架。
- Spring Social:支持整合社區網路,比如 Facebook、Twitter、LinkedIn、Github 等。
- Spring Integration:企業級集成模型的實現,使用輕量級的消息傳遞和聲明式適配器與其他企業應用集成。
還有不少其他有趣的項目,他們用於解決各種現代應用開發需求。欲知詳情,請看 http://spring.io/projects。
Spring 框架一開始提供了基於 XML 的方法來配置 Bean。之後 Spring 引入了基於 XML 的 DSL、註解和 JavaConfig 來配置 Bean 的方法。
讓我們快速看看每種配置方式的樣子。
基於XML的配置

基於註釋的配置

基於JavaConfig的配置

哇… Spring提供了很多方法來做同樣的事情,我們甚至可以混合使用這些方法,併在同一個應用程式中同時使用基於JavaConfig和註解的配置方式。
但是沒有一種適合所有類型的解決方案。必鬚根據自己的應用需求選擇方法。
好了,現在您已經看到了各種樣式的Spring bean配置的例子。
讓我們快速瀏覽一下典型的SpringMVC + JPA / Hibernate Web應用程式配置的樣子。
使用Spring MVC和JPA(Hibernate)的Web應用程式
在瞭解SpringBoot是什麼以及提供了什麼樣的功能之前,讓我們先看看典型的Spring Web應用程式配置如何,難點又是什麼,其次我們論述SpringBoot將如何解決這些問題。
第1步:配置Maven依賴項
首要的是我們需要配置pom.xml中所需的所有依賴項。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.sivalabs</groupId> <artifactId>springmvc-jpa-demo</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>springmvc-jpa-demo</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.9.2.RELEASE</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.13</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.13</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.13</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.4.190</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.3.11.Final</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring4</artifactId> <version>2.1.4.RELEASE</version> </dependency> </dependencies> </project>
我們已經配置好了所有Maven jar依賴項,包括Spring MVC,Spring Data JPA,JPA / Hibernate,Thymeleaf和Log4j。
第 2 步:使用 JavaConfig 配置 Service/DAO 層的 Bean
@Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages="com.sivalabs.demo") @PropertySource(value = { "classpath:application.properties" }) public class AppConfig { @Autowired private Environment env; @Bean public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } @Value("${init-db:false}") private String initDatabase; @Bean public PlatformTransactionManager transactionManager() { EntityManagerFactory factory = entityManagerFactory().getObject(); return new JpaTransactionManager(factory); } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setGenerateDdl(Boolean.TRUE); vendorAdapter.setShowSql(Boolean.TRUE); factory.setDataSource(dataSource()); factory.setJpaVendorAdapter(vendorAdapter); factory.setPackagesToScan("com.sivalabs.demo"); Properties jpaProperties = new Properties(); jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); factory.setJpaProperties(jpaProperties); factory.afterPropertiesSet(); factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); return factory; } @Bean public HibernateExceptionTranslator hibernateExceptionTranslator() { return new HibernateExceptionTranslator(); } @Bean public DataSource dataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName")); dataSource.setUrl(env.getProperty("jdbc.url")); dataSource.setUsername(env.getProperty("jdbc.username")); dataSource.setPassword(env.getProperty("jdbc.password")); return dataSource; } @Bean public DataSourceInitializer dataSourceInitializer(DataSource dataSource) { DataSourceInitializer dataSourceInitializer = new DataSourceInitializer(); dataSourceInitializer.setDataSource(dataSource); ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(); databasePopulator.addScript(new ClassPathResource("data.sql")); dataSourceInitializer.setDatabasePopulator(databasePopulator); dataSourceInitializer.setEnabled(Boolean.parseBoolean(initDatabase)); return dataSourceInitializer; } }
在 AppConfig.java 所描述的配置類中,我們做了下麵的事情:
- 使用 @Configuration 註解使之成為 Spring 配置類。
- 使用 @EnableTransactionManagement 註解允許基於註解的事務管理。
- 配置 @EnableJpaRepositories 指示在哪裡尋找 Spring Data JPA 庫。
- Configured PropertyPlaceHolder bean u使用 @PropertySource 註解和 PropertySourcesPlaceholderConfigurer 定義來配置 PropertyPlaceHolder Bean。配置屬性來自 application.properties 文件。
- 為 DataSource、JPA EntityManagerFactory 和 JpaTransactionManager 定義 Bean。
- 配置 DataSourceInitializer Bean,使之在應用啟動時執行 data.sql 腳本,初始化資料庫。
我們需要在 application.properties 中配置占位屬性值:

創建簡單的 SQL 腳本,data.sql,將示例數據填入 USER 表中:

創建 log4j.properties 文件,在其中寫一些基礎配置:

第3步:配置Spring MVC Web層Beans
我們必須配置Thymeleaf ViewResolver,靜態ResourceHandlers,適用於國際化的MessageSource,等等。
@Configuration @ComponentScan(basePackages = { "com.sivalabs.demo"}) @EnableWebMvc public 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 Bean來配置Thymeleaf ViewResolver。
- 註冊ResourceHandlers Bean表明URI/resources/**靜態資源請求將由本地/resources/目錄提供服務。
- 配置MessageSource Bean通過ResourceBundle載入classpath下的messages-{country-code}.properties國際化信息。
目前我們沒有要配置的信息,所以在src/main/resources文件夾下創建一個空的messages.properties文件。
第4步:註冊Spring MVC FrontController Servlet DispatcherServlet
在Servlet 3.x規範之前我們必須在web.xml註冊Servlets/Filters。自從Servlet 3.x規範出台我們能夠使用ServletContainerInitializer以編程方式註冊Servlets/Filters。
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() }; } }
在SpringWebAppInitializer.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。
@Entity public class User { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Integer id; private String name; //setters and getters } public interface UserRepository extends JpaRepository<User, Integer> { }
第六步:創建Spring MVC控制器
創建SpringMVC控制器來處理”/”URL請求並返回用戶列表。
@Controller public class HomeController { @Autowired UserRepository userRepo; @RequestMapping("/") public String home(Model model) { model.addAttribute("users", userRepo.findAll()); return "index"; } }
第七步:創建Thymeleaf視圖:/WEB-INF/views/index.html來展示用戶列表
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"/> <title>Home</title> </head> <body> <table> <thead> <tr> <th>Id</th> <th>Name</th> </tr> </thead> <tbody> <tr th:each="user : ${users}"> <td th:text="${user.id}">Id</td> <td th:text="${user.name}">Name</td> </tr> </tbody> </table> </body> </html>
我們準備好運行程式啦。但在此之前,我們需要下載和配置諸如Tomcat或者Jetty或者Wilddfly等容器。
你可以下載Tomcat 8併在你喜歡使用的IDE中配置並運行。然後打開瀏覽器訪問http://localhost:8080/springmvcjpa-demo。你可以看到user的詳細列表。
耶…我們做到了。
但是等一下~這不是花了非常多的工作量才能做一個從資料庫中讀取並顯示用戶列表信息嗎?
我們公正公平來看問題。所有的這種配置並不只是一個用戶案例。這個配置也是應用程式其它部分的基礎。
回過頭來,如果你只是想快速獲得和運行一個應用來說這是在是太麻煩太複雜了。
另一個問題是,如果你想開發另一個有類似技術棧的 SpringMVC 應用嗎?
好的,你可能為了拷貝粘貼這些配置而感到苦惱。是嗎?提出一個記憶深刻的問題:如果你要做類似的事情重覆一遍又一遍,那麼你是不是想尋找一個能自動處理的方式解決問題。
各種分散的配置寫了一遍又一遍,你會想到這裡會有一些其他的麻煩問題嗎?
好的,在這讓我把這些我能想到的問題列出。
- 你需要註意所有的類庫的相容性與 Spring 版本搭配和配置。
- 在配置裡面有 95% 的時間我們都是在配置 DataSource,EntityManagerFactory,TransactionManger 之類的實體。但如果 Spring 能夠自動的為我們完成這些配置豈不是更好啊。
- 類似的配置 SpringMVC 實體類比如 ViewResolver、MessageSource 等又需要花更多的工作時間了。
想一想,要怎樣才能讓 Spring 能夠自動化的完成配置實體?怎麼樣你才可以快速簡單的使用基於可定製的屬性完成自動的配置呢?
比如,將 DispacherServlet 的 url-pattern 映射 “/” 映射到 “/app/”。將 “/WEB-INF/views” 目錄 替換為在 “/WEB-INF/templates/” 目錄加入 Thymeleaf 視圖。
所以基本上,你希望 Spring 自動執行一些操作,但是又能夠提供更簡單的方式靈活的提供重寫預設配置?
好的,現在你正在走進 Spring Boot 的世界在裡面你所期待已久的那些東西都已經有了!!!
快速上手品味 Spring Boot
歡迎來到 Spring Boot 世界!Spring Boot 並不是需要你完全地關註和掌握很多東西。它可以預設的完成自動化的配置但是你又可以按自己的需要去重新配置任意配置。
相比我更喜歡用一個例子來說明而不是更多的解析。
所以讓我們現在開始用 Spring Boot 來快速構建一個應用。
Step 1:創建一個 Spring Boot 的 Maven 項目
創建一個 Maven 項目和(在 pom.xml 裡面)配置項目 jar 包依賴如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.sivalabs</groupId> <artifactId>hello-springboot</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>hello-springboot</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.2.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies> </project>
哇原來 pom.xml 的配置這麼少感覺簡單多了!
Step 2:在 application.properties 中配置數據源或JPA 屬性配置如下:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=admin spring.datasource.initialize=true spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true
你可以拷貝一些類似 data.sql 的文件到 src/main/resources 目錄中。
Step 3:創建一些 JAP 實體類和實體類所需要的 Spring Data JAP Repository 介面
在 springmvc-jpa-demo 應用項目中創建 User.java,UserRepository.java 和 HomeController.java 之類所需的東西。
Step 4:用 Thymeleaf 模板語言創建一個顯示用戶列表的視圖
在 springmvc-jap-demo 應用拷貝 /WEB-INF/views/index.html 到我們的新項目的 src/main/resources/templates 目錄中。
Step 5:創建一個 SpringBoot 啟動入口實體的類
創建一個有 main 函數的 Java 類 Application.java 如下:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
現在用 Java Application 的方式開始啟動運行 Application.java 之後打開瀏覽器訪問 http://localhost:8080/。
你就可以在頁面的表格上看到用戶列表的顯示。這感覺實在太酷了!!!
OK 好的,我想你會大聲說”這裡邊到底發生了做了些什麼???”。
讓我說明下剛纔發生了什麼
1. 輕鬆地依賴管理
- 首要察覺一點是我們用的是一些名為spring-boot-starter-*.的依賴項。要記得我說過 “95%的時間里用的配置相同”。因此當預設添加springboot-starter-web依賴項時,它將在開發Spring-webmvc,jackson-json,validation-api和tomcat等Spring MVC應用程式中提取所有常用庫。
- 我們添加了spring-boot-starter-data-jpa依賴項。這會拉取所有spring-data-jpa依賴項並添加Hibernate庫,因為大多數應用程式都把Hibernate作為JPA實施。
2. 自動配置
- spring-boot-starter-web不僅添加了所有這些庫,還配置了常見的bean,例如DispatcherServlet,ResourceHandlers,MessageSource等bean,具有合理的預設值。
- 我們還添加了spring-boot-starter-Thymeleaf,它不僅添加了Thymeleaf庫依賴項,還自動配置了ThymeleafViewResolver bean。
- 我們並沒有定義任何的DataSource,EntityManagerFactory,TransactionManageretc bean,但是它們會自動地創建。如何?如果我們的類路徑中有任何像H2或是HSQL的記憶體資料庫驅動程式,那麼SpringBoot將自動創建一個記憶體中的DataSource,然後自動註冊EntityManagerFactory,以及擁有合理的預設值TransactionManager bean。但我們在用MySQL,所以我們需要提供明確的MySQL連接細節。我們在application.propertiesfile中配置了這些MySQL連接細節,並且SpringBoot使用了這些屬性來創建一個DataSource。
3.嵌入式Servlet容器支持
最重要也是最驚奇的是我們創建了一個簡單的Java類,註釋了一些神奇的註解@SpringApplication,它有一個main方法,通過運行main,我們可以運行應用程式併在http:// localhost:8080 /上訪問它。
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應用程式快速瀏覽了SpringBoot。
在下一篇文章中,我們將深入探討SpringBoot並瞭解它是如何工作的。
來源代碼灣:http://codebay.cn/post/10067.html