Spring Boot入门(四)自动配置

Spring Boot自动配置是一个运行时的过程,考虑众多因素,决定Spring配置应该使用哪个,而不该用哪个。

Spring Boot自动配置需要考虑:
Spring的JdbcTemplate是否在Classpath中?若有,并且有DataSource的Bean,则自动配置一个JdbcTemplate的Bean。
Thymeleaf是否在Classpath中?若有,则配置Thymeleaf的模板解析器、视图解析器以及模板引擎。
Spring Security是否在Classpath中?若有,则进行一个基本的Web安全设置。
每当应用程序启动时,Spring Boot的自动配置都会进行重新配置。

专注应用程序功能

  1. 定义领域模型
    简单模型,属性+get/set
import javax.persistence.*;
@Entity
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String reader;
    private String isbn;
    private String title;
    private String author;
    private  String description;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getReader() {
        return reader;
    }

    public void setReader(String reader) {
        this.reader = reader;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

  1. 定义仓库接口
    将实体类对象持久化到数据库的仓库当中
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ReadingListRepository extends JpaRepository<Book, Long> {
List<Book> findByReader(String reader);//用户自定义方法
}

因为使用了Spring Data JPA,所以只需定义一个接口,扩展Spring Data JPA的JpaRepository接口。
通过接口扩展,ReadingListRepository直接继承了多个执行常用持久化操作的方法。当然,继承的接口,Spring Data在应用程序启动后,该接口在运行时会自动实现。

  1. 创建web界面
    使用Spring MVC处理HTTP请求:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;

@Controller
@RequestMapping("/")
public class ReadingListController {
    private ReadingListRepository readingListRepository;

    @Autowired
    public ReadingListController(ReadingListRepository readingListRepository) {
        this.readingListRepository = readingListRepository;
    }

    @RequestMapping(value = "/{reader}", method = RequestMethod.GET)
    public String readersBooks(@PathVariable("reader") String reader, Model model) {
        //根据{reader}从仓库取出Book列表
        List<Book> readingList = readingListRepository.findByReader(reader);
        if (readingList != null) {
            //用books键将列表存放在model中(model为一个Map)
            model.addAttribute("books", readingList);
        }
        //返回"readingList"作为视图名
        return "readingList";
    }

			
	//将正文数据绑定到一个Book对象上,将该对象的reader属性设置为读者姓名
	//通过仓库的save()保存修改后的Book对象,最后进行重定向
	@RequestMapping(value="/{reader}", method=RequestMethod.POST)
	@ResponseBody
	public String addToReadingList(@PathVariable("reader") String reader, @ResponseBody Book book) {
						
				book.setReader(reader);
				readingListRepository.save(book);
				return "redirect:/{reader}";
	}
}

@Controller:扫描并自动将其处理器(此处为ReadingListController)注册为Spring应用程序上下文中的一个Bean。
@RequestMapping:将处理器的方法映射到URL路径上

呈现阅读列表的Thymeleaf模板:
在src/main/resources/templates里创建一个名为readingList.html的文件

<html>
	<head>
		<title>Reading List</title>
		<link rel="stylesheet" th:href="@{/style.css}"></link>
	</head>
	<body>
		<h2>Your Reading List</h2>
		<div th:unless="${#lists.isEmpty(books)}">
			<dl th:each="book : ${books}">
				<dt class="bookHeadline">
					<span th:text="${book.title}">Title</span> by
					<span th:text="${book.author}">Author</span>
					(ISBN: <span th:text="${book.isbn}">ISBN</span>)
				</dt>
				<dd class="bookDescription">
					<span th:if="${book.description}"
					th:text="${book.description}">Description</span>
					<span th:if="${book.description eq null}">
					No description available</span>
				</dd>
			</dl>
		</div>
		<div th:if="${#lists.isEmpty(books)}">
			<p>You have no books in your book list</p>
		</div>
		<hr/>
		<h3>Add a book</h3>
		<form method="POST">
			<label for="title">Title:</label>
			<input type="text" name="title" size="50"></input><br/>
			<label for="author">Author:</label>
			<input type="text" name="author" size="50"></input><br/>
			<label for="isbn">ISBN:</label>
			<input type="text" name="isbn" size="15"></input><br/>
			<label for="description">Description:</label><br/>
			<textarea name="description" cols="80" rows="5">
			</textarea><br/>
			<input type="submit"></input>
		</form>
		</body>
</html>

该页面模板有两部分组成:上方是读者的阅读列表中的图书清单,下方是一个表单,读者可添加新书。

另外,引入的style.css文件,位于src/main.resources/static中:

body {
background-color: #cccccc;
font-family: arial,helvetica,sans-serif;
}
.bookHeadline {
font-size: 12pt;
font-weight: bold;
}
.bookDescription {
font-size: 10pt;
}
label {
font-weight: bold;
}

省略数据库配置(在配置文件中配相应的DataSource)
综上就是一个完整的web应用程序了。

在向应用程序加入Spring Boot时,有个名为spring-boot-autoconfigure的jar文件,包含了很多的配置类。每个配置类都在应用程序的Classpath里。这些配置类有用于Spring Data JPA的配置,有用于Spring MVC的配置,和其他配置。用户可以选择是否要使用他们。
这些配置文件采用条件配置(Spring4.0新特性),允许配置存在于应用程序中,但在满足特定条件前忽略该配置。
在Spring中要编写自己的条件,只需实现Condition接口,并覆盖它的matches()方法。
如,下面的条件类只有在Classpath里存在JdbcTemplate时才会生效:

public class jdbcTemplateConditon implements Conditon{
	@Override
	public boolean matches(ConditionContext context,AnnotatedTypeMetadata metadata){
			try{
					context.getClassLoader().loadClass("org.springframework.jdbc.core.JdbcTemplate");
					return true;
			}catch(Exception e){
					return false;
			}
	}
}

当用Java来声明Bean时,可以使用这个自定义条件类:

@Conditional(JdbcTemplateConditon.class)
public MyService myService{
	...
}

在该例子中,只有当JdbcTemplateCondition类条件成立时,才会创建MyService这个Bean,即MyService Bean创建的条件是Classpath里有JdbcTemplate。否则,这个Bean声明将被忽略。
在Spring Boot的自动配置类中,DataSourceAutoConfiguration添加了@Configuration注解,从其他配置类里导入了一些额外配置,还自定义了一下Bean。另外,添加了@ConditionalOnClass注解,要求Classpath里必须要有DataSource和EmbeddedDatabaseType。若他们不存在,DataSourceAutoConfiguration提供的配置会都被忽略。
DataSourceAutoConfiguration内嵌了JdbcTemplateConfiguration类,自动配置了一个JdbcTemplate Bean。
JdbcTemplateConfiguration使用了@Conditional注解,判断DataSourceAvailableCondition条件是否成立–是否有一个DataSource Bean或自动配置创建一个。假设有DataSource Bean,使用了@Bean注解的jdbcTemplate()方法会配置一个JdbcTemolate Bean。另外使用了@ConditionalOnMissingBean注解,因此,只有在不存在JdbcOperations(JdbcTemplate实现接口)类型的Bean时,会创建JdbcTemplate Bean。
以上,说明了Spring Boot如何利用条件化配置实现自动配置。

自动装配会做出一下决策:(以上述例子为例)
因为Classpath里有H2,所以会创建一个嵌入式H2数据库Bean,他的类型为javax.sql.DataSource,JPA实现(Hibernate)需要它来访问数据库。
因为Classpath里有Hibernate(Spring Data JPA传递引入的)的实体管理器,所以自动配置会配置与Hibernate相关的Bean,包括Spring的LocalContainerEntityManagerFactoryBean和JpaVendorAdapter。
因为Classpath里有Spring Data JPA,所以他会自动配置为根据仓库的接口创建仓库实现。
因为Classpath里有Spring Data JPA,所以它会自动配置为Spring MVC的视图,包括一个Thymeleaf的模板解析器、模板引擎及视图解析器。视图解析器会解析相对于Classpath根目录/templates目录里的模板。
因为Classpath里有Spring MVC,所以会配置Spring的DispatcherServlet并启用Spring MVC。
因为这时一个Spring MVC Web应用,所以会注册一个资源处理器,把相对于Classpath根目录/static目录下的静态内容提供出来。
因为Classpath里有Tomcat(通过web起步依赖传递),所以会启动一个嵌入式Tomcat容器。


参考文献:Spring Boot实战 ,丁雪丰 (译者)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值