SpringBoot
一.Spring回顾
1.基本概念
1.1.SpringBoot介绍
Spring Boot是其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
1.2…JavaConfig基本概念
Spring注解式编程也叫JavaConfig,即通过一个Java类来配置Spring,或者说把以前xml中配置的内容搬到了一个Java类中,这个类就是Spring的配置类,和以前的XML有相同的作用。
2.Spring回顾
2.1.IOC基本概念
控制反转,我们不需要手工去管理Bean,而是将Bean的创建,初始化,销毁等等工作全部交给Spring管理 。解放我们的工作量。
2.2.DI基本概念
依赖注入,既然Bean的管理交给了Spring,那么Bean之间的依赖关系也需要Spring去维护,DI指定就是Bean与Bean之间的依赖注入。
2.3.AOP基本概念
面向切面编程实现 ,可以看做是对面向对象的补充,面向切面指的是把多个Bean看成一个面,使用横切技术可以让功能(业务)作用于多个Bean , 使用AOP可以实现程序代码的解耦,公共代码的统一抽取和封装等等。Aop的原理是动态代理。
2.4.XML配置IOC
- 操作步骤
1.创建项目
2.导入依赖
3.创建applicationContext.xml
4.创建一个简单的类 MyBean
5.把这类在 applicationContext.xml 配置成Bean
6.编写测试类:让Spring加载applicationContext.xml 配置文件,获取容器 - ClassPathXmlApplicationContext
7.获取MyBean
-
创建项目
-
导入Spring依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies>
- 创建一个MyBean
public class MyBean {
}
- 创建xml配置文件,配置Bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myBean" class="cn.chenxin._01_xml_ioc.MyBean"></bean>
</beans>
- 测试
public class XmlTest {
@Test
public void testMyBean(){
//6.编写测试类:让Spring加载applicationContext.xml 配置文件,获取容器
//针对于classpath下的xml配置的 Spring容器上下文对象
ClassPathXmlApplicationContext classPathXmlApplicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//7.获取MyBean
MyBean bean = classPathXmlApplicationContext.getBean(MyBean.class);
System.out.println(bean);
}
}
二.注解方式配置IOC
1.操作步骤
1.创建新的包
2.创建一个类作为Spring的配置类
3.创建一个普通的类作为bean(MyBean)
4.在配置类中,配置Bean
5.编写测试:加载配置类 ,获取容器 ,获取MyBean
2.代码演示
2.1.创建一个类作为Bean
public class MyBean {
}
2.2.创建Spring的配置类
/**
* Spring的配置类 相当于是:applicationContext.xml
* @Configuration :Spring的配置标签,标记改类是Spring的配置类
*/
@Configuration
public class ApplicationConfig {
}
2.3…在配置类中定义Bean
/**
* Spring的配置类 相当于是:applicationContext.xml
* @Configuration :Spring的配置标签,标记改类是Spring的配置类
*/
@Configuration
public class ApplicationConfig {
/**
* @Bean : Spring的bean的定义标签 ,标记方法返回的对象交给Spring容器管理
*/
@Bean
public MyBean myBean(){
return new MyBean();
}
}
2.4…测试
加载配置类,获取容器,获取MyBean
@Test
public void test(){
//加载配置文件,拿到Spring容器
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(ApplicationConfig.class);
//通过容器获取Mybaean
MyBean bean = applicationContext.getBean(MyBean.class);
System.out.println(bean);
}
三.ComponentScan自动扫描
@ComponentScan是ioc组件自动扫描,相当于是 <context:component-scan base-package=
* 默认扫描当前包及其子包 中打了 @Service , @Controller , @Component , @Repository
其中一个注解的 类自动交给Spring管理;也可以通过 basePackages 属性指定扫描的包路径。
1.操作步骤
1.创建配置类
2.创建一个普通类作为Spring的Bean
3.要交给Spring管理的类上贴标签: @Service , @Controller , @Component , @Repository
4.在配置类上贴 @ComponentScan标签
5.编写测试
注意:使用了IOC扫描,那么就不要再使用方法的方式定义Bean了
2.代码演示
1.准备MyBean帖@Component
@Component
public class MyBean {
}
2.创建配置类,帖@ComponentScan
@Configuration
//@ComponentScans
@ComponentScan("包名")
public class ApplicationConfig {
}
注意:如果使用了自动扫描 ,那么配置类中就不要去配置@Bean
3.编写测试类
同上一个案例一样…省略…
4.其他属性介绍
-
ComponentScan.lazyInit :懒初始化
-
ComponentScan.Filter[] includeFilters :包含
-
ComponentScan.excludeFilters :排除
四.Bean的详解
1.Bean的属性介绍
我们以前使用Spring使用xml进行配置,如下:
<bean id="myBean"
name="myBean2"
init-method=""
destroy-method=""
lazy-init="false"
scope="prototype"
class="cn.chenxin._01_xml_ioc.MyBean">
...
</bean>
那么在JavaCong中如何配置Bean的各种属性?
1.1.Bean的id
- 那么在JavaCong中,方法名就是Bean的id
1.2.Bean的name
- 可以通过 @Bean标签的name属性指定
1.3.生命周期方法
-
init-method初始方法: @Bean(initMethod = “”) 指定
-
destroy-method销毁方法:@Bean(destroyMethod = “”)指定
1.4.Bean的Scope
- 单利多利,通过 @Scope(“prototype”)指定
1.5.懒初始化:
- lazy-init="false"懒初始化: 通过标签 @Lazy(value=false) 指定
2.代码演示
1.1.配置MyBean
@Configuration
public class ApplicationConfig {
/**
* bean的id :就是方法的名字“myBean”
* bean的name: 通过 @Bean(name = "myBean") 指定
* init-method初始方法: @Bean(initMethod = "") 指定
* destroy-method销毁方法:@Bean(destroyMethod = "")指定
* lazy-init="false"懒初始化: 通过标签 @Lazy(value=false) 指定
* scope="singleton"单例: 通过 @Scope(value="singleton")指定
*/
@Bean(name = "myBean",initMethod = "init",destroyMethod = "destroy")
//@Lazy(value=false)
//@Scope(value="singleton")
public MyBean myBean(){
MyBean myBean = new MyBean();
return myBean;
}
}
1.2.定义init
和destroy
方法
public class MyBean {
public void init(){
System.out.println("啊,我被创建啦....");
}
public void destroy(){
System.out.println("啊,我被销毁啦....");
}
}
1.3.Spring的Test
上面的案例中我们的是使用的Junit的测试 ,在很多场景下Junit测试不能满足我们的需求,比如Junit测试会导致Bean的销毁方法没办办法正常管理,所以我们需要用到Spring的测试。
- 导入Spring测试包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
- 编写测试类
//使用Spring的Test ,不要直接用Junit的Test
//@ContextConfiguration(classes = ApplicationConfig.class) :加载Spring的配置类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
public class JavaConfigTest {
@Autowired
private MyBean myBean;
@Test
public void testMyBean() throws Exception{
System.out.println(myBean);
}
}
需要注意:
使用了Spring的测试之后,就不要再使用new AnnotationConfigApplicationContext
这种方式了
@ContextConfiguration标签后面跟的是配置类的字节码
五.依赖注入
我们以前使用Spring使用xml进行配置,我们除了定义Bean而外还会给Bean进行依赖对象的注入,如下:
<bean id="myBean"
...
class="cn.chenxin._01_xml_ioc.MyBean">
<property name="username" value="zs" />
<property name="OtherBean" ref="OtherBean" />
</bean>
1.操作步骤
1.创建MyBean类,MyBean中有OtherBean字段
2.创建OtherBean类
3.定义MyBean
4.定义OtherBean
5.把OtherBean设置给MyBean
6.测试
2.代码演示
2.1.创建MyBean
public class MyBean {
private String username;
private OtherBean otherBean;
...getter,setter...
2.2.创建OtherBean
public class OtherBean {
}
2.2.配置MyBean,注入OtherBean
- 方式一:直接通过调方法的方式注入OtherBean
@Configuration
public class ApplicationConfig {
//@Autowired
//private OtherBean otherBean2;
/**
* 需求:给MyBean注入OtherBean
* 1.MyBean 需要通过容器获得
* 2.OtherBean 也需要通过容器获得
* 3.通过容器直接拿到的OtherBean要和通过MyBean拿到的OtherBean是同一个
*/
@Bean
public MyBean myBean(){
MyBean myBean = new MyBean();
//注入普通值
myBean.setUsername("我是MyBean");
//方式一:调用方法 , 通过掉OtherBean方法的方式获取OtherBean,
myBean.setOtherBean(otherBean());
return myBean;
}
//定义OtherBean
@Bean
public OtherBean otherBean(){
return new OtherBean();
}
}
- 方式二:直接参数传入OtherBean
@Configuration
public class ApplicationConfig {
//@Autowired
//private OtherBean otherBean2;
/**
* 需求:给MyBean注入OtherBean
* 1.MyBean 需要通过容器获得
* 2.OtherBean 也需要通过容器获得
* 3.通过容器直接拿到的OtherBean要和通过MyBean拿到的OtherBean是同一个
*/
@Bean
public MyBean myBean(OtherBean otherBean){
MyBean myBean = new MyBean();
//注入普通值
myBean.setUsername("我是MyBean");
//方式一:调用方法 , 通过掉OtherBean方法的方式获取OtherBean,
myBean.setOtherBean(otherBean);
return myBean;
}
//定义OtherBean
@Bean
public OtherBean otherBean(){
return new OtherBean();
}
}
2.3.测试
//使用Spring的Test ,不要直接用Junit的Test
//@ContextConfiguration(classes = ApplicationConfig.class) :加载Spring的配置类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
public class JavaConfigTest {
@Autowired
private MyBean myBean;
@Autowired
private OtherBean otherBean;
@Test
public void testMyBean() throws Exception{
System.out.println(myBean);
System.out.println(myBean.getOtherBean());
System.out.println(otherBean);
}
}
注意:如果MyBean是通过贴@Component标签的方式来定义的,那么注入OtherBean通过@Autowired就可以了。
六.条件Conditional
Conditional用来对某些组件是否注册做条件限制,比如:Conditional注解帖在bean的定义方法上来判断,如果不满足条件就不会定义bean
案例演示:创建一个Bean,如果操作系统的环境是Windows ,那就创建,否则不创建
1.准备工作
1.建包
2.建类MyBean
3.建配置类
4.配置类,配置MyBean
5.给MyBean加上条件:如果操作系统的环境是Windows ,那就创建
6.测试
2.代码演示
省略掉一些不重要的步骤…
2.1.在Bean的定义方法帖@Conditional
@Configuration
public class ApplicationConfig {
//定义条件:如果操作系统的环境是Windows ,那就创建,否则不创建
// @Conditional(value = MyBeanCondition.class):
//给Bean的定义加上条件,这个标签也可以打在类上面
//value属性指向的是条件类
@Bean
@Conditional(value = MyBeanCondition.class)
public MyBean myBean(){
return new MyBean();
}
}
2.2.定义条件类
//定义MyBean的条件类,MyBean是否能定义,通过该类的 matches 方法返回的boolean决定的
public class MyBeanCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//环境对象
Environment environment = context.getEnvironment();
//操作系统名字
String os = environment.getProperty("os.name");
if(os.equals("Windows 10")){
return true;
}
return false;
}
}
2.3.测试
根据条件类中matches方法的boolean值观察测试类中是否能注入MyBean
//使用Spring的Test ,不要直接用Junit的Test
//@ContextConfiguration(classes = ApplicationConfig.class) :加载Spring的配置类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
public class JavaConfigTest {
@Autowired
private MyBean myBean;
@Test
public void testMyBean() throws Exception{
System.out.println(myBean);
}
}
七.@Import导入
@Import标签,可以有用来实现配置类之间的导入,如同 “ 导入配置 , 当然还可以通过导入ImportSelector,以及导入ImportBeanDefinitionRegistrar的方式注册Bean。
1.导入配置Configuration
演示案例:创建两个配置类,一个配置类 ApplicationConfig
配置MyBean
,另一个配置类 OtherConfig
配置OtherBean
,使用@Improt
把两个配置类导入在一起,并且MyBean
中的OtherBean
要有值
1.操作步骤
1.创建两个配置类 `ApplicationConfig` ,`OtherConfig`
2.创建两个普通类 `MyBean` ,`OtherBean`
3.ApplicationConfig配置MyBean , MyBean只要注入OtherBean的值
4.OtherConfig配置`OtherBean`
5.@Improt导入配置类在一起
6.测试
2.代码演示
- 创建MyBean,OtherBean
public class MyBean {
private OtherBean otherBean;
public OtherBean getOtherBean() {
return otherBean;
}
public void setOtherBean(OtherBean otherBean) {
this.otherBean = otherBean;
}
}
- 创建配置类OtherConfig,定义OtherBean
//第二个配置类
@Configuration
public class OtherConfig {
@Bean
public OtherBean otherBean(){
return new OtherBean();
}
}
- 创建ApplicationConfig导入OtherConfig
//主配置类
//@Import(OtherConfig.class): 导入另外一个配置类
@Configuration
@Import(OtherConfig.class)
public class ApplicationConfig {
@Bean
public MyBean myBean(OtherBean otherBean){
MyBean myBean = new MyBean();
myBean.setOtherBean(otherBean);
return myBean;
}
}
- 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
public class JavaConfigTest {
@Autowired
private MyBean myBean;
@Autowired
private OtherBean otherBean;
@Test
public void testMyBean() throws Exception{
System.out.println(myBean);
System.out.println(myBean.getOtherBean());
System.out.println(otherBean);
}
}
-
分析图
2.导入ImportSelector
ImportSelector接口的作用是选择导入那些类,其中的方法 selectImports 就是用来返回要导入的类的class,
我们需要定义一个类,去实现 ImportSelector接口,复写selectImports 方法,返回我们要导入的类的字节码的字符串数组,然后把我们的类,交给@Import标签。
演示案例:在上面导入配置类的案例上做拓展 ,通过ImportSelector去导入MyBean和OtherBean。@Import标签去导入 ImportSelector的实现类。
1.操作步骤
1.创建mybean ,和OtherBean
2.创建主配置类
3.定义类 MyImportSelector 实现 ImportSelector
4.主配置类通过@Import(MyImportSelector.class)
5.测试
2.代码演示
省略到一些简单的步骤….
- 定义MyImportSelector
//定义导入选择器
public class MyImportSelector implements ImportSelector {
//返回要导入的类的字节码
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"cn.chenxin._08_import_selector.MyBean",
"cn.chenxin._08_import_selector.OtherBean"};
}
}
- 定义配置类,导入选择器
@Configuration
@Import(value = MyImportSelector.class)
public class ApplicationConfig {
}
- 测试
//使用Spring的Test ,不要直接用Junit的Test
//@ContextConfiguration(classes = ApplicationConfig.class) :加载Spring的配置类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
public class JavaConfigTest {
@Autowired
private MyBean myBean;
@Autowired
private OtherBean otherBean;
@Test
public void testMyBean() throws Exception{
System.out.println(myBean);
System.out.println(otherBean);
}
}
3.导入ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar导入Bean的注册器,其中的registerBeanDefinitions方法提供了一个BeanDefinitionRegistry参数可以用来注册Bean
演示案例:定义MyBean,通过ImportBeanDefinitionRegistrar的方式来注册MyBean到Spring容器。
1.操作步骤
1.创建MyBean
2.创建导入注册器: MyImportBeanDefinitionRegistrar
3.创建配置类
4.测试
2.代码演示
- 创建MyBean
public class MyBean {
}
- 定义 ImportBeanDefinitionRegistrar
//Bean注册器
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
//BeanDefinitionRegistry:bean的注册器,可以注册Bean
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
//参数:bean的名字 ,Bean的定义对象 BeanDefinition
RootBeanDefinition myBeanDefinition = new RootBeanDefinition(MyBean.class);
registry.registerBeanDefinition("myBean",myBeanDefinition);
}
}
- 定义配置类
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class) //导入bean注册器
public class ApplicationConfig{
}
- 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
public class JavaConfigTest {
@Autowired
private MyBean myBean;
@Test
public void testMyBean() throws Exception{
System.out.println(myBean);
}
}
八.SpringBoot入门
1.HelloWorld程序
使用Spring创建有一个简单Web程序,通过浏览器访问 http://localhost:8080 能够返回“hello world”信息
1.1.创建普通jar工程,导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
1.2.创建配置类
@SpringBootApplication
public class ApplicationConfig {
public static void main(String[] args) {
SpringApplication.run(ApplicationConfig.class);
}
}
1.3.编写Controller
@Controller
public class Example {
@RequestMapping("/")
@ResponseBody
String home() {
return "Hello World!";
}
}
1.4.启动测试
启动main方法 ,浏览器访问:http://localhost:8080
2.HelloWorld分析
2.1.spring-boot-starter-parent
SpringBoot的父工程,通过dependencyManagement标签帮我们管理了很多的基础jar包,我们如果要使用SpringBoot父工程管理起来的Jar包,需要在子模块的dependencies中导入,版本号不用写交给父模块管理
2.2.spring-boot-starter-web
spring-boot-starter-web:继承与SpringBoot的父工程 spring-boot-starter-parent
这个Jar包在继承web(SpringMvc) ,它把web所需要的的所有的jar到给你导入进来,包括
spring相关包,springmvc相关保,日志相关包,json相关包,tomcat相关包等等都搞进来了。
2.3.RestController
该标签是@Controller和@ResponseBody标签的组合标签,同时拥有两者的能力。
2.4.@EnableAutoConfiguration
开启自动配置,就是SpringBoot帮我们自动配置如:前端控制器,视图解析器,等等。自动配置原理如下:
1.@EnableAutoConfiguration上使用@Import导入了一个AutoConfigurationImportSelector 选择器
这里的导入选择器的作用就是去加载“自动配置”的类,注册到Spring容器中。
//省略....
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
//省略....
2.AutoConfigurationImportSelector的selectImports方法中返回一些自动配置类
的全限定名的数组
selectImports方法返回的数组就是“自动配置”的全限定名的数组,这些配置类最终会注册到Spring容器中,主要跟踪getCandidateConfigurations方法
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
//...省略...
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//...省略...
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
//...省略...
return StringUtils.toStringArray(configurations);
}
3.getCandidateConfigurations方法使用 SpringFactoriesLoader去 META-INF/spring.factories 文件中加载自动配置类
所有classpath中的jar包中的META-INF/spring.factories都会被尝试扫描
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
4.我们去 spring-boot-autoconfigure:2.0.5.RELEASE(这个是SpringBoot的自动配置包) 找到这个文件spring.factories 文件,里面有个很多的自动配置类如下:
#省略....
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
我这里主要截取了我们常用的几个自动配置
- DataSourceAutoConfiguration : 连接池的自动配置
- ThymeleafAutoConfiguration :模板引擎自动配置
- DispatcherServletAutoConfiguration : 前端控制器自动配置
- HttpEncodingAutoConfiguration: 编码过滤器自动配置
- MultipartAutoConfiguration:文件上传自动配置
- WebMvcAutoConfiguration : SpringMvc自动配置,如视图解析器
5.我们打开DispatcherServletAutoConfiguration 看一下前端控制器是如何配置的
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
@EnableConfigurationProperties(ServerProperties.class)
public class DispatcherServletAutoConfiguration {
//省略很多代码......
@Configuration
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
protected static class DispatcherServletConfiguration {
private final WebMvcProperties webMvcProperties;
//省略很多代码......
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(
this.webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(
this.webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(
this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
return dispatcherServlet;
}
这里看起来比较繁杂,我们调关键信息就可以了,这里可以看到,DispatcherServletAutoConfiguration 载入了一个WebMvcProperties ,其实这个对象就是用来从yml配置中读取DispatcherServlet的自定义配置项的,然后以WebMvcProperties 配置为基础,以Bean的方式配置了 DispatcherServlet。也就是说以前在web.xml中配置的前段控制器:org.springframework.web.servlet.DispatcherServlet ,现在在SpringBoot中的配置方式是一个Bean.
其他的自动配置类和以上类似:
编码过滤器:...HttpEncodingAutoConfiguration#characterEncodingFilter()
文件上传解析器:...MultipartAutoConfiguration#multipartResolver()
视图解析器:..WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#defaultViewResolver()
2.5.SpringApplication.run
这个run方法在启动SpringBoot应用,大概的启动流程:
1.加载,启动监听器
2.准备环境,参数等
3.打印Banner
4.创建容器 , 初始化容器
5.刷新容器 (前,刷新,后):注册Bean,初始化Bean , 加载配置类,解析配置,做自动配置
6.打包项目到内嵌Tomcat中
7.启动Tomcat
2.6.为什么项目打包方式是jar
SpringBoot的项目,默认的打包方式就是jar
打包方式 pom/jar/war
- pom:父工程的打包方式,用来管理依赖的 springboot-demo.pom
- jar:普通的java工程,用来打jar包 , springboot-demo.jar
- war: web工程 ,用来打war包 ,springboot-demo.war
2.7.@SpringBootApplication
@SpringBootApplication : 是一个组合标签,包括了下面三个标签:
- @SpringBootConfiguration :
- @Configuration :Spring的配置标签
- @EnableAutoConfiguration : 开启SpringBoot自动配置标签
- @ComponentScan :IOC组件自动扫描标签
2.8.dependencyManagement
这个标签是用来管理jar的,这个标签只是在声明jar包,子项目是用不了这个标签里面的jar包
如果子项目非得使用父项目的 dependencyManagement 里面的jar,得在子项目导入jar包,版本号不要了写,使用父项目的版本号,这样可以实现版本号的统一管理。
2.9.dependencies
如果在父工程的dependencies里面有jar包 ,那么这些jar包默认会被子项目给继承直接使用。
如何选择:如果所有的子项目都要用到的jar包 ,放到父工程的 dependencies ,如果只是部分子项目用到的jar包,放到 dependencyManagement 里面。
3.SpringBoot的特点
3.1.使用注解配置,无需xml(简单粗暴)
3.2.快速搭建,开发
3.3.简化的maven
3.4.方便的和三方框架集成
3.5.内嵌tomcat,部署简单
3.6.内置健康检查,监控等
3.7.自动配置,让配置更加简单
九.SpringBoot基本使用
1.项目结构
1.1.项目结构说明
.SpringBoot项目结构默认是Java项目结构,打包方式为Jar
src
--main
--java
--resources
--static //静态资源目录
--templates //模板页面目录,如:jsp ,ftl
--application.properties/application.yml //默认配置文件
注意:如果么有使用默认的配置文件名需要在配置类上使用 @PropertySource("classpath:redis.properties")
方式导入配置文件。
1.2.SpringBoot在多模块项目中搭建方式
study-springboot-parent
pom.xml //自己在父项目,继承SpringBoot,用来管理jar包 , 打包方式 pom
- springboot-base //子项目 ,继承自己在父项目,打包方式为 jar
- 其他子项目
2.独立运行
当项目上线时SpringBoot项目需要有独立在运行方式,不能以来IDEA工具运行,这时候就需要打包独立运行。
1.导入打包插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.打包项目
打包命令会把jar打包到target
目录
3.运行项目
java -jar xxx.jar
3.热部署
SpringBoot项目可以使用JRebel作为热部署,当然SpringBoot提供了一个热部署的工具包,导入工具包依赖后,在项目中修改了代码需要编译一下代码,即可以重启的方式实现热部署。
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
2.编译代码
使用 ctrl + F9 编译代码,为了方便也可以吧编译功能配置成 ctrl + s
4.SpringBoot配置
SpringBoot可以使用application.properties作为默认的配置文件,这种传统的配置方式可以使用起来并不是特别美观,SpringBoot另外也提供application.yml的方式来进行配置,YAML以数据为中心,比json、xml等更适合做配置文件,看起来更加美观。
4.1.YML基础语法
- k:(空格)v:表示一对键值对(空格必须有)
- 以空格的缩进来控制层级关系;只要是左对齐的一列数据,都是同一个层级的
- 属性和值也是大小写敏感;
4.2.值的写法
- 普通值:数字,字符串,布尔
#字符串默认不用加上单引号或者双引号;
#"":双引号;不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思
name: "zhangsan \n lisi" #输出;zhangsan 换行 lisi
#'':单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据
name: 'zhangsan \n lisi' #输出;zhangsan \n lisi
- k: v:在下一行来写对象的属性和值的关系;注意缩进
对象还是k: v的方式
friends:
lastName: zhangsan
age: 20
行内写法:
friends: {lastName: zhangsan,age: 18}
- 数组(List、Set)
#用- 值表示数组中的一个元素
pets:
- cat
- dog
- pig
#行内写法
pets: [cat,dog,pig]
4.3.案例:端口配置
使用yml配置服务端口 : 创建 application.yml 配置文件,内容如下:
server:
port: 8080 #端口配置
十.SpringBoot读取配置
把配置文件中的配置项读取到代码中使用是常见的开发方式,那么在SpringBoot中如何实现呢?SpringBoot提供了两种方式:1.@Value标签适合用来读取单个配置 , 2.@ConfigurationProperties标签适合用来将一堆配置绑定配置对象。
1.@Value取单个配置
1.1.配置文件
application:
name: springboot-demo
1.2.绑定配置的对象
@Controller
public class HelloController {
//@Value :从配置文件中取值 SPEL
@Value("${application.name}")
private String applicationName ;
- ${}:Spring表达式 SPEL , 当SpringBoot启动的时候,加载配置文件到Spring环境对象中
- ${application.name} :会去环境对象中匹配名字到 application.name的配置项目
- @Value :会把找到的值,赋值给 applicationName 字段
2@ConfigurationProperties绑定配置到对象
@Value
用来读取单个配置项目比较方便,但是如果配置项目比较多就需要写很多@Value
标签,这时候我们可以使用@ConfigurationProperties(prefix = "前缀")
来实现多个配置项到对象的绑定。
@ConfigurationProperties(prefix = "前缀")
自动的根据前缀从配置中过滤出配置项目,然后根据当前对象的字段名进行同名匹配,自动赋值。
2.1.在类上使用
一种用法:@Component+ @ConfigurationProperties打在类上面 , 这里以员工举例:
- 配置文件
employeeconfig:
id: 1
username: zs
password: "000000"
- .绑定配置到对象
@ConfigurationProperties(prefix = "employeeconfig")
@Component
public class EmployeeConfig {
private Long id;
private String username;
private String password;
...getter,setter...
}
2.2.在Bean的方法上使用
二种用法:@Bean +@ConfigurationProperties打在bean的定义方法上面
- 配置文件
deptconfig:
id: 1
name: "教学部"
num: "110"
- 配置绑定到对象
public class DeptConfig{
private Long id;
private String name;
private String num;
..getter,setter,...
}
//主配置类
@SpringBootApplication
public class ApplicationConfig
{
@Bean
@ConfigurationProperties(prefix = "deptconfig")
public DeptConfig deptConfig(){
return new DeptConfig();
}
...main...
}
2.3.测试
在Controller中注入 对象进行打印即可
十一.多环境配置切换
1.为什么要多环境配置
在生产级别的项目中我们会有多套配置环境 ,如:“开发环境” , “测试环境” , “生产环境” 等等 ,在开发到上线的过程中,环境的切换会导致配置文件内容的频繁修改,如果切换环境所需要修改的配置项目比较的,那么对于开发,或者运维人员来说工作量就太大了,SpringBoot的多环境配置可以轻松的解决此问题。方案是针对不同的环境做不同的配置,做多套配置(多个配置文件),在切换环境的时候只需要切换不同的配置文件即可。SpringBoot提供了两种配置方式:1.单文件配置多套环境, 2.多文件配置多套环境,如下图:
2.单文件配置多环境
2.1.创建配置文件
resource/application.yml
2.2.配置内容
多套配置环境通过 — 进行切分 , 通过使用 spring.profiles.active来激活某一个环境配置 ,通过spring.profiles来指定配置的名字
#主配置
spring:
profiles:
active: test #激活(选择)环境test
---
#开发环境配置
spring:
profiles: dev #指定环境名字dev
server:
port: 9999
---
#测试环境配置
spring:
profiles: test #指定环境名字test
server:
port: 8888
提示:这里有两套配置 ,通过spring.profiles指定配置的名字 , 通过 spring.profiles.acitve指定使用哪一套配置。
3.多文件配置多环境
通过配置文件的名字来识别环境
2.1.开发环境配置
创建配置文件 resources/application-dev.yml
server:
port: 9999
2.2.测试环境配置
创建配置文件 resources/application-test.yml
server:
port: 8888
2.3.主配置文件
创建配置文件 resources/application.yml
spring:
profiles:
active: test
#根据文件名字配置 application-dev.properties
SpringBoot启动的时候会默认加载 application.yml 配置文件 ,通过spring.profiles.active=test
找到 application-test.yml
配置文件,加载其内容。如果要使用application-dev.yml配置文件只需要把spring.profiles.active=test修改为spring.profiles.active=dev即可。
4.外部激活配置
4.1.命令行激活配置 - 推荐
如果项目已经打成jar包,我们要启动需要指定不同的配置环境,可以通过如下命令进行激活:
java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
4.2.虚拟机参数激活配置 - 知道就行
启动器的vm项加入配置参数:
-Dspring.profiles.active=dev
十二.SpringBoot测试
后续的学习过程中,每次都要写controller来访问测试比较麻烦,其他我们可以通过springboot的测试直接测试。就和原来不用启动tomcat一样测试 , 在SpringBoot中提供了@SpringBootTest(classes=配置类)
注解来加载配置类,配合@RunWith(SpringRunner.class)
标签一起完成测试功能。
1.使用SpringBoot测试
1.1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
1.2.编写测试类
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ApplicationConfig.class)//要告诉它在哪儿加载Spring配置类
public class TempTest {
@Test
public void test() throws Exception {
System.out.println("如果能打印说明测试成功...");
}
}
@SpringBootTest(classes = ApplicationConfig.class)
:SpringBoot测试标签,指向配置类的字节码
十三.日志的使用
日志框架的一个非常重要的组件 , 日志可以用来调试程序,跟踪代码执行情况,日志的级别可以区分不同的日志类型,可以将日志输出到控制台,或者文件,方便程序员查看系统的执行状况,和错误信息。并且可以根据日志的级别做不同内容的输出,这些优点是System.out.print做不到的。
1.打印日志
1.1.使用Logger打印日志
//日志打印
@RestController
public class LogDemoController {
//日志打印器
private Logger log = LoggerFactory.getLogger(LogDemoController.class);
@RequestMapping("/log-test")
public void logTest(){
//System.out.println("我是一个日志...");
//日志级别: trace -> debug -> info -> ,warn -> error
if(log.isTraceEnabled()){
log.trace("我是trace日志....");
}
// if(log.isDebugEnabled()){
// log.debug("我是debug日志....");
// }
log.debug("我是debug日志....");
log.info("我是info日志....");
log.warn("我是warn日志....");
log.error("我是error日志....");
}
}
注意:SpringBoot默认开启的日志级别是 “info”
1.2.结合Lombok插件打印日志
- IDEA安装Lombok插件
- 导入Lombok依赖包
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
- 使用@Slf4j打印日志
//日志打印
@RestController
@Slf4j
public class LogDemoController {
//日志打印器
//private Logger log = LoggerFactory.getLogger(LogDemoController.class);
@RequestMapping("/log-test")
public void logTest(){
//System.out.println("我是一个日志...");
//日志级别: trace -> debug -> info -> ,warn -> error
if(log.isTraceEnabled()){
log.trace("我是trace日志....");
}
// if(log.isDebugEnabled()){
// log.debug("我是debug日志....");
// }
log.debug("我是debug日志....");
log.info("我是info日志....");
log.warn("我是warn日志....");
log.error("我是error日志....");
}
}
2.日志的配置
1.1.使用默认配置
logging:
level:
root: info #全局配置日志级别:trace
cn:
chenxin: trace #指定 cn.chenxin包下面的日志级别用 trace
file: log/springboot.log #输出到日志文件
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n" #日志格式
1.2.使用logback-spring.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 定义常量 : 日志格式 -->
<property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n"/>
<!--ConsoleAppender 用于在屏幕上输出日志-->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!--定义控制台输出格式-->
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--打印到文件-->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/springboot.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/springboot-%d{yyyyMMdd}-%i.log.gz</fileNamePattern>
<maxFileSize>1KB</maxFileSize>
<maxHistory>30</maxHistory>
<!--总上限大小-->
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<!--定义控制台输出格式-->
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--root是默认的logger 这里设定输出级别是debug-->
<root level="info">
<!--定义了两个appender,日志会通过往这两个appender里面写-->
<appender-ref ref="stdout"/>
<appender-ref ref="file"/>
</root>
<!--如果没有设置 additivity="false" ,就会导致一条日志在控制台输出两次的情况-->
<!--additivity表示要不要使用rootLogger配置的appender进行输出-->
<logger name="cn.chenxin" level="error" additivity="false">
<appender-ref ref="stdout"/>
<appender-ref ref="file"/>
</logger>
</configuration>
十四.SpringBoot集成WEB
1.模板引擎
1.1.模板引擎的原理
模板引擎可以看做是一种文件(内容)合成技术,我们可以使用某种模板引擎(Freemarker),使用填充数据,对模板进行合并可以输出响应的文件 , 如: model(数据) + ftl (模板文件) = html(合并成html) ,举例(JSP):
模板文件
- /WEB-INF/views/user.jsp
....
欢迎登陆 ${username} <!-- el,jstl表达式-->
....
- controller
...
model.addAttribute("username","王大锤"); //model就是填充的数据
return "user.jsp";
- 视图解析器
视图解析器负责 把 model数据 和 jsp模板文件 进行合并成html (${username} + "王大锤" )
,输出给浏览器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
1.2.常见的模板引擎
JSP、Thymeleaf 3、Velocity 1.7、Freemarker 2.3.23
2.集成Thymeleaf
2.1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2.2.创建模板
创建文件: resources/templates/hello.html
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>成功!</h1>
<!--使用语法th:text 将div里面的文本内容设置为 -->
<div th:text="${msg}">这是显示欢迎信息</div>
</body>
</html>
2.3.编写controller
@Controller
public class HelloController {
@RequestMapping("/index")
public String hello(Model model){
model.addAttribute("msg","后面有人,认真听课" );
return "hello";
}
}
思考?为什么我们没有对Thymeleaf做任何配置就能使用?
2.4.Thymeleaf的自动配置原理
1.Thymeleaf配置
application.yml中可以对Thymeleaf的配置做调整,但是不是必须,建议不要配置,默认的配置足够用。
#spring:
# thymeleaf:
# enabled: true
# cache: false
# encoding: utf-8
# suffix: .html
# prefix:
# servlet:
# content-type: text/html
2.Thymeleaf自动配置原理
- Thymeleaf通过 @ConfigurationProperties把yml中的配置读取到 ThymeleafProperties 对象中
@ConfigurationProperties(prefix = "spring.thymeleaf") //读取spring.thymeleaf配置
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
//默认前缀
private String prefix = DEFAULT_PREFIX;
//默认后缀
private String suffix = DEFAULT_SUFFIX;
private Charset encoding = DEFAULT_ENCODING;
//...省略...
- ThymeleafAutoConfiguration 自动配置类使用 ThymeleafProperties 作为基础配置对Thymeleaf做自动配置,如视图解析器的自动配置如下:
@Configuration
//载入 ThymeleafProperties配置对象
@EnableConfigurationProperties(ThymeleafProperties.class)
@ConditionalOnClass(TemplateMode.class)
@AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class })
public class ThymeleafAutoConfiguration {
//省略...
//配置视图解析器
@Bean
@ConditionalOnMissingBean(name = "thymeleafViewResolver")
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
...
return resolver;
}
//省略...
2.5.Thymeleaf的语法
省略…
2.静态资源
2.1.静态资源目录
resource/static
2.2.webjars
某些js组件已经被打包成jar包,通过maven导入jar包就可以使用。下面以jquery举例: http://www.webjars.org/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t1ICp1kJ-1584465560649)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20200317101752532.png)]
- 导入jquery依赖
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
</dependency>
- 导入jquery的js
<script src="/webjars/jquery/3.4.1/jquery.js"></script>
<!-- 测试 -->
<script>
alert($);
</script>
2.3.默认首页
在resources下放置名字index.html的页面默认为首页如:resources/index.html
2.4.网页图标
在resources下放置名字为favicon.ico的图标如: resources/favicon.ico
3.SpringBoot中的MVC配置
在SpringBoot中提供了 WebMvcConfigurer 接口来针对SpringMvc做自定义的配置,比如针对于拦截器,就可以通过WebMvcConfigurer 接口中的addInterceptors方法的InterceptorRegistry拦截器注册器来注册。
3.1.配置拦截器
- 定义拦截器
//拦截器登录检查
@Component
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
//在controller方法调用前,先执行该方法:preHandle
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
log.info("拦截器执行了,URI:"+requestURI);
return true;
}
}
- 注册拦截器
创建拦截器配之类: config/WebConfig
//针对于web的配置
//WebMvcConfigurer:针对于springmvc配置的接口
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
//注册拦截器的方法 : InterceptorRegistry ,是注册拦截器的
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册具体的拦截器
registry.addInterceptor(loginCheckInterceptor) //new LoginCheckInterceptor()
//拦截器所有的请求
.addPathPatterns("/**")
//排除资源
.excludePathPatterns("/static/**",
"/webjars/**",
"/login",
"/regist",
"/css/**",
"/js/**",
"/html/**",
"/images/**");
}
}
3.2.添加视图控制器
- 视图控制器可以将某个url请求直接定位到某个资源,不用通过controller转发。在WebConfig配置中添加代码:
//针对于web的配置
//WebMvcConfigurer:针对于springmvc配置的接口
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/xx").setViewName("hello2.html");
}
//...省略....
}
当访问/xx 定位到 templates/hello2.html
- 填写模板文件 resources/templates/hello2.html
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="webjars/jquery/3.4.1/jquery.js"></script>
<!--<script>-->
<!--alert($);-->
<!--</script>-->
</head>
<body>
<h1>成功!</h1>
<!--使用语法th:text 将div里面的文本内容设置为 -->
<!--<div >第一个DIV:${msg}</div>-->
<div>这是hello2.html</div>
</body>
</html>
十五.集成MyBatis
MyBatis的集成是集成项目必须要做的工作 , 在集成MyBatis之前需要先集成DataSource,SpringBoot中提供了DataSource自动集成方案,让配置更简单,针对于MyBatis的集成也只需要简单几步配置即可。
1.操作步骤
1.导入依赖
2.配置DataSource
3.完成基本组件创建:domain ,mapper映射器,mapper.xml映射文件,service,table
4.配置MyBatis
5.测试
1.集成DataSource
1.1.导入依赖
这里我们把连接池,mysql驱动,以及MyBatis包都导入进来,连接池选择阿里的Druid
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<!-- mysql 数据库驱动. -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
2.2.手动配置方式 - 不推荐
- 手动配置四个属性
jdbc:
username: root
password: 123456
url: jdbc:mysql:///ssm
driver-class-name: com.mysql.jdbc.Driver
- 配置类中定义DataSource
@Bean
@ConfigurationProperties(prefix = "jdbc")
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
return dataSource ;
}
2.3.自动配置方式 - 推荐
application.yml配置:
#配置 druid 的 dataSource
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql:///crm
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
2.4.DataSource自动配置原理
1.DataSourceProperties
通过 @ConfigurationProperties(prefix = "spring.datasource")
读取yml配置中的DataSource配置项
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
//省略
private Class<? extends DataSource> type;
/**
* Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.
*/
private String driverClassName;
/**
* JDBC URL of the database.
*/
private String url;
/**
* Login username of the database.
*/
private String username;
/**
* Login password of the database.
*/
private String password;
2.DataSourceAutoConfiguration去载入DataSourceProperties
,最终调用 DataSourceConfiguration.Generic.class 对DataSource做自动配置
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class,
DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
//省略...
@Configuration
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {
}
3.最终通过 DataSourceConfiguration.Generic.class 配置DataSource
//省略...
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
}
这里有两个条件,1.在容器中找不到DataSource的Bean ,(我们没有手动配) ,;2.yml中有 spring.datasource.type的配置项,SpringBoot就会帮我们配置DataSource , 在 DataSourceProperties通过反射创建了一个类型为 spring.datasource.type 的值的类型的DataSource,并设置参数四大金刚(四大金刚)
2.集成MyBatis
…省略了基本组件生成代码:domain,mapper,service等等…
2.1.配置Mybatis
application.yml
mybatis:
mapper-locations: classpath:cn/chenxin/mapper/*Mapper.xml
#type-aliases-package: 别名可以不用配置
2.2.配置Mapper接口扫描包
@SpringBootApplication
@MapperScan("mapper接口的包名")
public class ApplicationConfig {
...
}
2.3.使用SpringBoot的Test测试
测试类中注入Service进行测试…省略…
也可以使用Controller直接测
十六.集成事务
在Spring中我们可以使用注解式事务配置,也可以使用xml方式进行事务配置,在SpringBoot同样可以使用这两种方式,只是SpringBoot推荐使用注解进行编程,所以我们这里主要采用注解的方式配置事务。
1.使用注解方式
1.1开启事务管理器
导入了MyBatis的依赖之后,事务管理器就已经存在,我们只需要在配置类开启事务管理即可。
@SpringBootApplication
@MapperScan("cn.chenxin.mapper")
@EnableTransactionManagement
public class ApplicationConfig{
...}
1.2.在service打事务标签
@Transactional赋予service有事务的功能
@Transactional
@Service
public class EmployeeServiceImpl
2.使用xml方式配置 - 了解
1.1.导入AOP的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
1.2.配置事务xml
<!-- 配置事物管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<aop:config>
<aop:pointcut expression="execution(* cn.chenxin.web.controller.service..*.*(..))" id="coreServicePointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="coreServicePointcut"/>
</aop:config>
<!-- aop应用事务管理 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="select*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
1.3.配置类导入xml配置
...
@ImportResource("classpath:applicationContext-service.xml")
public class ApplicationConfig
十七.扩展部分
1.FactoryBean
通过工厂的方式去定义bean
1.1.定义MyBean
class MyBean{}
1.2.定义FactoryBean工厂
public class MyBeanFactoryBean implements FactoryBean<MyBean> {
public MyBean getObject() throws Exception {
return new MyBean();
}
public Class<?> getObjectType() {
return MyBean.class;
}
public boolean isSingleton() {
return true;
}
}
1.3.配置 MyBeanFactoryBean的bean定义
@Configuration
public class ApplicationConfig {
@Bean
public MyBeanFactoryBean myBean(){
return new MyBeanFactoryBean();
}
}
3.测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes ={ ApplicationConfig.class})
public class AnnoTest {
@Autowired
private MyBean myBean;
@Test
public void test(){
System.out.println(myBean);
}
}
2.Bean生命周期
1.Bean+InitMethod+DestoryMethod
通过@Bean标签的InitMethod,DestoryMethod属性指定Bean的生命周期方法
@Bean(InitMethod="" , DestoryMethod="")
2.InitializingBean, DisposableBean
通过InitializingBean, DisposableBean接口做Bean的初始化和销毁
public class MyBean implements InitializingBean, DisposableBean {
public MyBean(){
System.out.println("创建.............");
}
public void destroy() throws Exception {
System.out.println("destroy方法...........");
}
public void afterPropertiesSet() throws Exception {
System.out.println("初始化方法...........");
}
}
3.PostConstruct+PreDestroy
@Component
public class MyBean {
@PostConstruct
public void init(){
System.out.println("init.....");
}
@PreDestroy
public void destory(){
System.out.println("destory.....");
}
}
4.BeanPostProcessor后置处理器
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前.....:"+bean);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后.....:"+bean);
return bean;
}
}
3.PageHelper的使用
1.导入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
2.编写查询语句
<select id="selectPage" resultType="cn.chenxin.web.controller.domain.Employee">
select id,username,realName from t_employee
</select>
注意:用了pagehelper之后 ,查询总条数的sql不用写 , limit 不用写 , 如上:
3.查询的service
@Override
public Page<Employee> selectPage() {
PageHelper.startPage(1,5 );
Page<Employee> page = (Page<Employee>) employeeMapper.selectPage();
return page;
}
PageHelper.startPage(1,5 ):设置当前页和每页条数
Page :是pagehelper自己封装的页面对象,如同我们以前的PageList ,里面有总条数,列表,总页数等等
4.获取结果
Page<Employee> page = employeeService.selectPage();
System.out.println("总条数:"+page.getTotal());
for (Employee employee : page.getResult()) {
System.out.println(employee);
}
itMethod="" , DestoryMethod="")
#### 2.InitializingBean, DisposableBean
通过InitializingBean, DisposableBean接口做Bean的初始化和销毁
```java
public class MyBean implements InitializingBean, DisposableBean {
public MyBean(){
System.out.println("创建.............");
}
public void destroy() throws Exception {
System.out.println("destroy方法...........");
}
public void afterPropertiesSet() throws Exception {
System.out.println("初始化方法...........");
}
}
3.PostConstruct+PreDestroy
@Component
public class MyBean {
@PostConstruct
public void init(){
System.out.println("init.....");
}
@PreDestroy
public void destory(){
System.out.println("destory.....");
}
}
4.BeanPostProcessor后置处理器
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前.....:"+bean);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后.....:"+bean);
return bean;
}
}
3.PageHelper的使用
1.导入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
2.编写查询语句
<select id="selectPage" resultType="cn.chenxin.web.controller.domain.Employee">
select id,username,realName from t_employee
</select>
注意:用了pagehelper之后 ,查询总条数的sql不用写 , limit 不用写 , 如上:
3.查询的service
@Override
public Page<Employee> selectPage() {
PageHelper.startPage(1,5 );
Page<Employee> page = (Page<Employee>) employeeMapper.selectPage();
return page;
}
PageHelper.startPage(1,5 ):设置当前页和每页条数
Page :是pagehelper自己封装的页面对象,如同我们以前的PageList ,里面有总条数,列表,总页数等等
4.获取结果
Page<Employee> page = employeeService.selectPage();
System.out.println("总条数:"+page.getTotal());
for (Employee employee : page.getResult()) {
System.out.println(employee);
}