原文:https://dzone.com/articles/why-springboot
做者:Siva Prasad Reddy Katamreddy
譯者:Oopsguyhtml
本文將介紹各類 Spring 的配置方式,幫助你瞭解配置 Spring 應用的複雜性。前端
Spring 是一個很是受歡迎的 Java 框架,它用於構建 Web 和企業應用。不像許多其餘框架只關注一個領域,Spring 框架提供了各類功能,經過項目組合來知足當代業務需求。java
Spring 框架提供了多種靈活的方式來配置 Bean。例如 XML、註解和 Java 配置。隨着功能數量的增長,複雜性也隨之增長,配置 Spring 應用將變得乏味且容易出錯。mysql
針對上述問題,Spring 團隊建立了 Spring Boot 以解決配置複雜的問題。web
但在開始將 Spring Boot 以前,咱們將快速瀏覽一下 Spring 框架,看看 Spring Boot 正在決解什麼樣的問題。spring
在本文中,咱們將介紹:sql
若是你是一名 Java 開發人員,那你極可能據說過 Spring 框架,甚至可能已經在本身的項目中使用了它。Spring 框架主要是做爲依賴注入容器,但它的做用遠不止這些。數據庫
連同 Spring 一塊兒的,還有許多其餘的 Spring 姊妹項目,能夠幫助構建知足當代業務需求的應用:apache
還有許多其餘有趣的項目涉及各類其餘當代應用開發需求。有關更多信息,請查看 http://spring.io/projects。編程
剛開始,Spring 框架只提供了基於 XML 的方式來配置 bean。後來,Spring 引入了基於 XML 的 DSL、註解和基於 Java 配置的方式來配置 bean。
讓咱們快速瞭解一下這些配置風格的大概模樣。
<bean id="userService" class="com.sivalabs.myapp.service.UserService"> <property name="userDao" ref="userDao"/> </bean> <bean id="userDao" class="com.sivalabs.myapp.dao.JdbcUserDao"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="secret"/> </bean>
@Service public class UserService { private UserDao userDao; @Autowired public UserService(UserDao dao){ this.userDao = dao; } ... ... }
@Repository public class JdbcUserDao { private DataSource dataSource; @Autowired public JdbcUserDao(DataSource dataSource){ this.dataSource = dataSource; } ... ... }
@Configuration public 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 提供了多種方式來作一樣的事,咱們甚至能夠混合使用,在同一個應用中使用基於 Java 配置和註解配置的方式。
這很是靈活,但它有好有壞。剛開始接觸 Spring 的新人可能會困惑應該使用哪種方式。到目前爲止,Spring 團隊建議使用基於 Java 配置的方式,由於它更具靈活性。
沒有哪種方案是萬能,咱們應該根據本身的需求來選擇合適的方式。
到此,你已經瞭解了多種 Spring Bean 配置方式的基本形式。
讓咱們快速地瞭解一下典型的 Spring MVC+JPA/Hibernate Web 應用的配置。
在瞭解 Spring Boot 是什麼以及它提供了什麼樣的功能以前,咱們先來看一下典型的 Spring Web 應用配置是怎樣的,哪些是痛點,而後咱們將討論 Spring Boot 是如何解決這些問題的。
首先須要作的是配置 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。
@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 資源庫(repository)@PropertySource
註解和 PropertySourcesPlaceholderConfigurer
Bean 定義配置 PropertyPlaceHolder
bean 從 application.properties
文件加載配置data.sql
腳原本初始化數據庫咱們須要在 application.properties
中完善配置,以下所示:
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=admin init-db=true hibernate.dialect=org.hibernate.dialect.MySQLDialect hibernate.show_sql=true hibernate.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, stdout log4j.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
咱們必須配置 Thymleaf 的 ViewResolver、處理靜態資源的 ResourceHandler 和處理 I18n 的 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 配置/resource/**
的靜態資源請求定位到 /resource/
目錄下如今咱們沒有配置任何 I18n 內容,所以須要在 src/main/resources
文件夾下建立一個空的 messages.properties
文件。
在 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() }; } }
在 SpringWebAppInitializer.java 配置類中,咱們完成了如下操做:
AppConfig.class
配置爲 RootConfigurationClass,它將成爲包含全部子上下文(DispatcherServlet)共享的 Bean 定義的父 ApplicationContextWebMvcConfig.class
配置爲 ServletConfigClass,它是包含了 WebMvc Bean 定義的子 ApplicationContext/
配置爲 ServletMapping,這意味全部的請求將由 DispatcherServlet 處理爲 User 實體建立一個 JPA 實體 User.java 和一個 Spring Data JPA 資源庫。
@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 控制器來處理 URL 爲 /
,並渲染一個用戶列表。
@Controller public class HomeController { @Autowired UserRepository userRepo; @RequestMapping("/") public String home(Model model) { model.addAttribute("users", userRepo.findAll()); return "index"; } }
<!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>
全部都配置好了,能夠啓動應用了。但在此以前,咱們須要在 IDE 中下載並配置像 Tomcat、Jetty 或者 Wildfly 等服務器。
你能夠下載 Tomcat 8 並配置在你喜歡的 IDE 中,以後運行應用並將瀏覽器指向 http://localhost:8080/springmvc-jpa-demo
。你應該看到一個以表格形式展現的用戶詳細信息列表。
真激動,咱們作到了!
可是等等,作了那麼多的工做僅僅是爲了從數據庫中獲取用戶信息而後展現一個列表?
讓咱們坦誠公平地來看待,全部的這些配置不只僅是爲了此次示例,這些配置也是其餘應用的基礎。
但我仍是想說,若是你想早點起牀跑步,那對不起,你還有太多的工做要作。
另外一個問題是,假設你想要開發另外一個 Spring MVC 應用,你會使用相似的技術棧?
好,你要作的就是複製粘貼配置並調整它。對麼?請記住一件事:若是你一次又一次地作一樣的事情,你應該尋找一種自動化的方式來完成它。
除了一遍又一遍地編寫相同的配置,你還能發現其餘問題麼?
這樣吧,讓我列出我從中發現的問題。
若是 Spring 能夠自動幫我作這些事情,那真的是非!常!棒!
想象一下,若是 Spring 可以自動配置 bean 呢?若是你可使用簡單的自定義配置方式來定義自動配置又將會怎麼?
例如,你能夠將 DispatcherServlet 的 url-pattern
映射到 /app/
,而不是 /
。你能夠將 Theymeleaf 視圖放在 /WEB-INF/template/
文件夾下,而不是 /WEB-INF/views
中。
因此基本上你但願 Spring 能自動執行這些操做,Spring 它有沒有提供一個簡單靈活的方式來覆蓋掉默認配置呢?
很好,你即將踏進入 Spring Boot 的世界,你將夢想成真!
歡迎來到 Spring Boot 世界!Spring Boot 正是你一直在尋找的。它能夠自動爲你完成某些事情,但若是有必要,你能夠覆蓋掉這些默認配置。
與其誇誇而談,不如來點案例實戰。
建立一個 Maven 項目並配置以下依賴:
<?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 文件一會兒變小了許多!
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
文件加中。
與 springmvc-jpa-demo
應用同樣,建立 User.java、UserRepository.java 和 HomeController.java。
從 springmvc-jpa-demo
項目中複製以前建立的 /WEB-INF/views/index.html
到 src/main/resources/template
文件夾中。
建立一個含有 main
方法的 Java 類 Application.java,以下所示:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
如今把 Application.java
看成一個 Java 應用運行,並將你的瀏覽其指向 http://localhost:8080/
。
不出意外,你將看到一個以表格的形式展現的用戶列表,真的很酷!
我彷彿聽到你在喊:「這到底發生了什麼事?」。
讓我解釋剛剛所發生的事情。
簡單的依賴管理
首先要注意的是咱們使用了一些名爲 spring-boot-start-*
的依賴。記住我說過我花費 95% 的時間來配置一樣的配置。當你在開發 Spring MVC 應用時添加了 spring-boot-start-web
依賴,它已經包含了一些經常使用的類庫,好比 spring-webmvc、jackson-json、validation-api 和 tomcat 等。
咱們添加了 spring-boot-starter-data-jpa
依賴。它包含了全部的 spring-data-jpa
依賴,而且還添加了 Hibernate 庫,由於不少應用使用 Hibernate 做爲 JPA 實現。
自動配置
spring-boot-starter-web
不只添加了上面所說的這些庫,還配置了常常被註冊的 bean,好比 DispatcherServlet、ResourceHandler 和 MessageSource 等 bean,而且應用了合適的默認配置。
咱們還添加了 spring-boot-starter-Thymeleaf
,它不只添加了 Thymeleaf 的依賴,還自動配置了 ThymeleafViewResolver bean。
雖然咱們沒有定義任何 DataSource、EntityManagerFactory 和 TransactionManager 等 bean,但它們能夠被自動建立。怎麼樣?若是在 classpath 下沒有任何內存數據庫驅動,如 H2 或者 HSQL,那麼 Spring Boot 將自動建立一個內存數據庫的 DataSource,而後應用合適的默認配置自動註冊 EntityManagerFactory 和 TransactionManager 等 bean。可是咱們使用的是 MySQL,所以咱們須要明確提供 MySQL 的鏈接信息。咱們已經在 application.properties
文件中配置了 MySQL 鏈接信息,Spring Boot 將應用這些配置來建立 DataSource。
支持嵌入式 Servlet 容器
@SpringApplication
,它有一個 main
方法。經過運行 main
方法,咱們能夠啓動這個應用,並可經過 http://localhost:8080/
來訪問。咱們添加了 spring-boot-starter-web
,它會自動引入 spring-boot-starter-tomcat
。當咱們運行 main()
方法時,它將 tomcat 做爲一個嵌入式容器啓動,咱們不須要部署本身的應用到外部安裝好的 tomcat 上。
順便說一句,你看到咱們在 pom.xml 中配置的打包類型是 jar 而不是 war,真有趣!
很是好,但若是我想使用 jetty 服務器而不是 tomcat 呢?很簡單,只須要從 spring-boot-starter-web
中排除掉 sprig-boot-starter-tomcat
,幷包含 spring-boot-starter-jetty
依賴便可。
就是這樣。
但這看起來真的很神奇!
我能夠想象此時你在想什麼。你正在感嘆 Spring Boot 真的很酷,它爲你自動完成了不少事情。可是,你還沒了徹底明白它幕後是怎樣工做的,對不對?
我能夠理解,就像觀看魔術表演,過程很是有趣,但你不知道魔術師是如何作到的。軟件開發則不同,你不用擔憂,將來咱們還將看到各類新奇的東西,並在之後的文章中詳細地解釋它們幕後的工做原理。很遺憾的是,我不能在這篇文章中把全部的東西都教給你。
在本文中,咱們快速介紹了 Spring 的各類配置風格,並瞭解了配置 Spring 應用的複雜性。此外,咱們經過建立一個簡單的 Web 應用來快速瞭解 Spring Boot。
在下一篇文章中,咱們將深刻了解 Spring Boot,瞭解它的工做原理。