SpringBoot
课程目标
了解SpringBoot的作用
掌握JavaConfig的使用方式
了解SpringBoot自动配置原理
掌握SpringBoot的基本使用
掌握@Configuration注解的作用
掌握@Bean注解的作用
掌握@ComponentScan注解的作用
掌握@Import和@ImportResource导入资源文件
掌握@SpringBootApplication及其上面的元注解的作用
掌握SpringBoot属性绑定
掌握SpringBoot搭建SSM开发环境
了解日志的作用
1.SpringBoot介绍
参考百度百科: https://baike.baidu.com/item/Spring%20Boot/20249767?fr=aladdin
Spring Boot是由Pivotal团队提供的全新框架, 其设计目的是用来简化新Spring应用的初始搭建以及开发过程。
人们把Spring Boot 称为搭建程序的脚手架
。其最主要作用就是帮我们快速的构建庞大的spring项目,并且尽可能的减少一切xml配置,做到开箱即用,迅速上手,让我们关注与业务而非配置。
该框架非常火,目前新开项目几乎都是基于SpringBoot搭建,非常符合微服务架构要求,企业招聘大多都要求有SpringBoot开发经验,属于面试必问的点。
优缺点
优点:
创建独立运行的Spring应用程序
嵌入的Tomcat,无需部署war文件
简化Maven配置
自动配置Spring
提供生产就绪型功能,如:日志,健康检查和外部配置等
不要求配置 XML
非常容易和第三方框架集成起来
缺点:
版本更新较快,可能出现较大变化
因为约定大于配置,所以经常会出现一些很难解决的问题
2.SpringBoot快速入门
方式1:使用idea创建SpringBoot工程
SpringBoot建议使用官方提供的工具来快速构建项目,网站:https://start.spring.io/ ,IDEA自带该功能,但需要联网使用
注意:官方提供的构建工具默认只能选择固定的版本,有些版本之间的差异非常大,所以如果需要选择某个版本建议项目构建后,自行在pom.xml文件中修改版本,建议学习阶段选择2.1.3版本
勾选web依赖包
提供controller代码
@Controller public class HelloController { @RequestMapping("/hello") @ResponseBody public String hello() { return "Hello Spring Boot"; } }
然后通过main方法启动程序,观察控制台输出内容,最后浏览器中输入http://localhost:8080/hello验证效果
方式2:创建普通Maven工程
添加依赖
<packaging>jarpackaging> <parent> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-parentartifactId> <version>2.1.3.RELEASEversion> parent> <dependencies> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starterartifactId> dependency> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-webartifactId> dependency> dependencies>
程序代码
@Controller public class HelloController { @RequestMapping("/hello") @ResponseBody public String hello() { return "Hello Spring Boot"; } }
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
然后通过main方法启动程序,观察控制台输出内容,最后浏览器中输入http://localhost:8080/hello验证效果
提出疑问
之前的web应用打包是war,为什么现在的打包方式是jar
当前项目继承的spring-boot-starter-parent项目有什么用
导入的依赖spring-boot-starter-web有什么用
占用8080端口的Tomcat9服务器哪来的
@SpringBootApplication注解有什么用
main方法中执行的代码SpringApplication.run(..)有什么用
入门案例分析
父工程坐标
SpringBoot提供了一个名为spring-boot-starter-parent的工程,里面已经对各种常用依赖(并非全部)的版本进行了管理,我们的项目需要以这个项目为父工程,这样我们就不用操心依赖的版本问题了,需要什么依赖,直接引入坐标即可!
<parent> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-parentartifactId> <version>2.1.3.RELEASEversion> parent>
继承是 Maven 中很强大的一种功能,继承可以使得子POM可以获得 parent 中的部分配置(groupId,version,dependencies,build,dependencyManagement等),可以对子pom进行统一的配置和依赖管理。
parent项目中的dependencyManagement里的声明的依赖 , 只具有声明的作用,并不实现引入,因此子项目需要显式的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本
parent项目中的dependencies里声明的依赖会被所有的子项目继承
web启动器
这是SpringBoot提供的web启动器 , 是一个快速集成web模块的工具包 , 包含springmvc,jackson相关的依赖
以及嵌入了Tomcat9服务器,默认端口8080
<dependencies> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-webartifactId> dependency> dependencies>
需要注意的是,我们并没有在这里指定版本信息。因为SpringBoot的父工程已经对版本进行了管理了。
这个时候,我们会发现项目中多出了大量的依赖:
这些都是SpringBoot根据spring-boot-starter-web这个依赖自动引入的,而且所有的版本都已经管理好,不会出现冲突。
傻瓜式配置的工具包
SpringBoot非常优秀的地方在于提供了非常多以spring-boot-starter-* 开头的开箱即用的工具包,常见工具包有以下一些:
spring-boot-starter: 核心的工具包,提供了自动配置,日志和YAML配置支持
spring-boot-starter-aop: 提供了快速集成SpringAOP和AspectJ的工具包
spring-boot-starter-freemarker: 提供了快速集成FreeMarker的工具包
spring-boot-starter-test: 提供了测试SpringBoot应用的工具包
spring-boot-starter-web: 提供了快速集成web模块的工具包,包括基于SpringMVC,Tomcat服务器等
spring-boot-starter-actuator: 提供了生产环境中使用的应用监控工具包
spring-boot-starter-logging: 提供了对日志的工具包,默认使用Logback
打包独立运行
对于SpringBoot项目来说无论是普通应用还是web应用,其打包方式都是jar即可,当然web应用也能打war包,但是需要额外添加许多插件来运行,比较麻烦.
默认的Maven打包方式是不能正常的打包SpringBoot项目的,需要额外的引入打包插件,才能正常的对SpringBoot项目打成jar包,以后只要拿到该jar包就能脱离IDE工具独立运行了
<build> <plugins> <plugin> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-maven-pluginartifactId> plugin> plugins> build>
使用maven的package命令进行打包
使用命令java -jar xxx.jar 运行jar包 ( --server.port=80)
3.JavaConfig
我们通常使用Spring都会使用xml对Spring进行配置,随着功能以及业务逻辑的日益复杂,应用伴随着大量的XML配置文件以及复杂的Bean依赖关系,使用起来很不方便。
在Spring3.0开始,Spring官方就已经开始推荐使用java配置来代替传统的xml配置了,它允许开发者将bean的定义和Spring的配置编写到到Java类中,不过似乎在国内并未推广盛行。当SpringBoot来临,人们才慢慢认识到java配置的优雅,但是,也仍然允许使用经典的XML方式来定义bean和配置spring。
回顾XML方式配置IoC
1. 定义两个Bean
@Setter@Getter public class SomeBean { private OtherBean otherBean; public SomeBean() { System.out.println("SomeBean被创建"); } public void init() { System.out.println("SomeBean被初始化"); } public void destroy() { System.out.println("SomeBean被销毁"); } }
public class OtherBean { public OtherBean() { System.out.println("OtherBean被创建"); }}
2. 在XML配置文件中去配置该Bean交给Spring管理
<bean id="someBean" class="cn.wolfcode.common.SomeBean" />
3. 启动Spring读取该XML文件创建容器对象,从容器中获取SomeBean对象
public class App { @Test public void testXmlConfig() { //1:读取XML配置文件,创建Spring容器 ApplicationContext ctx = new ClassPathXmlApplicationContexnt("applicationContext.xml"); //2:从容器中取出SomeBean对象 SomeBean someBean = ctx.getBean(SomeBean.class); System.out.println(someBean); }}
JavaConfig方式配置IoC
JavaConfig方式中使用注解彻底的替代XML文件,那么到底要怎么告诉Spring容器,Bean没有定义在XML文件中,而是定义在一个Java配置类中
@Configuration: 在类上贴该注解表示该类是Spring的配置类, 具有applicationContext.xml文件的作用
@Bean: 在Spring的配置类的方法上贴该注解后, 该方法返回的对象会交给Spring容器管理,替代applicationContext.xml中的bean标签
@ComponentScan: 在Spring配置类上贴该注解表示开启组件扫描器,默认扫描当前配置类所在的包,也可以自己指定,替代xml配置中的标签
AnnotationConfigApplicationContext: 该类是ApplicationContext接口的实现类,该对象是基于JavaConfig的方式来运作的Spring容器
定义一个配置类,替代之前的XML文件,类中定义方法,返回bean对象交给Spring管理
/** * @Configuration * 贴有该注解的类表示Spring的配置类 * 用于替代传统的applicationContext.xml */@Configurationpublic class JavaConfig { /** * @Bean * 该注解贴在配置类的方法上,该方法会被Spring容器自动调用 * 并且返回的对象交给Spring管理 * 相当于 */ @Bean public SomeBean someBean() { return new SomeBean(); }}
加载配置类,启动AnnotationConfigApplicationContext容器对象,测试效果
public class App { @Test public void testJavaConfig() { //1:加载配置类,创建Spring容器 ApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class); //2:从容器中取出SomeBean对象 SomeBean someBean = ctx.getBean(SomeBean.class); System.out.println(someBean); }}
@Bean注解中的属性
在xml配置bean的方式中,我们可以在bean标签中的id,name,init-method,destroy-method,scope等属性来完成对应的配置,在使用JavaConfig方式中我们也一样能通过相应的配置来完成同样的效果,这些效果大多封装到@Bean注解的属性中
@Bean注解中的属性
name: 对应bean标签中的name属性,用于给bean取别名
initMethod: 对应bean标签中的init-method属性,配置bean的初始化方法
destroyMethod: 对应bean标签中的destroy-method属性,配置bean的销毁方法
注意: 在配置类的方式中有许多的默认规定,比如:
bean的id就是当前方法名
配置多例则是在方法上添加@Scope("prototype")注解来实现,一般不用配,默认单例即可
以上案例中,在配置类内部去定义方法返回bean对象交给Spring管理的方式存在一个问题,就是如果需要创建的Bean很多的话,那么就需要定义很多的方法,显示类比较累赘,使用起来不方便,在XML配置的方式中可以通过配置组件扫描器的方式来减少bean标签的定义,那么在JavaConfig的方式中也可以通过添加组件扫描器的方式来减少方法的定义
@Component@Setter@Getterpublic class SomeBean { }
@Configuration //表示该类是Spring的配置类@ComponentScan //开启组件扫描器,默认扫描当前类所在的包,及其子包public class JavaConfig { }
如果需要扫描的包不是配置类所在的包时,我们可以通过注解中的value属性来修改扫描的包
注意:组件扫描的方式只能扫描我们自己写的组件,如果某个bean不是我们写的,则还是要通过在配置类中定义方法来处理,两者是可以同时存在的
SpringTest方式加载配置类
传统XML方式
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:xml文件路径")public class App { ... }
配置类方式
@ContextConfiguration注解不仅支持XML方式启动Spring测试,也支持配置类的方式,配置classes属性来指定哪些类是配置类即可
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes={配置类1.class, 配置类2.class, ...})public class App { ... }
或
@SpringBootTest@RunWith(SpringRunner.class)public class App { ... }
SpringBoot自动配置原理
使用SpringBoot之后,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这是如何做到的?
一切魔力的开始,都是从我们的main函数来的,所以我们再次来看下启动类:
@SpringBootApplicationpublic class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}
我们发现特别的地方有两个:
注解:@SpringBootApplication
run方法:SpringApplication.run()
我们分别来研究这两个部分。
了解@SpringBootApplication
点击进入,查看源码:
这里重点的注解有3个:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
@SpringBootConfiguration
通过这段我们可以看出,在这个注解上面,又有一个@Configuration
注解。通过上面的注释阅读我们知道:这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration
的类,并且读取其中的配置信息。而@SpringBootConfiguration
是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。
@ComponentScan
我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。因此,一般启动类会放在一个比较前的包目录中。
@EnableAutoConfiguration
@EnableAutoConfiguration
的作用,告诉SpringBoot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了spring-boot-starter-web
,而这个启动器中帮我们添加了tomcat
、SpringMVC
的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!
SpringBoot内部对大量的第三方库或Spring内部库进行了默认配置,这些配置是否生效,取决于我们是否引入了对应库所需的依赖,如果有那么默认配置就会生效。
那么
这些默认配置是在哪里定义的呢?
为何依赖引入就会触发配置呢?
其实在我们的项目中,已经引入了一个依赖:spring-boot-autoconfigure,其中定义了大量自动配置类
我们来看一个我们熟悉的,例如SpringMVC,查看mvc 的自动配置类:
打开WebMvcAutoConfiguration:
我们看到这个类上的4个注解:
@Configuration
:声明这个类是一个配置类
@ConditionalOnWebApplication(type = Type.SERVLET)
ConditionalOn,翻译就是在某个条件下,此处就是满足项目的类是是Type.SERVLET类型,也就是一个普通web工程,显然我们就是
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
这里的条件是OnClass,也就是满足以下类存在:Servlet、DispatcherServlet、WebMvcConfigurer。这里就是判断你是否引入了SpringMVC相关依赖,引入依赖后该条件成立,当前类的配置才会生效!
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
这个条件与上面不同,OnMissingBean,是说环境中没有指定的Bean这个才生效。其实这就是自定义配置的入口,也就是说,如果我们自己配置了一个WebMVCConfigurationSupport的类,那么这个默认配置就会失效!
接着,我们查看WebMvcAutoConfiguration该类中定义了什么:
视图解析器:
还有默认支持put请求的过滤器.
总结:
@SpringBootApplication注解内部是3大注解功能的集成
@ComponentScan: 开启组件扫描
@SpringBootConfiguration: 作用等同于@Configuration注解,也是用于标记配置类
@EnableAutoConfiguration: 内部导入AutoConfigurationImportSelector,该类中有个getCandidateConfigurations方法,加载jar包中META-INF/spring.factories文件中配置的配置对象,自动配置定义的功能,包括: AOP / PropertyPlaceholder / FreeMarker / HttpMessageConverter / Jackson / DataSource / DataSourceTransactionManager / DispatcherServlet / WebMvc 等等
SpringApplication.run(..)的作用
启动SpringBoot应用
加载自定义的配置类,完成自动配置功能
把当前项目配置到嵌入的Tomcat服务器
启动嵌入的Tomcat服务器
JavaConfig方式配置DI
传统XML方式
"someBean" <property name="otherBean" ref="otherBean"/>bean>"otherBean"
配置类方式
在配置类方式中我们有两种方式可以完成依赖注入,无论是哪种方式,前提都是要先把Bean交给Spring管理,然后在把Bean注入过去后再使用setter方法设置关系
通用步骤:先把两个Bean交给Spring管理
@Beanpublic SomeBean someBean() { SomeBean someBean = new SomeBean(); return someBean;}
@Beanpublic OtherBean otherBean() { return new OtherBean();}
把需要注入的Bean对象作为参数传入到另一个Bean的方法声明中,形参名称最好跟Bean的id一致
//在声明SomeBean的方法形参中直接注入OtherBean对象@Beanpublic SomeBean someBean(OtherBean otherBean) { SomeBean someBean = new SomeBean(); someBean.setOtherBean(otherBean); return someBean;}
配置文件的导入
@Import注解导入配置类
在Spring项目中一般都会有多个Spring的配置文件,分别配置不同的组件,最后关联到主配置文件中,该功能也是同样可以在配置类的方式中使用的
传统XML方式
<import resource="classpath:applicationContext.xml"/>
配置类方式
//主配置类@Configuration@Import(OtherConfig.class) //在主配置类中关联分支配置类public class MainConfig { ... }//分支配置类@Configurationpublic class OtherConfig { ... }//测试@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(MainConfig.class) //加载主配置类public class App { ... }
@ImportResource注解导入XML配置(了解)
//主配置类@Configuration@ImportResource("classpath:applicationContext.xml") //在主配置类中关联XML配置public class MainConfig { ... }//测试@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=MainConfig.class) //加载主配置类public class App { ... }
@PropertySource注解导入外部属性文件
传统XML方式
<context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" />bean>
配置类方式
方式1:使用@PropertySource + @Value
<dependency> <groupId>com.alibabagroupId> <artifactId>druidartifactId> <version>1.1.10version>dependency><dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <scope>runtimescope>dependency>
/** * @PropertySource:把属性配置加载到Spring的环境对象中 * @Value:从Spring环境对象中根据key读取value */@Configuration@PropertySource("classpath:db.properties")public class JavaConfig { @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean(initMethod="init", destroyMethod="close") public DruidDataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; }}
XML配置中的标签在被扫到时,是会额外的去创建解析器去专门解析context开头的标签,该解析器是ContextNamespaceHandler,该解析器的内部又分别注册了各种不同功能的解析器,如: property-placeholder / component-scan / annotation-config 等等
方式2:直接在配置类中注入Spring的环境对象
@Configuration@PropertySource("classpath:db.properties")public class JavaConfig { /** * environment:表示Spring的环境对象,该对象包含了加载的属性数据 */ @Autowired private Environment environment; @Bean(initMethod="init", destroyMethod="close") public DruidDataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(environment.getProperty("jdbc.url")); dataSource.setUsername(environment.getProperty("jdbc.username")); dataSource.setPassword(environment.getProperty("jdbc.password")); return dataSource; }}
4.SpringBoot参数配置
参数来源
命令行启动项目时传入的参数, 如: java -jar xxx.jar --server.port=80
application.properties或者YAML文件
一般用的比较多的就是直接在application.properties或者YAML配置 , 其次是命令行启动方式
application.properties语法
server.port=80server.session-timeout=30server.tomcat.uri-encoding=UTF-8 spring.datasource.url = jdbc:mysql://localhost:3306/crmspring.datasource.username = rootspring.datasource.password = mymysqlspring.datasource.driverClassName = com.mysql.jdbc.Driver
vs
application.yml语法
server: port: 80 session-timeout: 30 tomcat.uri-encoding: UTF-8 spring: datasource: url : jdbc:mysql://localhost:3306/crm username : root password : mymysql driverClassName : com.mysql.jdbc.Driver
application.properties优先级
一个项目中可以有多个application.properties文件存放在不同目录中,此时他们会遵循固定的优先级来处理有冲突的属性配置, 优先级由高到底,高优先级的配置会覆盖低优先级的配置
项目/config/application.properties
项目/application.properties
classpath:config/application.properties
classpath:application.properties
一般都在classpath:application.properties做配置,其他方式不使用
5.SpringBoot实战
现在我们来把crm改造为springboot项目, 课件中提供了无shiro版的crm代码, 我们上课先用这个来改造,因为springboot要与shiro集成, 还需要有其他的配置, 现在上课先不弄shiro有关的
迁移CRM项目
1.快速创建SpringBoot项目
2.添加依赖(如果是普通maven项目,需要手动添加)
<packaging>jarpackaging><parent> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-parentartifactId> <version>2.1.3.RELEASEversion>parent><dependencies> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starterartifactId> dependency>dependencies>
3.添加启动类(如果是普通maven项目,需要手动添加)
@SpringBootApplicationpublic class CrmApplication { public static void main(String[] args) { SpringApplication.run(CrmApplication.class, args); }}
4.拷贝crm代码
把crm中的src\main\java 中的java代码全部拷贝到新项目中的src\main\java里面
把src\main\resources中存放mapper.xml的目录也拷贝到新项目中的src\main\resources里面
5.添加PageHelper分页插件依赖
<dependency> <groupId>com.github.pagehelpergroupId> <artifactId>pagehelper-spring-boot-starterartifactId> <version>1.2.13version>dependency>
6.其他依赖
<dependency> <groupId>org.projectlombokgroupId> <artifactId>lombokartifactId>dependency><dependency> <groupId>com.alibabagroupId> <artifactId>fastjsonartifactId> <version>1.2.47version>dependency> <dependency> <groupId>org.apache.poigroupId> <artifactId>poiartifactId> <version>4.1.2version>dependency>
准备好测试类
此处使用springboot的测试注解,这种方式会自动去读取配置类和配置文件application.properties
@SpringBootTest@RunWith(SpringRunner.class)public class DepartmentServiceTest { @Autowired private IDepartmentService departmentService; @Test public void testList(){ List departments = departmentService.listAll(); System.out.println(departments); }}
此时运行测试类发现找不到mapper相关的bean, 需要先集成mybatis
集成MyBatis
准备依赖
<dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId>dependency><dependency> <groupId>org.mybatis.spring.bootgroupId> <artifactId>mybatis-spring-boot-starterartifactId> <version>1.3.1version>dependency>
Mapper接口扫描器只要在配置类上贴个注解@MapperScan(...)即可
@SpringBootApplication@MapperScan("cn.wolfcode.crm.mapper")public class SpringbootCrmApplication { public static void main(String[] args) { SpringApplication.run(SpringbootCrmApplication.class, args); }}
配置属性
application.properties
以前在XML配置了哪些mybatis的属性在这里就配置哪些属性,属性前缀mybatis
mybatis.configuration.lazy-loading-enabled=truemybatis.configuration.lazy-load-trigger-methods=clonemybatis.mapper-locations=classpath:cn/wolfcode/crm/mapper/*Mapper.xmlmybatis.type-aliases-package=cn.wolfcode.crm.domain#打印SQL日志logging.level.cn.wolfcode.crm.mapper=trace
此时运行测试类出现了问题 , 无法配置连接池 , 未指定“url”属性,无法配置嵌入的datasource。
数据库连接池
自动配置方式
application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql:///crm?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8spring.datasource.username=rootspring.datasource.password=admin
此时运行测试类发现可以执行成功 , 并且我们看到了使用的连接池是Hikari , 全称是Hikaricp
其实 , 在springboot2.0之后 , 采用的默认连接池就是Hikari, 号称"史上最快的连接池", 所以我们没有添加依赖也能直接用, springboot的自动配置中含有DataSourceAutoConfiguration配置类, 会先检查容器中是否已经有连接池对象, 没有则会使用默认的连接池, 并根据特定的属性来自动配置连接池对象, 用到的属性值来源于DataSourceProperties对象
Druid集成
当然如果我们在项目中还是想要使用Druid作为连接池也是可以的
只需要添加依赖即可, 此时加的是Druid的springboot自动配置包, 里面包含了DruidDataSourceAutoConfigure自动配置类,会自动创建druid的连接池对象, 所以springboot发现已经有连接池对象了,则不会再使用Hikari
<dependency> <groupId>com.alibabagroupId> <artifactId>druid-spring-boot-starterartifactId> <version>1.1.21version>dependency>
注意 : 如果添加的依赖是以前那种普通包, 只有Druid自身的依赖, 并不是自动配置包, 则需要以下配置
<dependency> <groupId>com.alibabagroupId> <artifactId>druidartifactId> <version>1.1.19version>dependency>
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
所以一般如果已经提供了springboot相关的自动配置包 , 直接使用自动配置的会更方便些.
对于Hikari以及Druid两款都是开源产品,阿里的Druid有中文的开源社区,交流起来更加方便,并且经过阿里多个系统的实验,想必也是非常的稳定,而Hikari是SpringBoot2.0默认的连接池,全世界使用范围也非常广,对于大部分业务来说,使用哪一款都是差不多的,毕竟性能瓶颈一般都不在连接池。
事务管理
准备依赖
<dependency> <groupId>org.aspectjgroupId> <artifactId>aspectjweaverartifactId>dependency>
XML方式(了解)
采取配置类和XML混用的策略, 在配置类上使用@ImportResource("classpath:spring-tx.xml")
注解方式
直接在业务层实现类上或者其方法上直接贴@Transactional注解即可
#SpringBoot默认优先选择CGLIB代理,如果需要改为优先使用JDK代理,需要做以下配置spring.aop.proxy-target-class=false #优先使用JDK代理
SpringBoot 自动配置中提供了TransactionAutoConfiguration事务注解自动配置类 , 引入了事务的依赖后, 可直接使用@Transactional注解
在测试类上添加方法, 在service层可插入运行时异常的代码进行测试
@Testpublic void testSave(){ Department department = new Department(); department.setName("测试"); departmentService.save(department);}
WEB集成
添加依赖
<dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-webartifactId>dependency>
修改端口 application.properties
server.port=80
目录结构
因为打包方式是jar,不是war,里面没有webapp文件了,拿webapp中的资源文件存放位置按规定的方式存在指定的文件中。
拷贝静态资源及模板文件
静态资源处理
默认情况下,Springboot会从classpath下的 /static , /public , /resources , /META-INF/resources下加载静态资源
可以在application.properties中配置spring.resources.staticLocations属性来修改静态资源加载地址
因为应用是打成jar包,所以之前的src/main/webapp就作废了,如果有文件上传,那么就的必须去配置图片所在的路径
路径映射配置(了解)
在springboot自动配置中, WebMvcAutoConfiguration自动配置类导入了DispatcherServletAutoConfiguration配置对象 , 会自动创建DispatcherServlet前端控制器 , 默认的< url-pattern >是 / , SpringBoot多数用于前后端分离和微服务开发,默认支持RESTFul规范,所以一般都是使用默认匹配 / ,不做改动
但是 , 因为我们crm项目是用的*.do的 ,为了能正常使用 , 我们需要修改 application.properties配置
#在匹配模式时是否使用后缀模式匹配spring.mvc.pathmatch.use-suffix-pattern=true
第二种方式:
SpringBoot提供了WebMvcConfigurer配置接口 , 是使用JavaConfig配置SpringMVC的标准,如果我们需要对SpringMVC做配置,则需要让我们的配置类实现该接口
自定义一个配置类
@Configurationpublic class MvcJavaConfig implements WebMvcConfigurer { public void configurePathMatch(PathMatchConfigurer configurer) { //开启后缀匹配模式 configurer.setUseRegisteredSuffixPatternMatch(true); }}
集成FreeMarker
在传统的SpringMVC中集成FreeMarker需要把FreeMarkerConfigurer和FreeMarkerViewResolve两个对象配置到Spring容器中,同时两个对象都要分别配置一些属性,还是比较麻烦的
在SpringBoot中,依靠自动配置功能,我们可以非常轻松的实现集成FreeMarker,只需要引入一个依赖即可
<dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-freemarkerartifactId>dependency>
集成原理
SpringBoot的自动配置中含有FreeMarkerAutoConfiguration配置对象,该配置对象又导入了FreeMarkerReactiveWebConfiguration配置对象,在里面创建了FreeMarkerConfigurer和FreeMarkerViewResolve两个对象交给Spring管理,并且设置了默认的属性值,这些属性值来源于FreeMarkerProperties对象
常见属性配置
spring.freemarker.enabled=true: 是否开启freemarker支持
spring.freemarker.allow-request-override: 是否允许request中的属性覆盖model中同名属性,默认false
spring.freemarker.allow-session-override: 是否允许session中的属性覆盖model中同名属性,默认false
spring.freemarker.cache: 是否支持模板缓存,默认false
spring.freemarker.charset=UTF-8: 模板编码
spring.freemarker.content-type=text/html: 模板contenttype
spring.freemarker.expose-request-attributes: 是否开启request属性暴露,默认false
spring.freemarker.expose-session-attributes: 是否开启session属性暴露,默认false
spring.freemarker.expose-spring-macro-helpers: 是否开启spring的freemarker宏支持,默认为false
spring.freemarker.prefer-file-system-access: 默认为true,支持实时检查模板修改
spring.freemarker.prefix: 加载模板时候的前缀
spring.freemarker.settings.*: 直接配置freemarker参数
spring.freemarker.suffix: 模板文件后缀
spring.freemarker.template-loader-path=classpath:/templates/: 模板加载地址
#一般我们会做1个配置,其余默认即可#暴露session对象的属性spring.freemarker.expose-session-attributes=true
统一异常处理
框架自带方式
SpringBoot默认情况下,会把所有错误都交给BasicErrorController类完成处理,错误的视图导向到 classpath:/static/error/ 和 classpath:/templates/error/ 路径上,http状态码就是默认视图的名称
如: 出现404错误 -> classpath:/static/error/404.html 或者 出现5xx类错误 -> classpath:/static/error/5xx.html
控制器增强器方式
自己定义一个控制器增强器,专门用于统一异常处理,该方式一般用于5xx类错误
@ControllerAdvice //控制器增强器public class ExceptionControllerAdvice { @ExceptionHandler(Exception.class) //处理什么类型的异常 public String handlException(Exception e, Model model) { model.addAttribute("msg", e.getMessage()); return "errorView"; //逻辑视图名称 }}
添加拦截器
在传统的XML方式中,我们需要在< mvc:interceptors >标签中去注册我们自定义的拦截器,在SpringBoot,只需要让我们的配置对象去实现WebMvcConfigurer接口,实现接口中addInterceptors方法即可
让spring管理拦截器bean对象 , 在拦截器类上贴@Component注解
@Componentpublic class LoginInterceptor implements HandlerInterceptor { }
@Componentpublic class PermissionInterceptor implements HandlerInterceptor { }
声明一个配置类, 实现WebMvcConfigurer接口 ,在addInterceptors方法注册拦截器
@Configurationpublic class MvcJavaConfig implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Autowired private PermissionInterceptor permissionInterceptor; public void addInterceptors(InterceptorRegistry registry) { //注册登录拦截器 registry.addInterceptor(loginInterceptor) //传入拦截器对象 .addPathPatterns("/**") //拦截规则 //注意:静态资源也要排除一下,因为Springboot把静态资源也拦截了 .excludePathPatterns("/loginUser.do", "/login.html", "/css/**", "/js/**"); //排除的资源 //注册权限拦截器 registry.addInterceptor(permissionInterceptor) //传入拦截器对象 .addPathPatterns("/**") //拦截规则 //注意:静态资源也要排除一下,因为Springboot把静态资源也拦截了 .excludePathPatterns("/loginUser.do", "/login.html", "/css/**", "/js/**"); //排除的资源 }}
6.系统日志
为什么要用日志?
比起System.out.println,日志框架更为灵活,可以把日志的输出和代码分离
日志框架可以方便的定义日志的输出环境,控制台,文件,数据库
日志框架可以方便的定义日志的输出格式和输出级别
SpringBoot中的日志介绍
Springboot默认已经开启日志
默认的日志格式为: 时间 日志级别 线程ID 线程名称 日志类 日志说明
Springboot的日志分为: 系统日志和应用日志
日志级别,级别越高,输出的内容越少, 如果设置的级别为info, 则debug以及trace级别的都无法显示trace < debug < info < warn < error
Springboot默认选择Logback作为日志框架,也能选择其他日志框架,但是没有必要
common-logging / java-logging / log4j / log4j2 / logback / slf4j
类中使用日志输出
在我们自定义的类中如果要使用日志框架来输出
方式1: 在类中定义一个静态Logger对象
这里传入当前类的作用是方便输出日志时可以清晰地看到该日志信息是属于哪个类的
//静态日志对象private static final Logger log = LoggerFactory.getLogger(当前类.class);
效果:
方式2: 使用lombok提供的@Slf4j注解来简化代码 , 其实和方式1的作用是一样的
@Slf4j@Servicepublic class PermissionServiceImpl implements IPermissionService {}
使用lombok可以使用注解:@slf4j注解简化了静态日志对象的引入代码,之后直接可以在需要的地方打印日志即可。
在需要输出日志的地方使用日志的输出方法
log.info(...);log.error(...);...//输出日志中有变量可以使用{}作为占位符log.info("删除id为{}的数据", id);
我们来尝试一下日志功能, 写到之前的权限加载功能内
//如果该权限的表达式已经存在数据库,就不进行插入,如果不存在就插入if(!allExpression.contains(expression)){ Permission permission = new Permission(); permission.setName(annotation.name()); permission.setExpression(expression); permissionMapper.insert(permission); log.debug("权限插入成功:{}",expression); log.info("权限插入成功:{}",expression); log.warn("权限插入成功:{}",expression);}
执行权限加载功能后,发现控制台出现info与warn的信息, debug的没有显示,原因是因为springboot默认的日志级别是info,所以debug低于info级别,就不会显示出来了
如果要修改日志级别,最快速的方式是在application.properties配置
#把日志级别修改为debug,不过我们一般不会更改,除非要调试找bug,不然控制台显示的内容太多也容易乱logging.level.root=debug
Logback配置文件的使用
Logback框架默认会自动加载classpath:logback.xml,作为框架的配置文件,在SpringBoot中使用时,还会额外的支持自动加载classpath:logback-spring.xml,在SpringBoot中推荐使用logback-spring.xml,功能更强大些
样板文件:
<?xml version="1.0" encoding="UTF-8"?><configuration scan="true" scanPeriod="60 second" debug="false"> <property name="appName" value="springboot demo" /> <contextName>${appName}contextName> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd-HH:mm:ss} %level [%thread]-%logger{35} >> %msg %npattern> encoder> appender> <root level="info"> <appender-ref ref="STDOUT" /> root> configuration>
参考日志格式:
%d{yyyy-MM-dd-HH:mm:ss} %level [%thread]-%class:%line >> %msg %n
格式中的标识符组成:
%logger{n}: 输出Logger对象类名,n代表长度
%class{n}: 输出所在类名,
%d{pattern}或者date{pattern}: 输出日志日期,格式同java
%L/line: 日志所在行号
%m/msg: 日志内容
%method: 所在方法名称
%p/level: 日志级别
%thread: 所在线程名称
7.其他功能
切换运行环境(了解)
在实际开发中,一个系统是有多套运行环境的,如开发时有开发的环境,测试时有测试的环境,不同的环境中,系统的参数设置是不同的,如:连接开发数据和测试数据库的URL绝对是不同的,那么怎么快速的切换系统运行的环境
我们需要为不同的环境创建不同的配置文件,在不同的配置文件中有各自不同阶段的配置,在使用时在application.properties文件中指定要使用哪一个配置文件即可。
application-dev.properties
server.port=8081
application-test.properties
server.port=8082
在application.properties中指定需要使用的环境即可
#指定使用的环境是devspring.profiles.active=dev
热部署插件(了解)
除了使用JRebel来实现热部署,还可以使用Springboot提供的spring-boot-devtools包来完成Springboot应用热部署
<dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-devtoolsartifactId>dependency>
SpringBoot重启是reload重启,通过监控classpath的变化,如果classpath中的文件发生变化,即触发重启.springboot通过两个classpath来完成reload,一个basic classloader中加载不变的类(jar包中的类),一个restart classloader中加载classpath中的类(自己写的类),重启的时候,restart classloader中的类丢弃并重新加载,也就是说其实这个插件很...
排除资源
#默认排除的资源spring.devtools.restart.exclude=static/**,templates/**,public/**#增加额外的排除资源spring.devtools.restart.additional-exclude=public/** #处理默认配置排除之外的spring.devtools.restart.enabled=false #禁用自动重启
修改banner(了解)
SpringBoot提供了一些扩展点,比如修改banner:在resources根目录中存入banner.txt文件,替换默认的banner
#application.propertiesspring.main.banner-mode=off #关闭banner
java学途
只分享有用的Java技术资料
扫描二维码关注公众号
笔记|学习资料|面试笔试题|经验分享
如有任何需求或问题欢迎骚扰。微信号:JL2020aini
或扫描下方二维码添加小编微信
小伙砸,欢迎再看分享给其他小伙伴!共同进步!