spring是一個用於建立web和企業應用的一個很流行的框架。和別的只關注於一點的框架不一樣,Spring框架經過投資並組合項目提供了大量的功能來知足現代的業務需求。html
Spring提供了許多靈活的方式來配置bean,如XML,註解和JavaConfig。隨着功能數量的增長,複雜度也提高了,致使Spring應用的配置變得單調乏味且容易出錯。前端
Spring團隊開發出SpringBoot來解決配置複雜的問題。java
可是在深刻了解SpringBoot以前,咱們會快速瞭解一下Spring框架,看一看SpringBoot究竟試圖解決什麼問題。mysql
在這篇文章中將會涉及:web
若是你是一個JAVA開發人員,那麼你極可能據說過Spring框架,而且可能已經在項目中使用過它。Spring框架最初建立是爲了依賴注入容器,可是它的功能遠遠不止這個。面試
Spring之因此流行是如下幾個緣由:spring
還有不少Spring的兄弟框架輔助Spring來解決當代業務需求:sql
還有不少其餘解決各類各樣當代應用開發需求的有趣的項目。更多詳情能夠參考Spring官網數據庫
在早期,Spring框架提供了基於XML的方式來配置bean。後來Spring引入了基於XML的DSL,註解和基於JavaConfig的方法來配置bean。apache
讓咱們快速瞭解一下這些不一樣的配置風格:
<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; } }
Wow...Spring爲作同一件事情提供了那麼多方法,咱們甚至能夠在同一個應用中將三者混合使用。
高靈活性既有好的一面也有壞的一面。初次使用Spring的人每每會困惑,不知道該使用哪一種方法。目前來講,Spring團隊推薦使用基於JavaConfig的方法來提供更高的靈活性。
可是沒有一勞永逸的解決方法。每一個人都應當基於應用的需求來選擇方法。
好了,如今你看到了各類Spring配置的風格。
讓咱們看一下經典的SpringMVC + JPA/Hibernate的Web應用的配置。
在瞭解什麼是SpringBoot以及它提供了什麼功能以前,讓咱們看一個經典的Spring Web項目的配置,它的痛點是什麼。而後咱們會討論SpringBoot是如何解決這些問題的。
咱們首先要作的就是在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>
咱們已經配置好了所需的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; } }
在AppCofig.java
配置類中咱們作了如下幾件事情:
@Configuration
將其標記爲Spring配置類@EnableTransactionManagement
支持基於註解的事務管理@EnableJpaRepositories
說明在尋找Spring Data JPA庫@PropertySource
和PropertySourcesPlaceholderConfigure
配置PropertyPlaceHolder bean,它將會從application.properties
文件中讀取配置。DataSource
,JPA EntityManagerFactory
和JpaTransactionManager
。DataSourceInitializer
,從而在應用啓動時執行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
咱們還須要配置Thymeleaf的ViewResolver
,i18n的ResourceHandler
和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
註解將其標記爲配置類@EnbaleWebMvc
支持基於註解的Spring MVC配置TemplateResolver, SpringTemplateEngine, ThymeleafViewResolver
來配置ThymeleafViewResolver。URI/resources/**
的靜態資源的訪問將會定向至/resources/direcotry
。MessageSource
來從messages-{country-code}.properties
加載i18n信息。目前爲止咱們沒有任何消息須要配置,因此只在src/main/resources
文件夾中建立一個空的message.properties
文件。
在Servlet3.x以前咱們須要在web.xml
文件中註冊Servlets/Filters。從Servlet3.x開始咱們能夠直接使用代碼在ServletContainerInitializer
中註冊。
SpringMVC提供了一個很方便的類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
配置爲RootConfigClassess
,使其成爲應用上下文幷包含被全部其它上下文所共享的bean定義。WebMvcConfig.class
配置爲ServletConfigClasses
,它包含WebMvc bean的上下文。/
做爲ServletMapping
,意味着全部的請求都將被DispatcherServlet
處理OpenEntityManagerInViewFilter
做爲Servlet過濾器,從而使咱們能夠在渲染視圖的時候惰性加載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> { }
@Controller public class HomeController { @Autowired UserRepository userRepo; @RequestMapping("/") public String home(Model model) { model.addAttribute("users", userRepo.findAll()); return "index"; } }
/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>
咱們如今能夠啓動應用了。可是在那以前咱們須要在IDE中下載並配置服務器如Tomcat,Jetty或是Wildfly。
你能夠下載Tomcat8並在你最喜歡的IDE中配置它,而後運行應用並在瀏覽器中訪問http://localhost:8080/springmvcjpa-demo
,你應當會看見一個用戶列表。
耶...咱們作到了。
可是等等...只是爲了展現一個從數據庫中獲取的用戶列表,工做量未免太大了吧?
讓咱們客觀的來看。全部的配置不僅是爲了這個應用場景,它還適用於全部其餘的應用。
並且,再次強調,若是你想快速上手並運行,這裏的工做量太大了。
還有一個問題是,假設你想開發另外一個有類似技術棧的SpringMVC應用?那麼你就須要複製粘貼這些配置而且修改。可是記住,當你須要重複的作一件事情的時候,你就應當尋找一個將其自動化的方法。
除了須要一遍遍的寫相同的配置,你還發現如下問題了嗎?
DataSource, EntitymanagerFactory,TransactionManager
,spring不能自動幫我完成這些事情嗎?ViewResolver, MessageSource
。若是Spring可以自動幫我完成這些事情,那真的是美滋滋!
想一想一下,若是Spring可以自動配置beans?若是你可以使用簡單的自定義屬性來自定義自動配置的過程?
好比,你但願要將DispatcherServlet映射的URL模式從/
改變爲/app/
。你還但願不要將Thymeleaf視圖放在/WEB-INF/views
文件夾中而是/WEB-INF/templates/
文件夾中。
因此基本上你但願Spring自動完成這些事情可是容許你用一種簡單的方式重寫默認的配置。
那麼,你講進入SpringBoot的世界,在那裏你將夢想成真!
歡迎來到Spring Boot!Spring Boot正是你所尋找的東西、它會自動幫你完成配置並容許你重寫默認的配置。
我將用一個例子來講明。讓咱們實現和以前相同的Web應用,不過此次咱們使用Spring Boot。
<?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>
Wow!咱們的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
這裏和Spring中建立的User.java, UserRepository.java和HomeController.java
相同。
將springmvc-jpa-demo項目中的/WEB-INF/views/index.html
複製到新項目的src/-main/resources/templates
文件夾中。
建立一個帶有main方法的Application.java
類
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
如今運行Application.java
而且在瀏覽器上訪問http://localhost:8080/
你應該可以看到一個用戶列表的表格。太酷了!
okok,我聽到你在大喊「發生了什麼?」
讓我來解釋發生了什麼。
1.簡單的依賴管理
spring-boot-starter-*
的依賴。記住我說過「95%的狀況下咱們會使用相同個配置」。因此當你添加了sping-boot-starter-web
依賴時,它會自動拉取開發SpringMVC所經常使用的庫如Spring-webmvc
,jackson-json
,validation-api
和tomcat
spring-boot-starter-data-jpa
依賴。它會拉取全部spring-data-jpa
的依賴,還會添加Hibernate
庫由於大多數應用都是用Hibernate做爲JPA的實現。2.自動配置
spring-boot-starter-web
不只僅添加了和其相關的依賴,還默認配置了常見的bean好比DispatcherServlet, ResourceHandlers, MessageSource
。spring-boot-starter-Thymeleaf
依賴,它不只添加Thymeleaf庫還會自動配置ThyemeleafViewResovler
。DataSource, EntityManagerFactory, TransactionManager
等bean,可是它們被自動建立了。怎麼作到的?若是咱們有內存級數據庫如H2
或是HSQL
,那麼SpringBoot就會自動建立一個內存的EntityManager
而且註冊EntityManagerFactory
,將TransactionsManager
beans按照默認自動配置。可是咱們在使用MySQL,所以咱們須要明確提供MySQL鏈接的詳情。咱們已經在application.properties
中配置了鏈接詳細信息,Spring Boot會利用這些配置建立一個DataSource
。3.嵌入式Servlet容器的支持
最重要的是,咱們使用@SpringApplication
註解建立了一個簡單的包含main函數的Java類。咱們能夠運行main方法啓動應用而且經過http://localhost:8080/
訪問。
servlet容器是哪裏來的?spring-boot-starter-web
自動拉取了spring-boot-starter-tomcat
。當咱們運行main方法時,它將tomcat做爲內嵌容器啓動,咱們無需將應用部署到外部安裝的tomcat服務器上。
順便說一下,你注意到咱們的打包方式是jar而不是war嗎。太棒了!
好吧,那要是我想要用Jetty服務器而不是tomcat怎麼辦呢?很簡單,你只須要在spring-boot-starter-web
中exclude掉spring-boot-starter-tomcat
而後includespring-boot-starter-jetty
。
這篇文章咱們快速瞭解了一下各類Sring配置的風格,而且瞭解了配置Spring應用的複雜性。同時咱們也快速瞭解瞭如何經過spring-boot建立一個簡單的web應用。
想要了解更多開發技術,面試教程以及互聯網公司內推,歡迎關注個人微信公衆號!將會不按期的發放福利哦~