读者应具备:
-
Spring SpringMVC服务器端开发基础
-
Maven基础
本篇主要介绍Spring Boot在企业开发中常见场景的使用、以及Spring Boot的基本原理结构。
以下为本篇设计的技术应用场景:
构建Spring Java程序
构建JUnit测试用例
构建Spring JDBC Template应用程序操作数据库
构建Servlet、JSP程序
构建SSH应用(Spring、Spring MVC、Hibernate)
构建SSM应用(Spring、Spring MVC、MyBatis)
构建SSJPA应用(Spring、Spring MVC、Spring Data JPA)
构建FreeMarker应用程序
构建基于Redis缓存应用程序
构建基于ActiveMQ消息队列应用程序
构建基于Spring Security访问控制应用程序
构建基于Dubbox分布式架构应用程序
介绍完应用场景后,再来了解下Spring Boot的基本原理结构。
引言
如果读者写过稍微复杂一些的Spring程序,那么你一定曾经编写过那铺天盖地的各类配置文件。例如:
-
applicationContext-dao.xml(针对DAO的配置——数据源、持久层框架与spring整合bean)
-
applicationContext-tx.xml(针对事务的配置)
-
applicationContext-amq.xml(针对ActiveMQ的配置)
-
applicationContext-webservice.xml(针对WebService发布的配置)
-
applicationContext-redis.xml(针对操作Redis的配置)
-
applicationContext-security.xml(针对Spring Security的配置)
-
applicationContext-freemarker.xml(针对FreeMarker模板引擎的相关配置)
-
springmvc.xml(Spring MVC的配置)
-
...
除此之外,我们还要维护大量的依赖。最坑的是,不同的版本框架之间可能会存在不兼容的问题。或许,我们早已习惯了这些配置,但我们今天要学习是以一种崭新的开发方式来开发Spring应用程序。它将掀起一场推翻Spring过去统治的轻量级JavaEE企业应用世界的技术革命。
而这一场技术革命原动力就是我今天要呈现给大家的——Spring Boot。
本篇目标
-
介绍如何使用Spring Boot开发基于各类技术框架的应用程序
-
了解Spring Boot自动配置原理、结构
目录
Spring Boot常见企业开发场景应用、自动配置原理结构分析引言本篇目标目录环境准备Spring Java配置Spring Boot基本编程模型导入依赖导入配置编码常见企业开发场景应用构建Spring Java应用程序构建Junit测试用例构建Spring JDBC Template应用程序操作数据库构建Servlet、JSP程序构建SSH应用程序(Spring、Spring MVC、Hibernate)构建SSM应用(Spring、Spring MVC、MyBatis)构建SSJPA应用(Spring、Spring MVC、Spring Data JPA)构建FreeMarker应用程序构建基于Redis缓存应用程序构建基于ActiveMQ消息队列应用程序构建基于Dubbox分布式架构应用程序启动ZooKeeper编写服务提供者编写服务消费者Spring Boot自动配置原理结构分析结尾
环境准备
编译环境:1.7+
构建工具:Maven
数据库:Mysql 5.x
开发环境:推荐使用IDEA或者STS
-
在mysql中创建一个名字为springboot的数据库
-
使用如下脚本创建表结构
create table `t_user` (`id` int (11),`username` varchar (765),`password` varchar (300));insert into `t_user` (`id`, `username`, `password`) values('2','zhangsan','000');insert into `t_user` (`id`, `username`, `password`) values('3','lisi','000');insert into `t_user` (`id`, `username`, `password`) values('4','wangwu','000');insert into `t_user` (`id`, `username`, `password`) values('5','zhaoliu','000');insert into `t_user` (`id`, `username`, `password`) values('6','张北','110');insert into `t_user` (`id`, `username`, `password`) values('7','江南','000000');insert into `t_user` (`id`, `username`, `password`) values('8','江北','123123');
Spring Java配置
SPring Java配置是Spring 3.0所推荐的配置方式。因为,XML的可读性确实不怎么样,我们一边要编写Java代码,一边要编写XML配置文件。所以,从Spring 3.0开始,推荐使用Java配置+注解方式来编写Spring程序。
接下来,我给大家演示一个比较简单的案例——从数据库中更新一条用户数据、查询一条用户数据。为了简单起见,使用Spring JDBC Template来操作数据库。
-
首先创建一个Maven工程,往pom.xml中导入Spring、MySql相关依赖
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.2.4.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>4.2.4.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>4.2.4.RELEASE</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>1.7</source><target>1.7</target></configuration></plugin></plugins></build>
-
创建Java实体类,
/*** 用户表*/public class User {private Integer id;private String username;// 用户名private String password;// 密码public User() {}public User(int id, String username, String password) {this.id = id;this.username = username;this.password = password;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "User [id=" + id + ", username=" + username + ", password=" + password + "]";}}
-
写到这,如果大家比较熟悉Spring开发的话,肯定是要开始编写spring配置文件了,并且在配置文件中,创建需要用于操作数据库的Bean。但这儿,我们要使用Java配置来创建Bean。以前在XML文件中创建Bean的配置,现在都写在Java代码中了。以下为Java配置:
/*** @Configuration注解表示这是一个配置类* @author FengZhou**/@Configurationpublic class Conf {/*** 创建一个C3P0数据源* @return* @throws PropertyVetoException*/@Beanpublic ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");comboPooledDataSource.setJdbcUrl("jdbc:mysql:///springboot");comboPooledDataSource.setUser("root");comboPooledDataSource.setPassword("000000");return comboPooledDataSource;}/*** 创建一个用于操作数据库的JdbcTemplate* @return* @throws PropertyVetoException*/@Beanpublic JdbcTemplate jdbcTempalte() throws PropertyVetoException {JdbcTemplate jdbcTemplate = new JdbcTemplate();jdbcTemplate.setDataSource(c3p0DataSource());return jdbcTemplate;}}
@Configuration
这个注解标识,当前修饰的类就是一个配置类。你可以把它认为被@Configuration修饰的类就是一个配置文件。
@Bean
这个注解表示Spring会自动执行被它修饰的方法,并且将此方法的返回对象放入到Spring IOC容器中。
上述代码创建了两个Bean,分别是C3P0的数据源和用于操作数据的JdbcTemplate。
-
编写测试用例
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=Conf.class)// 加载Java配置public class JdbcTemplateTest01 {@Autowiredprivate JdbcTemplate jdbcTemplate;@Testpublic void test01() {// 执行一条更新语句jdbcTemplate.execute("update t_user t set t.username='zhaosi' where t.id = 1");}@Testpublic void test02() {// 查询一条数据jdbcTemplate.query("select * from t_user where id = 2", BeanPropertyRowMapper.newInstance(User.class));}}
本次的测试用例,不再有applicationContext.xml配置文件,而是使用一个Java配置类代替了这个配置文件。
Spring Boot基本编程模型
接下来,我们要开始使用Spring Boot开发应用程序。Spring Boot的基本开发模型如下:
导入依赖
1、添加起步依赖(这个起步依赖不是具体的JAR包,而是你要开发什么样的功能,就使用什么样的起步依赖)——注意:可以把起步依赖看成一个Spring Boot封装过的特殊依赖,这个依赖也是具备有传递性特征的
2、导入其他关联依赖(数据库驱动、JSTL等)
导入配置
1、配置application.properties或者application.yml
2、编写Java自定义配置
编码
1、编写Main入口,并加载SpringBoot自动配置
2、编写业务代码
a) 获取Spring Boot自动配置生成的BEAN Template
b) 使用BEAN Template来执行业务操作
大家可以先不用了解Spring Boot开发的具体细节,只需要重点记住这几个重点:
-
导入依赖
-
导入配置
-
编写代码
这个过程其实和我们之前的Spring开发并没有太大区别。
常见企业开发场景应用
构建Spring Java应用程序
第一个应用不涉及到数据库的操作。我们的目标是使用Spring Boot来编写一个简单的Java程序。这个Java程序只是通过Spring Boot来创建一个Spring IOC容器,并从调用容器中Bean的方法。
-
导入Spring Boot依赖
还记得前面的代码吗?我们在创建Maven项目后,需要往pom.xml中导入很多的以来。而使用了Spring Boot之后呢?
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency></dependencies>
yup. 你没看错,就只有这么几行。这个以
spring-boot-starter
开头的依赖称作起步依赖
。可以把它看成是Spring Boot应用程序必须要导入的依赖。它里面封装了很多的其他的依赖。这里,我们需要开发Spring应用程序,只需要导入一个spring-boot-starter
即可。 -
编写DAO接口和实现
public interface UserDao {/*** 根据ID获取用户* @param id* @return*/User get(int id);}
为了简单,这里就先不从数据中查询数据,直接构建一些User对象来操作(User实体类之前已经给出)
@Repositorypublic class UserDaoImpl implements UserDao{private ArrayList<User> userList = new ArrayList<User>();public UserDaoImpl() {// 往数组中添加一些模拟测试数据userList.add(new User(1, "zhangsan", "000"));userList.add(new User(2, "lisi", "000"));userList.add(new User(3, "wangwu", "000"));userList.add(new User(4, "zhaoliu", "000"));}@Overridepublic User get(int id) {for (User user : userList) {if(user.getId().equals(id)) {return user;}}return null;}}
-
编写服务接口和实现类
public interface UserService {/*** 根据ID获取用户* @param i* @return*/User get(int id);}
@Servicepublic class UserServiceImpl implements UserService{@Autowiredprivate UserDao userDao;@Overridepublic User get(int id) {return userDao.get(id);}}
-
编写Spring Boot应用程序入口
@SpringBootApplication public class Application {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(Application.class);UserService userService = context.getBean(UserService.class);User user = userService.get(1);System.out.println(user);} }
注意:
要在main所在的Applcation类上添加
@SpringBootApplication
注解,这个注解会启动Spring Boot的自动配置。然后使用SpringApplication.run可以创建一个Spring IOC工厂,它的返回值就是我们熟知的ApplicationContext。然后,我们就可以获取IOC工厂的Bean了。
构建Junit测试用例
要构建基于Spring Boot的测试用例,还需要额外引入另一个起步依赖。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency>
编写测试用例如下:
@RunWith(SpringRunner.class) @SpringBootTest(classes=Application.class) public class UserServiceImplTest {@Autowiredprivate UserService userService;@Testpublic void testGet() {User user = userService.get(2);System.out.println(user);}}
使用@SpringBootTest替代之前的@ContextConfiguration,直接加载Spring Boot的入口类即可。
构建Spring JDBC Template应用程序操作数据库
接下来,我将使用Spring Boot来使用JDBC Template操作数据库。
导入起步依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version> </parent> <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1</version></dependency></dependencies>
因为,这里需要使用到mysql驱动以及c3p0连接池,所以多导入了两个依赖
重新编写DAO
public interface UserDao {/*** 根据ID获取用户* @param id* @return*/User get(int id);}@Repository public class UserDaoImpl implements UserDao{@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic User get(int id) {return jdbcTemplate.queryForObject("select * from t_user t where t.id = ?",BeanPropertyRowMapper.newInstance(User.class),id);} }
编写Service
public interface UserService {/*** 根据ID获取用户* @param i* @return*/User get(int id); }@Service public class UserServiceImpl implements UserService{@Autowiredprivate UserDao userDao;@Overridepublic User get(int id) {return userDao.get(id);}}
编写配置文件application.properties
c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql:///springboot c3p0.user=root c3p0.password=000000
注意:这个配置文件中以c3p0开头的,其实是自定义的配置。一会我们需要指定这个前缀来进行加载
编写启动类
@SpringBootApplication public class Application {@Bean(name="datasource")@Primary@ConfigurationProperties(prefix="c3p0")public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {return new ComboPooledDataSource();}public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(Application.class);UserService userService = context.getBean(UserService.class);User user = userService.get(2);System.out.println(user);} }
注意@ConfigurationProperties(prefix="c3p0")
这个注解,这个注解表示,将application.properties配置文件中的以c3p0开头的配置信息注入到ComboPooledDataSource这个对象上面。而在application.properties中的配置c3p0.driverClass=com.mysql.jdbc.Driver
,相当于就是在进行属性注入。这里指的是:将com.mysql.jdbc.Driver注入到ComboPooledDataSource Bean的driverClass属性。
这种加载配置的方法,真的是不服不行。要比之前简单了很多。
构建Servlet、JSP程序
接下来我们要来使用Spring Boot来做最简单的Web开发(虽然我们开发不一定会用到,但我们还是来体验体验,毕竟这是我们的曾经啊...)
-
导入Spring Boot起步依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency></dependencies>
注意:使用Spring Boot开发JSP应用程序,一定要加载下面的依赖
<dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope> </dependency>
-
编写DAO
public interface UserDao {/*** 根据ID获取用户* @param id* @return*/User get(int id);}@Repositorypublic class UserDaoImpl implements UserDao{@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic User get(int id) {return jdbcTemplate.queryForObject("select * from t_user t where t.id = ?",BeanPropertyRowMapper.newInstance(User.class),id);}}
-
编写Service
public interface UserService {/*** 根据ID获取用户* @param i* @return*/User get(int id);/*** 查询所有用户* @return*/List<User> findAll();}@Service@Transactionalpublic class UserServiceImpl implements UserService{@Autowiredprivate UserDao userDao;@Overridepublic User get(int id) {return userDao.get(id);}}
-
编写Servlet | 这里使用的是注解方式定义Servlet,这种方式更加容易与Spring进行整合。
@WebServlet(name="UserServlet", urlPatterns="/user/findUserList") public class UserServlet extends HttpServlet{@Autowiredprivate UserService userService;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {List<User> users = userService.findAll();req.setAttribute("list", users);req.getRequestDispatcher("/index.jsp").forward(req, resp);} }
urlPatterns
配置了这个Servlet被访问的URL -
编写JSP页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP测试</title> </head> <body><table border=1><tr><th>ID</th><th>用户名</th><th>密码</th></tr><c:forEach items="${list}" var="user"><tr><td>${user.id}</td><td>${user.username}</td><td>${user.password}</td></tr></c:forEach></table> </body> </html>
-
编写入口
@SpringBootApplication @ServletComponentScan public class Application {@Bean(name="datasource")@ConfigurationProperties(prefix="c3p0")public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {return new ComboPooledDataSource();}public static void main(String[] args) {SpringApplication.run(Application.class);} }
注意:一定要在Application类上加上
@ServletComponentScan
注解,否则Servlet是不会被加载的。 -
编写配置文件
server.port=10086 server.context-path=/c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql:///springboot c3p0.user=root c3p0.password=000000
server.port
配置的是web应用访问的端口号,server.context-path=/是应用访问的根路径 -
访问http://localhost:10086/user/findUserList测试应用。如果应用执行成功应该可以看到用户数据
构建SSH应用程序(Spring、Spring MVC、Hibernate)
-
导入依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</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-actuator</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><dependency><groupId>javassist</groupId><artifactId>javassist</artifactId><version>3.11.0.GA</version></dependency></dependencies>
-
使用JPA注解修饰User实体类
@Entity @Table(name="t_user") public class User {@Id@GeneratedValue(strategy=GenerationType.IDENTITY)private Integer id;private String username;private String password;public User() {}public User(Integer id, String username, String password) {this.id = id;this.username = username;this.password = password;}public User(String username, String password) {this(null, username, password);}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "User [id=" + id + ", username=" + username + ", password=" + password + "]";} }
-
编写DAO
public interface UserDao {User get(int id);List<User> findAll();void add(User user);}@Repository public class UserDaoImpl extends HibernateDaoSupport implements UserDao{// 注入SessionFactory@Autowiredpublic void autoWiredFactory(SessionFactory sessionFactory) {super.setSessionFactory(sessionFactory);}@Overridepublic User get(int id) {return getHibernateTemplate().get(User.class, id);}@Overridepublic List<User> findAll() {return getHibernateTemplate().findByExample(new User());}@Overridepublic void add(User user) {getHibernateTemplate().save(user);} }
-
编写Service
public interface UserService {/*** 根据ID获取用户* @param i* @return*/User get(int id);/*** 查询所有用户* @return*/List<User> findAll();/*** 新增用户* @param user*/void add(User user);}@Service @Transactional public class UserServiceImpl implements UserService{@Autowiredprivate UserDao userDao;@Overridepublic User get(int id) {return userDao.get(id);}@Overridepublic List<User> findAll() {return userDao.findAll();}@Overridepublic void add(User user) {userDao.add(user);}}
-
编写Controller/Handler
@Controller @RequestMapping("/user") public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/findUserList")public String findUserList(Model model) {List<User> list = userService.findAll();model.addAttribute("list", list);return "/index.jsp";} }
-
JSP页面参见Servlet/JSP案例
-
编写Spring Boot入口
@SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class);}@Bean@ConfigurationProperties(prefix="c3p0")public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {return new ComboPooledDataSource();}@Bean@ConfigurationProperties(prefix="hibernate")public LocalSessionFactoryBean sessionFactory() throws PropertyVetoException {LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();sessionFactoryBean.setDataSource(c3p0DataSource());return sessionFactoryBean;}@Beanpublic HibernateTransactionManager transactionManager() throws PropertyVetoException {HibernateTransactionManager tx = new HibernateTransactionManager();tx.setSessionFactory(sessionFactory().getObject());return tx;} }
注意:此处因为Hibernate没有Starter起步依赖,所以我使用了Java配置来整合Hibernate。第一个Bean是C3P0数据源,第二个Bean是SessionFactory,第三个Bean是事务管理器。
-
编写配置文件
server.port=10086 server.context-path=/c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql:///springboot c3p0.user=root c3p0.password=000000hibernate.packagesToScan=com.itheima.springboot.entity
构建SSM应用(Spring、Spring MVC、MyBatis)
为了简单起见,这里使用逆向工程生成实体类、Mapper接口、Mapper映射文件。因为查询实体、映射文件的代码比较长,这里就不把代码贴上来了,大家自己使用逆向工程生成下就OK。
-
导入依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version> </parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.1</version></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency> </dependencies>
-
Service代码
public interface UserService {/*** 根据ID获取用户* @param i* @return*/TUser get(int id);/*** 查询所有用户* @return*/List<TUser> findAll();/*** 新增用户* @param user*/void add(TUser user); }@Service @Transactional public class UserServiceImpl implements UserService{@Autowiredprivate TUserMapper userMapper;@Overridepublic TUser get(int id) {return userMapper.selectByPrimaryKey(id);}@Overridepublic List<TUser> findAll() {return userMapper.selectByExample(null);}@Overridepublic void add(TUser user) {userMapper.insert(user);} }
-
Controller代码
@Controller @RequestMapping("/user") public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/findUserList")public String findUserList(Model model) {List<TUser> list = userService.findAll();model.addAttribute("list", list);return "/index.jsp";} }
-
Spring Boot入口应用
@SpringBootApplication @MapperScan(basePackages="com.itheima.springboot.mapper") public class Application {public static void main(String[] args) {SpringApplication.run(Application.class);} }
注意:Spring Boot整合MyBatis需要在Application类上添加@MapperScan,否则不会为Mapper创建代理对象,执行程序失败。
-
配置文件
server.port=10086 server.context-path=/#数据库配置 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql:///springboot spring.datasource.username=root spring.datasource.password=000000
这里使用默认的数据源,如果想要使用其他的数据源参照之前的配置即可
-
访问http://localhost:10086/user/findUserList
构建SSJPA应用(Spring、Spring MVC、Spring Data JPA)
-
导入Maven依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version> </parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1</version></dependency> </dependencies>
注意:导入了
spring-boot-starter-data-jpa
依赖 -
编写Java实体类,参考SSH整合JPA实体类
-
编写DAO
public interface UserRepository extends JpaRepository<User, Integer>{ }
(这个代码是真的喜欢)
-
编写Service
public interface UserService {/*** 根据ID获取用户* @param i* @return*/User get(int id);/*** 查询所有用户* @return*/List<User> findAll();/*** 新增用户* @param user*/void add(User user); }
-
编写Controller
@Controller @RequestMapping("/user") public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/findUserList")public String findUserList(Model model) {List<User> list = userService.findAll();model.addAttribute("list", list);return "/index.jsp";} }
-
编写入口
@SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class);}@Bean(name="datasource")@Primary@ConfigurationProperties(prefix="c3p0")public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {return new ComboPooledDataSource();} }
-
配置文件
server.port=10086 server.context-path=/c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql:///springboot c3p0.user=root c3p0.password=000000
构建FreeMarker应用程序
-
导入依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency></dependencies>
多导入了
spring-boot-starter-freemarker
起步依赖 -
编写DAO
public interface UserRepository extends JpaRepository<User, Integer>{ }
-
编写Service
public interface UserService {/*** 根据ID获取用户* @param i* @return*/User get(int id);/*** 查询所有用户* @return*/List<User> findAll();/*** 新增用户* @param user*/void add(User user);}@Service @Transactional public class UserServiceImpl implements UserService{@Autowiredprivate UserRepository userRepository;@Overridepublic User get(int id) {return userRepository.findOne(id);}@Overridepublic List<User> findAll() {return userRepository.findAll();}@Overridepublic void add(User user) {userRepository.save(user);} }
-
编写Controller
@Controller @RequestMapping("/user") public class UserController {// 静态页面输出到的目录@Value("${freemarker.output_path}")private String OUTPUT_PATH;@Autowiredprivate UserService userService;// 获取FreeMarker配置类@Autowiredprivate Configuration configuration;@RequestMapping("/genPage")@ResponseBodypublic Map genPage() throws Exception {List<User> list = userService.findAll();Map model = new HashMap<String, Object>();model.put("list", list);Template template = configuration.getTemplate("user_list.ftl");template.process(model, new FileWriter(OUTPUT_PATH + "userList.html"));Map result = new HashMap<String, Object>();result.put("success", true);result.put("message", "生成页面成功!");return result;} }
-
编写入口
@SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class);}@Bean(name="datasource")@Primary@ConfigurationProperties(prefix="c3p0")public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {return new ComboPooledDataSource();} }
-
编写配置文件
server.port=10086 server.context-path=/ # FreeMarker静态页面输出目录 freemarker.output_path=G:/workspace/free_test/t49/src/main/webapp/c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql:///springboot c3p0.user=root c3p0.password=000000
-
编写FreeMarker模板,此模板默认放在classpath下的template/user_list.ftl中
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP测试</title> </head> <body><table border=1><tr><th>ID</th><th>用户名</th><th>密码</th></tr><#list list as user><tr><td>${user.id}</td><td>${user.username}</td><td>${user.password}</td></tr></#list></table> </body> </html>
-
访问http://localhost:10086/user/genPage,然后检查HTML页面是否生成
构建基于Redis缓存应用程序
-
导入依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency></dependencies>
要开发导入Redis起步依赖
spring-boot-starter-data-redis
-
编写DAO
public interface UserRepository extends JpaRepository<User, Integer>{}
-
编写Service
public interface UserService {/*** 根据ID获取用户* @param i* @return*/User get(int id);/*** 查询所有用户* @return*/List<User> findAll();/*** 新增用户* @param user*/void add(User user);}@Service @Transactional public class UserServiceImpl implements UserService{@Autowiredprivate UserRepository userRepository;@Autowiredprivate RedisTemplate redisTemplate;@Overridepublic User get(int id) {return userRepository.findOne(id);}@Overridepublic List<User> findAll() {Long size = redisTemplate.boundListOps("userList").size();List<User> userList = redisTemplate.boundListOps("userList").range(0, size);if(userList == null || size == 0) {System.out.println("从数据库中获取数据...");userList = userRepository.findAll();System.out.println("将数据放入缓存...");redisTemplate.boundListOps("userList").rightPushAll(userList.toArray(new User[0]));return userList;}else {System.out.println("从缓存中获取数据...");return userList;}}@Overridepublic void add(User user) {userRepository.save(user);}}
-
编写Controller
@Controller @RequestMapping("/user") public class UserController {@Value("${freemarker.output_path}")private String OUTPUT_PATH;@Autowiredprivate UserService userService;@RequestMapping("/findUserList")public String findUserList(Model model) {List<User> list = userService.findAll();model.addAttribute("list", list);return "/index.jsp";} }
-
编写Spring Boot入口
@SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class);}@Bean(name="datasource")@Primary@ConfigurationProperties(prefix="c3p0")public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();return comboPooledDataSource;} }
-
编写配置文件
server.port=10086 server.context-path=/c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql:///springboot c3p0.user=root c3p0.password=000000
-
启动Redis
-
访问http://localhost:10086/user/findUserList,注意控制台的变化
构建基于ActiveMQ消息队列应用程序
-
导入依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-activemq</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.28</version></dependency></dependencies>
这里导入了ActiveMQ的起步依赖
-
编写DAO
public interface UserRepository extends JpaRepository<User, Integer>{ }
-
编写Service
public interface UserService {/*** 根据ID获取用户* @param i* @return*/User get(int id);/*** 查询所有用户* @return*/List<User> findAll();/*** 新增用户* @param user*/void add(User user);}@Service @Transactional public class UserServiceImpl implements UserService{@Autowiredprivate UserRepository userRepository;@Overridepublic User get(int id) {return userRepository.findOne(id);}@Overridepublic List<User> findAll() {return userRepository.findAll();}@Overridepublic void add(User user) {userRepository.save(user);}}
-
编写Controller
@Controller @RequestMapping("/user") public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate JmsTemplate jmsTemplate;@RequestMapping("/findUserList")public String findUserList(Model model) {List<User> list = userService.findAll();model.addAttribute("list", list);return "/index.jsp";}@RequestMapping("/add")public String add(User user) {userService.add(user);final List<User> userList = userService.findAll();jmsTemplate.send("queue_page", new MessageCreator() {@Overridepublic Message createMessage(Session session) throws JMSException {return session.createTextMessage(JSON.toJSONString(userList));}});return "redirect:/user/findUserList";} }
在添加一个用户,往AMQ中发送一条queue消息
-
编写Listener
@Component public class PageGeneratorListener {@Value("${freemarker.output_path}")private String OUTPUT_PATH;@Autowiredprivate Configuration configuration;@JmsListener(destination="queue_page")public void genHtml(String userListStr) throws Exception {Template template = configuration.getTemplate("user_list.ftl");List<User> userList = JSON.parseArray(userListStr, User.class);Map map = new HashMap<String, Object>();map.put("list", userList);template.process(map, new FileWriter(OUTPUT_PATH + "user_list.html"));} }
监听AMQ中queue_page队列的消息,如果接收到消息,使用FreeMarker重新生成一个HTML页面在服务器端
-
编写入口
@SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class);}@Bean(name="datasource")@Primary@ConfigurationProperties(prefix="c3p0")public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();return comboPooledDataSource;} }
-
编写配置文件
server.port=10086 server.context-path=/freemarker.output_path=G:/workspace/free_test/t51/src/main/webapp/spring.activemq.broker-url=tcp://localhost:61616 spring.activemq.user=admin spring.activemq.password=adminc3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql:///springboot c3p0.user=root c3p0.password=000000
构建基于Spring Security访问控制应用程序
-
导入依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.4</version></dependency></dependencies>
导入了Spring Security的起步依赖
spring-boot-starter-security
-
编写DAO
public interface UserRepository extends JpaRepository<User, Integer>{// 根据用户名查询用户User findByUsername(String username); }
-
编写Service
public interface UserService {/*** 根据ID获取用户* @param i* @return*/User get(int id);/*** 查询所有用户* @return*/List<User> findAll();/*** 新增用户* @param user*/void add(User user);}@Service @Transactional public class UserServiceImpl implements UserService{@Autowiredprivate UserRepository userRepository;@Overridepublic User get(int id) {return userRepository.findOne(id);}@Overridepublic List<User> findAll() {return userRepository.findAll();}@Overridepublic void add(User user) {userRepository.save(user);}}
-
编写Spring Security登录验证用户服务
@Service @Transactional public class AuthUserService implements UserDetailsService {@Autowiredprivate UserRepository userRepository;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {if(StringUtils.isNotBlank(username)) {// 从数据库中获取用户User user = userRepository.findByUsername(username);if(user != null) {// 创建用户、加载角色List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();authorities.add(new SimpleGrantedAuthority("ROLE_USER"));return new org.springframework.security.core.userdetails.User(username, user.getPassword(), authorities);}else {throw new UsernameNotFoundException("用户名不存在");}}return null;} }
-
编写Controller
@Controller @RequestMapping("/user") public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/findUserList")public String findUserList(Model model) {List<User> list = userService.findAll();model.addAttribute("list", list);return "/index.jsp";}@RequestMapping("/add")public String add(User user) {userService.add(user);return "redirect:/user/findUserList";} }
-
编写应用入口
@SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class);}@Bean(name="datasource")@Primary@ConfigurationProperties(prefix="c3p0")public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();return comboPooledDataSource;} }
-
编写配置文件
server.port=10086server.context-path=/freemarker.output_path=G:/workspace/free_test/t51/src/main/webapp/c3p0.driverClass=com.mysql.jdbc.Driverc3p0.jdbcUrl=jdbc:mysql:///springbootc3p0.user=rootc3p0.password=000000
-
编写页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>JSP测试</title></head><body><table border="1"><form action="<%=request.getContextPath()%>/user/add" method="post"><tr><td>用户名:<input type="text" name="username"/></td><td>密码:<input type="text" name="password"/></td><td><input type="submit" value="新增"/></td></tr></form></table><table border=1><tr><th>ID</th><th>用户名</th><th>密码</th></tr><c:forEach items="${list}" var="user"><tr><td>${user.id}</td><td>${user.username}</td><td>${user.password}</td></tr></c:forEach></table></body></html>
-
访问http://localhost:10086/user/findUserList,弹出登录对话框,输入数据库中任意的用户名和密码登录即可。
-
构建基于Dubbox分布式架构应用程序
启动ZooKeeper
编写服务提供者
-
导入依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>com.cjoop</groupId><artifactId>spring-boot-starter-dubbox</artifactId><version>0.0.1</version></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.7</version></dependency><dependency><groupId>com.github.sgroschupf</groupId><artifactId>zkclient</artifactId><version>0.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.4</version></dependency></dependencies>
这里导入了Dubbox的起步依赖,这样配置起来很方便。
-
导入实体类,注意因为要在网络上传输,所以要实现Serializable接口
@Entity @Table(name="t_user") public class User implements Serializable{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)private Integer id;private String username;private String password;public User() {}public User(Integer id, String username, String password) {this.id = id;this.username = username;this.password = password;}public User(String username, String password) {this(null, username, password);}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "User [id=" + id + ", username=" + username + ", password=" + password + "]";} }
-
编写DAO
public interface UserRepository extends JpaRepository<User, Integer>{User findByUsername(String username);}
-
编写Service(注意:请使用Dubbox中的@Service,否则服务将不会被发布)
public interface UserService {/*** 根据ID获取用户* @param i* @return*/User get(int id);/*** 查询所有用户* @return*/List<User> findAll();/*** 新增用户* @param user*/void add(User user);}@Service @Transactional public class UserServiceImpl implements UserService{@Autowiredprivate UserRepository userRepository;@Overridepublic User get(int id) {return userRepository.findOne(id);}@Overridepublic List<User> findAll() {return userRepository.findAll();}@Overridepublic void add(User user) {userRepository.save(user);}}
-
编写入口
@SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class);}@Bean(name="datasource")@Primary@ConfigurationProperties(prefix="c3p0")public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();return comboPooledDataSource;} }
-
编写配置文件
server.port=10086 server.context-path=/#配置Dubbo包扫描,自动将带有Service注解的类发布为Dubbox服务 dubbo.annotation.package=com.itheima.springboot.service dubbo.application.name=com.itheima.user.servicec3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql:///springboot c3p0.user=root c3p0.password=000000
-
启动应用,如果服务发布成功,可以在Dubbo Admin上看到已经发布的服务
编写服务消费者
-
导入依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.14.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><dependency><groupId>com.cjoop</groupId><artifactId>spring-boot-starter-dubbox</artifactId><version>0.0.1</version></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.7</version></dependency><dependency><groupId>com.github.sgroschupf</groupId><artifactId>zkclient</artifactId><version>0.1</version></dependency><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId></dependency></dependencies>
-
引入实体类
public class User {private Integer id;private String username;private String password;public User() {}public User(Integer id, String username, String password) {this.id = id;this.username = username;this.password = password;}public User(String username, String password) {this(null, username, password);}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "User [id=" + id + ", username=" + username + ", password=" + password + "]";}}
-
引入Service接口
public interface UserService {/*** 根据ID获取用户* @param i* @return*/User get(int id);/*** 查询所有用户* @return*/List<User> findAll();/*** 新增用户* @param user*/void add(User user);}
-
编写Controller
@Controller@RequestMapping("/user")public class UserController {@Referenceprivate UserService userService;@RequestMapping("/findUserList")public String findUserList(Model model) {List<User> list = userService.findAll();model.addAttribute("list", list);return "/index.jsp";}@RequestMapping("/add")public String add(User user) {userService.add(user);return "redirect:/user/findUserList";}}
-
编写入口
@SpringBootApplicationpublic class Application {public static void main(String[] args) {SpringApplication.run(Application.class);}}
-
编写配置文件
server.port=10087server.context-path=/dubbo.annotation.package=com.itheima.springboot.controllerdubbo.application.name=com.itheima.user.web
-
编写页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>JSP测试</title></head><body><table border="1"><form action="<%=request.getContextPath()%>/user/add" method="post"><tr><td>用户名:<input type="text" name="username"/></td><td>密码:<input type="text" name="password"/></td><td><input type="submit" value="新增"/></td></tr></form></table><table border=1><tr><th>ID</th><th>用户名</th><th>密码</th></tr><c:forEach items="${list}" var="user"><tr><td>${user.id}</td><td>${user.username}</td><td>${user.password}</td></tr></c:forEach></table></body></html>
-
访问http://localhost:10087/user/findUserList
Spring Boot自动配置原理结构分析
通过实践,可以隐约感觉到。Spring Boot相当于基于Maven和Spring做了一个开发平台,使用这个平台可以减少配置、快速开发。那么Spring Boot到底是如何做到的呢?
回想,我们开发的第一个案例。我们只是往pom.xml中进行简单配置,就可以开始进行Spring开发了。
然后,更新项目可以看到,在Maven的依赖中,导入了很多的JAR包。
这两段配置怎么这么神奇,它到底做了什么?先来看看这个spring-boot-starter-parent的pom文件。
先是定义了很多的常量
里面还定义了一些依赖的版本锁定、插件的版本锁定。但没有导入具体的JAR包。
这个spring-boot-starter-parent从spring-boot-dependencies中继承,这个pom文件中定义了大量的版本号、以及版本锁定。
这些版本应该都是做过兼容性测试的,一般不要去修改否则出现不兼容问题是比较麻烦的。
再看看spring-boot-starter这个依赖
这个starter起步依赖中包含了导入了spring-boot依赖,spring-boot依赖导入了spring framework的核心依赖。
spring-boot-autoconfigure依赖,spring-boot-starter-logging会自动日志相关的依赖。
这个spring-boot-autoconfigure里面包含了很多玄机。
我猜想,Spring Boot是通过自动配置,来帮助我们自动创建了很多bean在IOC容器中。
所以接下来要回答两个问题:
1、Spring创建了哪些Bean?
2、因为我们之前都是通过编写很多的配置文件来创建和配置bean的,那Spring是如何读取配置来创建这些bean的?
接着猜:
以前的配置信息肯定还有,Spring不应该是把之前假设的平台全部推倒,而是把常用的配置整合起来了,就省去了我们自己来手动配置的过程。那么,我猜:每一个Starter都会有其对应的配置信息。我们来找一找spring-boot-starter的配置信息。
这个autoconfigure里面有大量的包,而且命名方式是以技术组件来命名的
要知道Spring Boot创建了哪些bean,直接去看自动配置包中,以Configuration结尾的类就可以了。要想看看具体application.properties中应该配置哪些属性,直接去看以properties文件结尾的类就可以了。
来看一段自动配置的源代码,下面这段代码是从JmsAutoConfiguration中截取出来的。
@Configuration @ConditionalOnClass({ Message.class, JmsTemplate.class }) @ConditionalOnBean(ConnectionFactory.class) @EnableConfigurationProperties(JmsProperties.class) @Import(JmsAnnotationDrivenConfiguration.class) public class JmsAutoConfiguration {@Configurationprotected static class JmsTemplateConfiguration {private final JmsProperties properties;private final ObjectProvider<DestinationResolver> destinationResolver;private final ObjectProvider<MessageConverter> messageConverter;public JmsTemplateConfiguration(JmsProperties properties,ObjectProvider<DestinationResolver> destinationResolver,ObjectProvider<MessageConverter> messageConverter) {this.properties = properties;this.destinationResolver = destinationResolver;this.messageConverter = messageConverter;}@Bean@ConditionalOnMissingBean@ConditionalOnSingleCandidate(ConnectionFactory.class)public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);jmsTemplate.setPubSubDomain(this.properties.isPubSubDomain());DestinationResolver destinationResolver = this.destinationResolver.getIfUnique();if (destinationResolver != null) {jmsTemplate.setDestinationResolver(destinationResolver);}MessageConverter messageConverter = this.messageConverter.getIfUnique();if (messageConverter != null) {jmsTemplate.setMessageConverter(messageConverter);}JmsProperties.Template template = this.properties.getTemplate();if (template.getDefaultDestination() != null) {jmsTemplate.setDefaultDestinationName(template.getDefaultDestination());}if (template.getDeliveryDelay() != null) {jmsTemplate.setDeliveryDelay(template.getDeliveryDelay());}jmsTemplate.setExplicitQosEnabled(template.determineQosEnabled());if (template.getDeliveryMode() != null) {jmsTemplate.setDeliveryMode(template.getDeliveryMode().getValue());}if (template.getPriority() != null) {jmsTemplate.setPriority(template.getPriority());}if (template.getTimeToLive() != null) {jmsTemplate.setTimeToLive(template.getTimeToLive());}if (template.getReceiveTimeout() != null) {jmsTemplate.setReceiveTimeout(template.getReceiveTimeout());}return jmsTemplate;}}
这里面有几个很重要的注解
-
@ConditionalOnClass
这个注解表示,如果检测到当前的JVM中加载了Message.class, JmsTemplate.class,就加载该Java Config配置。
-
@ConditionalOnMissingBean
这个注解表示,如果IOC容器中没有检测到这个类型的Bean,就创建一个。如果检测到了,那么就不创建了。所以,如果我们自己配置了JmsTemplate这个Bean,那这个自动配置就失效了
-
@ConditionalOnBean
这个注解表示,如果IOC容器中有指定类型的Bean,才加载Java Config配置。例如:这里如果检测到容器中有ConnectionFactory类型的Bean,才会创建JmsTemplate。
-
@EnableConfigurationProperties
这个注解表示将以Properties结尾的配置类,加载到当前的自动配置类中。一般的Starter中的Properties类都可以从application.properties中的指定前缀的属性加载。从而让我们可以轻松的自定义里面的配置。
-
@Import
导入其他的Java Config配置,相当于之前XML配置中的import。
结尾
大家应该有一个直接的体会,Spring Boot真的让我们的工作更加轻松了。以前要写的很多配置、导很多的依赖,现在只需要短短几行代码就可以解决问题。而且,不再需要我们去考虑版本之间的兼容问题了。相信,很快大家编写的应用都会切换到Spring Boot。它将让我们将更多的精力放在编写、设计结构、算法上。