SpringBoot笔记
SpringBoot官方文档
一、SpringBoot的常用注解
@ConfigurationProperties、@PropertySource、@ImportResource的区别
1.@ConfigurationProperties:
@ConfigurationProperties:告诉SpringBoot将本类中的所有属性与配置文件中的相关属性进行绑定;
如:@ConfigurationProperties(prefix = "person") 就是将配置文件中前缀为person下边的属性与该注解所在类中的属性进行绑定
2.@PropertySource:
@PropertySource:加载指定的配置文件
如:@PropertySource("classpath:person.properties")
3.@ImportResource:
@ImportResource:导入Spring的配置文件xxx.xml,让配置文件中的内容生效;
如:@ImportResource(location={"classpath:bean.xml"})(作用在启动类上)
4.@Configuration:
@Configuration:指明当前类是一个配置类;用来代替之前的Spring配置文件.xml
二、Profile多环境支持
1.多文件
约定文件名:application-{profile}.properties 使用spring-profiles.active={profile}激活对应的环境
application-dev.properties
application-prod.properties
2.yml多文档块
server:port: 8080
spring:profiles:active: prod
---
server:port: 8081
spring:profiles: dev
---
server:port: 8082
spring:profiles: prod
三、配置文件加载位置
SpringBoot启动会扫描一下位置的application.properties或application.yml文件作为SpringBoot的默认配置文件。
file:./config/
file:./
classpath:/config/
classpath:/
优先级由高到低,高优先级的配置会覆盖低优先级的配置;SpringBoot会从这四个位置全部加载主配置文件,故会形成一个互补配置。
四、外部配置加载顺序
1.命令行参数
如:java -jar xxx.jar --server.port=8087
由jar包外向jar包内
优先加载带profile的
2.jar包外部的application-{profile}.properties或application.ym|(带spring.profile)配置文件
3.jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件
再来加载不带profile的
4.jar包外部的application.properties或application.yml(不带spring.profile)配置文件
5.jar包内部的application.properties或application.yml(不带spring.profile)配置文件
五、自动配置原理(面试必问题)
application.properties配置文件参考
@EnableAutoConfiguration
->@Import({AutoConfigurationImportSelector.class})
->getCandidateConfigurations(annotationMetadata, attributes);
->SpringFactoriesLoader.loadFactoryNames();
->classLoader.getResources(“META-INF/spring.factories”)
①配置原理:
1.SpringBoot启动时加载主配置类,开启了自动配置功能 @EnableAutoConfiguration
2.@EnableAutoConfiguration的作用:
●利用@EnableAutoConfigurationImportSelector给容器中导入一些组件?
●List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置
●SpringFactoriesLoader.loadFactoryNames()扫描所有jar包类路径下 META-INF/spring.factoryies,把扫描到的这些文件的内容包装成properties对象,从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把它们添加在容器中
将类路径下 META-INF/spring.factories里面配置的所有EnableAutoConfiguration的值加入到了容器中;
每一个xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置
3.每一个配置类进行自动配置功能
4.以HttpEncodingAutoConfiguration为例解释自动配置原理:
@Configuration
@EnableConfigurationProperties({ServerProperties.class})//启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把这个类加入到ioc容器中@ConditionalOnWebApplication//Spring底层@Conditional注解,根据不同的条件,如果满足指定的条件,整个配置类中的配置就会生效 判断当前类是不是Web应用,如果是则生效;@ConditionalOnClass({CharacterEncodingFilter.class})//判断当前项目有没有这个类@ConditionalOnProperty(prefix = "server.servlet.encoding",value = {"enabled"},matchIfMissing = true
)//判断配置文件中是否存在某个配置 如:server.servlet.encoding.enable ; 如果不存在,判断也是成立的
public class HttpEncodingAutoConfiguration {private final Encoding properties;////只有一个有参构造方法的情况下,参数的值就会从容器中拿public HttpEncodingAutoConfiguration(ServerProperties properties) {this.properties = properties.getServlet().getEncoding();}@Bean//给容器中添加一个组件,这个组件的某些值需要从properties中获取@ConditionalOnMissingBean//判断容器中没有这个组件才会加入该组件public CharacterEncodingFilter characterEncodingFilter() {CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();filter.setEncoding(this.properties.getCharset().name());filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));return filter;}
一但这个自动配置类生效,这个配置类就会给容器中添加组件,这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
精髓:
1)、SpringBoot启动会加载大量的自动配置类
2)、看我们需要的功能有没有SpringBoot默认写好的自动配置类
3)、我们再来看这个自动配置类中到底配置了那些组件;
4)、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可在配置文件中指定这些属性的值;
xxxAutoConfiguration自动配置类
给容器中添加组件
xxxProperties封装配置文件中相关属性
②细节:
@Conditional派生注解
作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置里面的内容才生效。
@Conditional扩展注解 | 作用(判断是否满足当前指定条件) |
---|---|
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定的Bean |
@ConditionalOnMissingBean | 容器中不存在指定的Bean |
@ConditionalOnExpression | 满足SpEL表达式指定 |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnMissingClass | 系统中没有指定的类 |
@ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定资源文件 |
@ConditionalOnWebApplication | 当前是Web环境 |
@ConditionalOnNotWebApplication | 当前不是Web环境 |
@ConditionalOnJndi | JNDI存在指定项 |
自动配置类必须在一定条件下才能生效
故该怎么知道哪些自动配置类是否生效?
只需在配置文件中开启debug=true 来让控制台打印自动配置报告
六、Spring Boot与日志
1.市面上常用的日志框架:
JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j…
日志门面(日志的抽象层) | 日志实现 |
---|---|
SLF4j(Simple Logging Facade for Java) Jboss-logging | log4j JUL (java.util.logging) log4j2 Logback |
左边选个日志门面、右边选一个来实现;
日志门面:SLF4J;
日志实现:Logback;
SpringBoot:底层是Spring框架,Spring框架默认使用JCL;
SpringBoot选用SLF4j和Logback;
2.SLF4j使用
1> 如何在系统中使用SLF4J
以后开发的时候,日记方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法;
给系统里面导入slf4j的jar和logback的实现;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class HelloWorld {public static void main(String[] args) {Logger logger = LoggerFactory.getLogger(HelloWorld.class);logger.info("Hello World");}
}
每一个日志的实现框架都有自己的配置文件,使用slf4j后,配置文件还是使用日志实现框架自己本身的配置文件
2 >遗留问题
SpringBoot使用的是slf4j+logback,但其他框架本身也可能在使用别的日志框架,如Spring(commons-logging)、Hibernate(jboss-logging)、Mybatis…故需要统一使用slf4j进行输出
3.SpringBoot日志间的关系
如何让系统中的日志都统一到slf4j:
1.将系统的中其他日志框架先排出去
2.用中间包来替换原有的日志框架
3.再导入slf4j其他的实现
总结:
1)、SpringBoot底层也是使用slf4j+logback的方式进行日志记录
2)、SpringBoot把其他的日志都替换成了slf4j
3)、中间替换包(log4j-to-slf4j、jul-to-slf4j)
一句话:SpringBoot能适应所有的日志,而且底层使用slf4j的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的日志框架排除掉。
4.日志使用
1.默认配置
//记录器Logger logger = LoggerFactory.getLogger(getClass());@Testvoid contextLoads() {//日志的级别: trace<debug<info<warn<error 由低到高,低于当前级别的则不显示,默认为info级别,可自定义在配置文件中指定级别logger.trace("这是trace日志");logger.debug("这是debug日志");logger.info("这是info日志");logger.warn("这是warn日志");logger.error("这是error日志");}
2.日志输出格式:
%d表示时间、
%thread表示线程名、
%-5level表示级别从左显示5个字符宽度、
%logger{50}表示logger名字最长50个字符,否则按照句点分割
%msg日志消息、
%n 换行
如:%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -%msg%n
SpringBoot修改日志配置:
#指定级别 (可具体到哪个包)
logging.level.com=trace
#不指定路径则在当前项目下生成日志文件,也可以指定路径
logging.file=
#在当前磁盘的根路径下创建spring文件夹和里面的log文件夹;使用spring.log作为默认文件
logging.file.path=/spring/log
#在控制台输出的日志格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -%msg%n
#指定文件中输出的日志格式
logging.pattern.file=
3.logback.xml配置样例
<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false"><!-- 定义日志的根目录 --><property name="LOG_HOME" value="/app/log" /><!-- 定义日志文件名称 --><property name="appName" value="atguigu-springboot"></property><!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 --><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><!--日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度%logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符--><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></layout></appender><!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --> <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 指定日志文件的名称 --><file>${LOG_HOME}/${appName}.log</file><!--当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 %i:当文件大小超过maxFileSize时,按照i进行文件滚动--><fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern><!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除。--><MaxHistory>365</MaxHistory><!-- 当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy--><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>100MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!-- 日志输出格式: --> <layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern></layout></appender><!-- logger主要用于存放日志对象,也可以定义日志类型、级别name:表示匹配的logger类型前缀,也就是包的前半部分level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERRORadditivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,false:表示只用当前logger的appender-ref,true:表示当前logger的appender-ref和rootLogger的appender-ref都有效--><!-- hibernate logger --><logger name="com.atguigu" level="debug" /><!-- Spring framework logger --><logger name="org.springframework" level="debug" additivity="false"></logger><!-- root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 --><root level="info"><appender-ref ref="stdout" /><appender-ref ref="appLogAppender" /></root>
</configuration>
log4j.properties配置样例
### set log levels ###
log4j.rootLogger = debug , stdout , D , E### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{ 1 }:%L - %m%n#### 输出到日志文件 ###
#log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.D.File = logs/log.log
#log4j.appender.D.Append = true
#log4j.appender.D.Threshold = DEBUG ## 输出DEBUG级别以上的日志
#log4j.appender.D.layout = org.apache.log4j.PatternLayout
#log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
#
#### 保存异常信息到单独文件 ###
#log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.D.File = logs/error.log ## 异常日志文件名
#log4j.appender.D.Append = true
#log4j.appender.D.Threshold = ERROR ## 只输出ERROR级别以上的日志!!!
#log4j.appender.D.layout = org.apache.log4j.PatternLayout
#log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
七.Web开发
1.SpringBoot对静态资源的映射规则
private final ResourceProperties resourceProperties;//设置和静态资源有关的参数,如缓存时间
public void addResourceHandlers(ResourceHandlerRegistry registry) {if (!this.resourceProperties.isAddMappings()) {logger.debug("Default resource handling disabled");} else {Duration cachePeriod = this.resourceProperties.getCache().getPeriod();CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();if (!registry.hasMappingForPattern("/webjars/**")) {this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));}String staticPathPattern = this.mvcProperties.getStaticPathPattern();if (!registry.hasMappingForPattern(staticPathPattern)) {this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));}}}//映射欢迎页
@Beanpublic WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());return welcomePageHandlerMapping;}
1) 所有/webjars/**,都去classpath:/META-INF/resources/webjars/找资源
webjars:以jar包的方式引入静态资源 (即在pom.xml文件中引入资源的依赖https://www.webjars.org/ 或https://mvnrepository.com/ )
2)“/**”:访问当前项目所有资源(静态济源文件夹)
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
"/" :当前项目所有的根路径
3)欢迎页;静态资源文件夹下的所有index.html页面被"/**"映射。
4)所有的**/favicon.ico 都是在静态资源文件下找。
2.模板引擎
SpringBoot推荐Thmeleaf,功能强大,语法简单。
1)引入thymeleaf
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2)Thymeleaf使用&语法
@ConfigurationProperties(prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {private static final Charset DEFAULT_ENCODING;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 = "classpath:/templates/";private String suffix = ".html";...
}
1.表达式:
Simple expressions:(表达式语法)Variable Expressions: ${...}:获取变量值;OGNL;1)、获取对象的属性、调用方法2)、使用内置的基本对象:#ctx : the context object.#vars: the context variables.#locale : the context locale.#request : (only in Web Contexts) the HttpServletRequest object.#response : (only in Web Contexts) the HttpServletResponse object.#session : (only in Web Contexts) the HttpSession object.#servletContext : (only in Web Contexts) the ServletContext object.${session.foo}3)、内置的一些工具对象:
#execInfo : information about the template being processed.
#messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax.
#uris : methods for escaping parts of URLs/URIs
#conversions : methods for executing the configured conversion service (if any).
#dates : methods for java.util.Date objects: formatting, component extraction, etc.
#calendars : analogous to #dates , but for java.util.Calendar objects.
#numbers : methods for formatting numeric objects.
#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
#objects : methods for objects in general.
#bools : methods for boolean evaluation.
#arrays : methods for arrays.
#lists : methods for lists.
#sets : methods for sets.
#maps : methods for maps.
#aggregates : methods for creating aggregates on arrays or collections.
#ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样;补充:配合 th:object="${session.user}:<div th:object="${session.user}"><p>Name: <span th:text="*{firstName}">Sebastian</span>.</p><p>Surname: <span th:text="*{lastName}">Pepper</span>.</p><p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p></div>Message Expressions: #{...}:获取国际化内容Link URL Expressions: @{...}:定义URL;@{/order/process(execId=${execId},execType='FAST')}Fragment Expressions: ~{...}:片段引用表达式<div th:insert="~{commons :: main}">...</div>Literals(字面量)Text literals: 'one text' , 'Another one!' ,…Number literals: 0 , 34 , 3.0 , 12.3 ,…Boolean literals: true , falseNull literal: nullLiteral tokens: one , sometext , main ,…
Text operations:(文本操作)String concatenation: +Literal substitutions: |The name is ${name}|
Arithmetic operations:(数学运算)Binary operators: + , - , * , / , %Minus sign (unary operator): -
Boolean operations:(布尔运算)Binary operators: and , orBoolean negation (unary operator): ! , not
Comparisons and equality:(比较运算)Comparators: > , < , >= , <= ( gt , lt , ge , le )Equality operators: == , != ( eq , ne )
Conditional operators:条件运算(三元运算符)If-then: (if) ? (then)If-then-else: (if) ? (then) : (else)Default: (value) ?: (defaultvalue)
Special tokens:No-Operation: _
3.SpringMVC自动配置原理
Spring Boot Reference Guide
Spring Boot自动配置好了SpringMVC
1.以下是SpringBoot对SpringMVC的默认:
-
Inclusion of
ContentNegotiatingViewResolver
andBeanNameViewResolver
beans.- 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转发?重定向?))
- ContentNegotiatingViewResolver:组合所有的视图解析器
- 如何定制:我们可以自己给容器中添加一个视图解析器;自动的将其组合起来;
-
Support for serving static resources, including support for WebJars (see below).静态资源文件夹路径,webjars。
-
Automatic registration of
Converter
,GenericConverter
,Formatter
beans.- 自动注册了
Converter
:类型转换器GenericConverter
,Formatter
:格式化器- 自己添加的格式化转换器,我们只需要放在容器中即可;
-
Support for
HttpMessageConverters
(see below).- HttpMessageConverter :SpringMVC用来转换请求和响应的;
- HttpMessageConverters:是从容器中确定;获取所有的HttpMessageConverter ;
- 自己给容器中添加HttpMessageConverter ,只需将自己的组件注册到容器中(@Bean,@Component)
-
Automatic registration of
MessageCodesResolver
(see below).定义错误代码生成规则 -
Static
index.html
support.静态首页访问 -
Custom
Favicon
support (see below). -
Automatic use of a
ConfigurableWebBindingInitializer
bean (see below).- 我们可以配置一个ConfigurableWebBindingInitializer添加到容器来替换默认的;
If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own @Configuration
class of type WebMvcConfigurerAdapter
, but without @EnableWebMvc
. If you wish to provide custom instances of RequestMappingHandlerMapping
, RequestMappingHandlerAdapter
or ExceptionHandlerExceptionResolver
you can declare a WebMvcRegistrationsAdapter
instance providing such components.
If you want to take complete control of Spring MVC, you can add your own @Configuration
annotated with @EnableWebMvc
.
2.扩展SpringMVC
编写一个配置类(@Configuration)是WebMvcConfigurerAdapter类型;不能标注@EnableWebMvc;
既保留了所有的自动配置,也能用我们扩展的配置;
/*** 使用WebMvcConfigurerAdapter可以来扩展SpringMvc的功能*/
//@EnableWebMvc//能全权接管SpringMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {//注册拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {
// SpringBoot2.0+ 会拦截静态资源registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html", "/", "/user/login", "/asserts/**", "/webjars/**");}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**", "/asserts/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/static");}//所有的组件会一起起作用@Overridepublic void addViewControllers(ViewControllerRegistry registry) {//登录页视图解析registry.addViewController("/").setViewName("login");registry.addViewController("/index.html").setViewName("login");//主页视图解析registry.addViewController("/purchase_order.html").setViewName("main");}
}
原理:
1)、WebMvcAutoConfiguration是SpringMvc的自动配置类
2)、在做其他自动配置时,会导入:@Import(EnableWebMvcConfiguration.class)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();//从容器中获取所有的WebMvcConfigurer@Autowired(required = false)public void setConfigurers(List<WebMvcConfigurer> configurers) {if (!CollectionUtils.isEmpty(configurers)) {this.configurers.addWebMvcConfigurers(configurers);}}//一个参考实现//protected void addViewControllers(ViewControllerRegistry registry) {//this.configurers.addViewControllers(registry);// }}
3)、容器中所有的WebMvcConfiguration都会一起起作用;
4)、我们的配置类也会被调用
效果:SpringMVC的自动配置和我们自己扩展的自动配置都会起作用;
3.全面接管SpringMVC
SpringBoot对SpringMVC的自动配置不需要了,所有的都是自己配置的;只需要在配置类上添加@EnableWebMvc注解
4.如何修改SpringBoot的默认配置
模式:
1)SpringBoot在自动配置很多组建的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户自己配置的,如果没有才自动配置;如果有写组件有多个(如:ViewResolver)将用户配置的和默认的组个起来;
5.RestfulCRUD
1.Thymeleaf公共页面元素抽取
1、抽取公共片段
<div th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</div>
2、在需要的地方引入公共片段
<body>
...
<div th:insert="~{footer :: copy}"></div>
</body>
~{templatename::selector} 模板名::选择器
~{templatename::fragmentname} 模板名::片段名
3、默认效果
insert的功能片段在div标签中
三种引入功能片段的th属性:
**th:insert ** :将整个公共片段插入到声明引入的元素中
th:replace :将声明引入的元素替换为公共片段
th:include :将被引入的片段的内容包含近这个标签中
<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</footer>//三种引入方式
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
//效果
<div><footer>© 2011 The Good Thymes Virtual Grocery</footer>
</div><footer>© 2011 The Good Thymes Virtual Grocery</footer>
<div>© 2011 The Good Thymes Virtual Grocery
</div>
6.错误处理机制
1、SpringBoot默认的错误处理机制
1)、默认:浏览器返回一个默认的网页
2)、客户端会返回 Json格式数据
参照ErrorMvcAutoConfiguration:错误处理的自动配置
给容器中添加了一下组件:
DefaultErrorAttributes:帮我们在页面共享信息
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,boolean includeStackTrace) {Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();errorAttributes.put("timestamp", new Date());addStatus(errorAttributes, requestAttributes);addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);addPath(errorAttributes, requestAttributes);return errorAttributes;
}
BasicErrorController:处理默认/error请求
@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {@RequestMapping(produces = {"text/html"})//产生html类型数据;浏览器发送的请求被这个方法处理public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {HttpStatus status = this.getStatus(request);Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.TEXT_HTML)));response.setStatus(status.value());ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);return modelAndView != null ? modelAndView : new ModelAndView("error", model);}@RequestMapping//产生json数据;客户端发送的请求被这个方法处理public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {HttpStatus status = this.getStatus(request);if (status == HttpStatus.NO_CONTENT) {return new ResponseEntity(status);} else {Map<String, Object> body = this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.ALL));return new ResponseEntity(body, status);}}
ErrorPageCustomizer:
public class ErrorProperties {@Value("${error.path:/error}")private String path = "/error";//系统出现错误后来到/error请求进行处理
DefaultErrorViewResolver:
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), model);if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);}return modelAndView;}private ModelAndView resolve(String viewName, Map<String, Object> model) {//默认SpringBoot去找error/404这个页面String errorViewName = "error/" + viewName;//模板引擎可以解析这个页面就用模板引擎解析TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);//模板引擎可用的情况下返回到errorViewName指定的视图地址,模板引擎不能用就在静态资源文件夹下找errorViewName对应的页面 error/404.htmlreturn provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);}
步骤:
一但系统出现4xx或5xx之类的错误,ErrorPageCustomizer就会生效(定制错误的响应规则),继而发送/error请求,继而被BasicErrorController处理
响应页面;去哪个页面是由DefaultErrorViewResolver解析得到的
protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {Iterator var5 = this.errorViewResolvers.iterator();ModelAndView modelAndView;do {if (!var5.hasNext()) {return null;}ErrorViewResolver resolver = (ErrorViewResolver)var5.next();modelAndView = resolver.resolveErrorView(request, status, model);} while(modelAndView == null);return modelAndView;}
2.如何定制错误响应
1)、如何定制错误的页面:
有模板引擎的情况下:error/状态码:将错误页面命名为 错误状态码.html放在模板引擎文件夹里的error文件夹下,发生此状态码错误就会来到对应的页面;
我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确状态码页面优先。
页面能获取的信息:
timestamp:时间戳
status:状态码
error:错误提示
exception:异常对象
message:异常消息
errors:JSR303数据校验的错误都在这里
**无模板引擎的情况:**模板引擎找不到错误页面,静态资源文件夹下找
以上都没有错误页面,就默认来到SpringBoot默认的错误页面提示
2)、如何定制错误的 Json数据:
①:自定义异常处理&返回定制json数据(不能自适应效果)
@ControllerAdvice //异常处理注解
public class MyExceptionController {//SpringBoot不能自动识别是客户端访问还是浏览器访问,返回的全部时Json数据// @ResponseBody//@ExceptionHandler(Exception.class)//处理所有的异常,也可以处理特定的异常//public Map<String,Object> myException_1(Exception e){// Map<String,Object> map = new HashMap<>();// map.put("code","自己定义的异常" );// map.put("message",e.getMessage() );// return map;
}
②:转发到/error进行自适应响应效果处理
@ControllerAdvice //异常处理注解
public class MyExceptionController {
//可以根据客户端或浏览器 自适应返回数据类型@ExceptionHandler(Exception.class)//处理所有的异常,也可以处理特定的异常public String myException_2(Exception e, HttpServletRequest request){Map<String,Object> map = new HashMap<>();//传入自己的状态码request.setAttribute("javax.servlet.error.status_code", 400);map.put("code","自己定义的异常" );map.put("message",e.getMessage() );return "forward:/error";}
}
③:携带自定义错误信息数据
出现错误后回来到/error请求,会被BasicErrorController处理,向应出去可以获取的数据是由getErrorAttributes得到的(是AbstractErrorController(ErrorController)规定的方法)
1.完全来编写一个ErrorController的实现类【或者是编写AbstractErrorController的子类】,放在容器中
2.页面上能用的数据,或者是json返回能用的数据都是通过errorAttributes.getAttributes得到,容器中DefaultErrorAttributes.getAttributes(),默认进行处理的;
自定义ErrorAttributes
/*** 能够在浏览器或者客户端访问时显示自定义的错误信息*/
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {@Overridepublic Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {Map<String,Object> map = super.getErrorAttributes(webRequest, options);map.put("company","com");//我们的异常处理器携带的数据Map<String,Object> ext = (Map<String, Object>) webRequest.getAttribute("ext", 0);map.put("ext",ext );return map;}
}
最终结果:响应是自适应的,可以通过定制ErrorAttributes改变需要返回的内容
7.配置嵌入式Servlet容器
SpringBoot默认使用内嵌式Tomcat.
1)、如何定制和修改Servlet容器的相关配置
①:修改和server有关的配置(serverProperties)
server.port=8080
server.servlet.context-path=/curd
server.tomcat.uri-encoding=UTF-8#通用的Servlet容器设置
server.xxx
#Tomcat的设置
server.tomcat.xxx
②:编写一个WebServerFactoryCustomizer(嵌入式Servlet定制器)来修改servlet容器的配置
/*** 2.0+的SpringBoot中EmbeddedServletContainerCustomizer已经不存在,被WebServerFactoryCustomizer替代了* @return*/@Beanpublic WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryWebServerFactoryCustomizer(){return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {//定制嵌入式的Servlet规则@Overridepublic void customize(ConfigurableWebServerFactory factory) {factory.setPort(9999);}};}
2)、注册Servlet三大组件【servlet、Filter、Listener】
由于SpringBoot默认是以jar包的形式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件
注册三大件用一下方法:
ServletRegistrationBean
// SpringBoot注册Web三大组件(servlet、filter、listener)//1.注册Servlet@Beanpublic ServletRegistrationBean myServlet() {ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(), "/myServlet");return registrationBean;}
FilterRegistrationBean
//2.注册Filter@Beanpublic FilterRegistrationBean myFilter() {FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new MyFilter());registrationBean.setUrlPatterns(Arrays.asList("/hello", "/myServlet"));return registrationBean;}
ServletListenerRegistrationBean
//3.注册Listener@Beanpublic ServletListenerRegistrationBean myListener() {ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());return registrationBean;}
SpringBoot自动配置SpringMVC时,自动注册了SpringMVC的前端控制器:DispatcherServlet
@Bean( name = {"dispatcherServletRegistration"} )
@ConditionalOnBean(value = {DispatcherServlet.class},name = {"dispatcherServlet"})
public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, webMvcProperties.getServlet().getPath());
//默认拦截 "/" 所有请求,包括静态资源,但是不拦截JSP,"/*"拦截JSP
registration.setName("dispatcherServlet");
registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());multipartConfig.ifAvailable(registration::setMultipartConfig);return registration;}
3)、替换为其它嵌入式Servlet容器
默认支持:
Tomcat(默认使用):
Jetty:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><artifactId>spring-boot-starter-tomcat</artifactId><groupId>org.springframework.boot</groupId></exclusion></exclusions></dependency><!--引入其他的Servlet容器--><dependency><artifactId>spring-boot-starter-jetty</artifactId><groupId>org.springframework.boot</groupId></dependency>
</dependency>
Undertow:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><artifactId>spring-boot-starter-tomcat</artifactId><groupId>org.springframework.boot</groupId></exclusion></exclusions></dependency><!--引入其他的Servlet容器--><dependency><artifactId>spring-boot-starter-jetty</artifactId><groupId>org.springframework.boot</groupId></dependency>
</dependency>
8.使用外置Servlet容器
嵌入式Servlet应打成Jar包
优点:简单、便捷
缺点:默认不支持JSP、优化定制比较复杂
外置的Servlet容器:外面安装Tomcat 应用打成War包
步骤:
1、创建一个War项目
2、将嵌入式Tomcat指定为provided
<dependency><artifactId>spring-boot-starter-tomcat</artifactId><groupId>org.springframework.boot</groupId><scope>provided</scope>
</dependency>
3、必须编写一个SpringBootServletInitializer的子类,并调用configure方法
public class ServletInitializer extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {//传入SpringBoot应用主程序return builder.sources(SpringBootRestfulcrudApplication.class);}
}
4、启动Tomcat服务器即可使用。
原理:
jar包:执行SpringBoot主启动类的main方法,启动ioc容器,创建嵌入式的Servlet容器。
war包:启动服务器,服务器启动SpringBoot应用(SpringBootServletInitializer),启动ioc容器。
八、SpringBoot与Docker
1、简介
Docker是一个开源的应用容器引擎;
Docker支持将软件编译成一个镜像,然后在镜像中配置好各种软件,将镜像发布出去,其他使用者可以直接使用这个镜像。运行中的这个镜像称为容器,容器启动是非常快的。
2、核心概念
docker主机(host):安装了Docker程序的机器(Docker直接安装在操作系统上)
docker客户端(Client):连接docker主机进行操作
docker仓库(Registry):用来保存各种打包好的软件镜像
docker镜像(Images):软件打包好的镜像;放在docker仓库中
docker容器(Container):镜像启动后的实例称为一个容器;容器是独立运行的一个或一组应用
使用Docker的步骤:
1)、安装Docker
2)、去Docker仓库找到这个软件对应的镜像
3)、使用Docker运行这个镜像,这个镜像就会生成一个Docker容器
4)、对容器启动的停止就是对软件的启动停止
3、安装Docker
1)、安装Linux虚拟机
1、VMWare、VirtualBox(轻量)
2、导入虚拟机文件
3、双击启动导入的虚拟机(用户名:root 密码:123456)
4、使用客户端连接Linux服务器进行命令操作
5、设置虚拟机网络 (桥接网络>根据实机选择网络选择界面名称>接入网线)
6、重启虚拟机网卡
service network restart
7、查看虚拟机IP地址
ip addr
2)、在Linux虚拟机上安装Docker
1、查看Centos版本(要求Centos版本内核高于3.10)
# uname -r
2、安装docker
# yum install docker
3、启动docker
# systemctl start docker
注:如果启动时报错:Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.
解决:vi进入 /etc/sysconfig/docker
OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false'改为OPTIONS='--selinux-enabled=false --log-driver=journald --signature-verification=false'即可。
4、查看docker版本
# docker -v
Docker version 1.13.1, build 7d71120/1.13.1
5、开机自启docker
# systemctl enable docker
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
4、Docker常用命令&操作
1)、镜像操作
操作 | 命令 | 说明 |
---|---|---|
检索 | docker search xxx 如 docker search mysql | 与docker hub官网一样,可以检索镜像的信息,如镜像的Tag |
拉取 | docker pull 镜像名 : tag | tag是可选的,tag表示标签,多为软件的版本,默认是latest |
列表 | docker images | 查看本地所有镜像 |
删除 | docker rmi image-id | 删除指定的本地镜像 |
docker hub官网搜索镜像
2)、容器操作
软件镜像(xxx.exe)----运行镜像----产生一个容器(正在运行的软件)
步骤:
1、搜索镜像
[root@localhost ~]# docker search tomcat
2、拉取镜像
[root@localhost ~]# docker pull tomcat //拉取的tomcat镜像不要新版本
3、根据镜像启动容器
[root@localhost ~]# docker run --name mytomcat -d containerName // -d代表后台运行
f4991f8cf0bf0573f9549929aa98985b7148afd71bbe9c1f37c70aaa00acf461
4、停止运行中的容器
# docker stop 容器的id/docker container stop 容器ID
5、查看运行中的容器
# docker ps
6、查看所有的容器
# docker ps -a
7、启动容器
# docker start 容器的id/docker container start 容器ID
8、删除一个容器
# docker rm 容器的id
9、启动一个做了端口映射的tomcat
# docker run -d -it -p 8888:8080 tomcat;
-p:主机的端口映射到容器的一个端口 #(主机端口8888:映射虚拟机容器中的端口8080)
#注:docker容器运行必须有一个前台进程, 如果没有前台进程执行,容器认为空闲,容器运行的命令如果不是那些一直挂起的命令(eg. 运行top,tail等),就会自行退出,
# docker run -d -it -p 8080:8080 tomcat /bin/bash
10、查看日志
# docker logs containerName/containerId
更多docker命令参考
3)、安装MySQL示例
拉取mysql镜像
# docker pull mysql:5.7.38
错误启动演示:
# docker run -d mysql:5.7.38
使用docker ps查看没有后台运行的容器
查看日志docker logs mysql容器的id
Database is uninitialized and password option is not specifiedYou need to specify one of the following:- MYSQL_ROOT_PASSWORD- MYSQL_ALLOW_EMPTY_PASSWORD- MYSQL_RANDOM_ROOT_PASSWORD 这三个参数必须指定一个
正确启动演示:
# docker run -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7.38 未做端口映射
# docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7.38 做了端口映射
其他带参高级操作:
# docker run --name some-mysql -v /conf/mysql:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
-v /conf/mysql:/etc/mysql/conf.d 把主机的/conf/mysql挂载到mysql容器的/etc/mysql/conf.d文件夹里面,改mysql的配置文件放在/conf/mysql下# docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
指定mysql的一些参数
九、SpringBoot与数据访问
1、JDBC
导入依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>
2.0+版本的SpringBoot默认使用的数据源:com.zaxxer.hikari.HikariDataSource
数据源的相关配置都在DataSourceProperties.class中
自动配置原理:
和数据源有关的配置都在这个包下:
org.springframework.boot.autoconfigure.jdbc
1)、参考DataSourceConfiguration.class,根据配置创建数据源,默认使用Hikari连接池,可以使用spring.datasource.type指定自定义的数据源类型;
2)、SpringBoot默认支持以下数据源
org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource
3)、也可以使用以下方法自定义数据源类型
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean({DataSource.class})
@ConditionalOnProperty(name = {"spring.datasource.type"})
static class Generic {Generic() {}@BeanDataSource dataSource(DataSourceProperties properties) {return properties.initializeDataSourceBuilder().build();}
}
使用DataSourceBuilder来创建数据源,其中有一个build()方法,通过BeanUtils进行反射创建相应的type的数据源,并且绑定相关属性
4)、还有一处配置:DataSourceAutoConfiguration ,代表数据源的自动配置。
由于2.0版本以上的SpringBoot源码变动,DataSourceAutoConfiguration 中没有DataSourceInitializer 。不过,有一个DataSourceInitializerInvoker,是一个ApplicationListener监听器,其中则有。
其作用:
2.0版本以上是
1、createSchema():运行建表语句
2、initSchema():运行插入数据的SQL语句
二者都调用runScripts()方法,但2.0版本以上要在配置文件中加入
# 初始化模式
spring.datasource.initialization-mode=always
其有三个值:always为始终执行初始化,embedded只初始化内存数据库(默认值),如h2等,never为不执行初始化
是应为2.0版本有个isEnabled()方法,用来判断类型的。
2.0版本以下:
1、runSchemaScripts():运行建表语句
2、runDataScripts():运行插入数据的sql语句。
默认只需将文件命名为:
schame-*.sql、data-*.sql
默认规则:schame.sql或schema-all.sql
如果不是用默认规则,则需要在配置文件中使用spring.datasource.schema=xxx
指定sql脚本文件的路径,如spring.datasource.schema=classpath:department.sql
在运行建表语句时,先通过getScripts()方法获取sql脚本文件。可以通过resources指定文件的位置,如果找不到,就去找类路径下找fallback,而fallback就是schema
5)、操作数据库:自动配置了jdbcTemplate操作数据库
注:每次启动项目都会重新执行建表语,可以删除sql脚本文件,也可在配置文件中将spring.datasource.initialization-mode改为never
2、整合Druid数据源
添加Druid数据源依赖:
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.8</version>
</dependency>
给容器中注入Druid数据源:
@Configuration
public class DruidConf {@Bean@ConfigurationProperties(prefix = "spring.datasource")//绑定数据元的其他配置public DataSource druid(){return new DruidDataSource() ;}/*** 配置druid监控* 配置一个管理后台的Servlet:statViewServlet* @return*/@Beanpublic ServletRegistrationBean statViewServlet(){ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");Map<String,Object> map = new HashMap<>();map.put("loginUsername", "admin");map.put("loginPassword", "123456");map.put("allow", ""); //""或null为访问所有map.put("deny","192.168.2.175" );//拒绝访问//为此注册设置初始化参数。调用此方法将替换任何现有的初始化参数。bean.setInitParameters(map);return bean;}/*** 配置一个监控Web的filter:webStatFilter* @return*/@Beanpublic FilterRegistrationBean webStatFilter(){FilterRegistrationBean bean = new FilterRegistrationBean(new WebStatFilter());Map<String,Object> map = new HashMap<>();//释放这些请求map.put("exclusions", "*.js,*.css,/druid/*");bean.setInitParameters(map);//拦截所有请求bean.setUrlPatterns(Arrays.asList("/*"));return bean;}
}
application.properties
# 应用名称
spring.application.name=spring-boot-data-jdbc
# 应用服务 WEB 访问端口
server.port=8080
# 数据库驱动:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据源名称
spring.datasource.name=defaultDataSource
# 初始化模式
spring.datasource.initialization-mode=never
# 数据库脚本文件路径
spring.datasource.schema=classpath:department.sql
# 数据库连接地址
spring.datasource.url=jdbc:mysql://192.168.2.175:3306/jdbc?serverTimezone=UTC
# 自定义数据源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j2
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.useGlobalDataSourceStat=true
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500#是否启用StatViewServlet(监控页面)默认值为false(考虑到安全问题默认并未启动,如需启用建议设置密码或白名单以保障安全)
#spring.datasource.druid.stat-view-servlet.enabled=true
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=root
Druid监控
3、整合MyBatis
1)、引入MyBatis依赖
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version>
</dependency>
2)、注解版
注解版不能配置xxx.xml,所以注解版的配置需要使用MybatisAutoConfiguration类中的ConfigurationCustomizer定制一个MyBatis配置类加入到容器中
@Configuration
public class MybatisConf {@Beanpublic ConfigurationCustomizer configurationCustomizer(){return new ConfigurationCustomizer() {@Overridepublic void customize(org.apache.ibatis.session.Configuration configuration) {configuration.setMapUnderscoreToCamelCase(true);//开启驼峰命名法}};}
}
注:如果mapper包下的mapper太多,可以在SpringBoot启动类上使用@MapperScan注解扫描mapper包。
3)、配置文件版
创建一个Mybatis全局配置文件:mybatis-conf.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><setting name="mapUnderscoreToCamelCase" value="true"/></settings>
</configuration>
在SpringBoot配置文件application.properties中增加以下配置:
# 指定MyBatis全局配置文件路径
mybatis.config-location=classpath:mybatis/mybatis-conf.xml
#指定mapper映射文件路径
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
创建mapper.xml映射文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atcpl.springboot.mapper.Mappers"><select id="queryEmpById" resultType="com.atcpl.springboot.entity.Employee">select * from employee where id = #{id}</select>
</mapper>
注: ,namespace的值为mapper接口文件的全类名。
<select id=" “>,id的值为mapper接口中抽象方法的方法名。
更多配置参考Mybatis官方文档
4、整合SpringData JPA
1)、SpringData简介
2)、整合SpringData JPA
jpa:ORM(Object Relational Mapping)
步骤:
①:编写一个实体类(bean)和数据表进行映射,并且配置好映射关系
/*** 使用JPA注解配置映射关系*/
@Entity //告诉JPA这是一个实体类 (与数据表映射的类)
@Table(name = "user_table") // @Table指定和哪个数据表对应;默认是实体类类名小写user
public class User {@Id // @Id 主键@GeneratedValue(strategy = GenerationType.IDENTITY) // 主键自增private Integer id;@Column(name = "email",length = 25) // 这是和数据表对应的一个列; name指定字段名 length指定长度private String email;@Column //字段名默认为属性名private String userName;
}
②:创建一个Dao接口来操作实体类对应的数据表(Repository)
/*** 这是一个Dao接口,来操作实体类对应的数据表(Repository)* JpaRepository<T,ID> :* 泛型T:代表要操作的实体类* 泛型ID:实体类主键*/
public interface UserRepository extends JpaRepository<User,Integer> {}
③:JPA的基本配置
spring:jpa:hibernate:# 更新或者创建数据表结构ddl-auto: update# 在控制台显示sqlshow-sql: true
所有的JPA配置都在JpaProperties.class类中。
findOne()与findById():
调用findByid方法,返回实体类的Optional,再调用isPresent进行判断是否不为空,若是就调用get获取对象,然后判断对象是否存在,删除
Optional<Permission> permissions = permissionDao.findById(id);
if (permissions.isPresent()){Permission permission = permissions.get();if (permission != null){permissionDao.delete(permission);}
}
调用findById()方法和orElse(null)方法,获取实体类对象,然后再判断实体类是否为空
permissionDao.findById(id).ifPresent(permission -> {if (permission != null){permissionDao.delete(permission);}
});
十、启动配置原理
几个重要的事件回调机制
配置在META-INF/spring.factories
ApplicationContextInitializer
SpringApplicationRunListener
只需要放在ioc容器中
ApplicationRunner
CommandLineRunner
启动原理:
1、创建SpringApplication对象
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");//保存主配置类this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//判断当前应用是否为Web应用this.webApplicationType = WebApplicationType.deduceFromClasspath();//从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//从类路径下找到ETA‐INF/spring.factories配置的所有ApplicationListenersetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//从多个配置类中找到有main方法的主配置类this.mainApplicationClass = deduceMainApplicationClass();}private Class<?> deduceMainApplicationClass() {try {StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();for (StackTraceElement stackTraceElement : stackTrace) {if ("main".equals(stackTraceElement.getMethodName())) {return Class.forName(stackTraceElement.getClassName());}}}catch (ClassNotFoundException ex) {// Swallow and continue}return null;}
2、调用run()方法
public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();//从类路径META-INF/spring.factories下获取SpringApplicationRunListenersSpringApplicationRunListeners listeners = getRunListeners(args);//回调所有的获取SpringApplicationRunListener.starting()方法listeners.starting();try {//封装命令行参数ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//准备环境ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);//创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成configureIgnoreBeanInfo(environment);//打印banner图,就是控制台中那个大SpringBanner printedBanner = printBanner(environment);//创建ApplicationContext;决定创建web的ioc还是普通的ioccontext = createApplicationContext();//做异分析报告exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);//准备上下文环境;将environment保存到ioc中;而且applyInitializers()方法回调之前保存的所有的ApplicationContextInitializer的initialize方法;listeners.contextPrepared(context)则回调所有的SpringApplicationRunListener的contextPrepared();//prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();prepareContext(context, environment, listeners, applicationArguments, printedBanner);//刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);
//扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)refreshContext(context);//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调//ApplicationRunner先回调,CommandLineRunner再回调afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}//整个SpringBoot应用启动完成以后返回启动的ioc容器;return context;
}
3、事件监听机制
配置在META-INF/spring.factories
ApplicationContextInitializer
public class HelloApplicationContextInitializer implementsApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {System.out.println("ApplicationContextInitializer...initialize..."+applicationContext);}
}
SpringApplicationRunListener
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {//必须有的构造器public HelloSpringApplicationRunListener(SpringApplication application, String[] args){}@Overridepublic void starting() {System.out.println("SpringApplicationRunListener...starting...");}@Overridepublic void environmentPrepared(ConfigurableEnvironment environment) {Object o = environment.getSystemProperties().get("os.name");System.out.println("SpringApplicationRunListener...environmentPrepared.."+o);}@Overridepublic void contextPrepared(ConfigurableApplicationContext context) {System.out.println("SpringApplicationRunListener...contextPrepared...");}@Overridepublic void contextLoaded(ConfigurableApplicationContext context) {System.out.println("SpringApplicationRunListener...contextLoaded...");}@Overridepublic void finished(ConfigurableApplicationContext context, Throwable exception){System.out.println("SpringApplicationRunListener...finished...");}
}
配置(META-INF/spring.factories)
org.springframework.context.ApplicationContextInitializer=\
com.atguigu.springboot.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.atguigu.springboot.listener.HelloSpringApplicationRunListener
只需要放在ioc容器中
ApplicationRunner
@Component
public class HelloApplicationRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("ApplicationRunner...run....");}
}
CommandLineRunner
@Component
public class HelloCommandLineRunner implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));}
}
十一、自定义Starter
starter:又叫场景启动器
1、这个场景需要使用到的依赖是什么?
2、如何编写自动配置
@Configuration //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter //指定自动配置类的顺序
@Bean //给容器中添加组件
@ConfigurationPropertie结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加入到容器中
自动配置类要能加载
将需要启动就加载的自动配置类,配置在META‐INF/spring.factories
3、模式
启动器只用来做依赖导入;
专门来写一个自动配置模块;
启动器依赖自动配置;别人只需要引入启动器(starter)
启动器命名规约:
- 官方命名空间
- 前缀:“spring-boot-starter-”
- 模式:“spring-boot-starter-模块名”
- 如:spring-boot-starter-web、spring-boot-starter-jdbc
- 自定义命名空间
- 后缀:“-spring-boot-starter”
- 模式:模块-spring-boot-starter
- 如:mybatis-spring-boot-starter
即:自定义启动器名-spring-boot-starter
xtLoaded…");
}
@Override
public void finished(ConfigurableApplicationContext context, Throwable exception){
System.out.println(“SpringApplicationRunListener…finished…”);
}
}
**配置(META-INF/spring.factories)** ```properties
org.springframework.context.ApplicationContextInitializer=\
com.atguigu.springboot.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.atguigu.springboot.listener.HelloSpringApplicationRunListener
只需要放在ioc容器中
ApplicationRunner
@Component
public class HelloApplicationRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("ApplicationRunner...run....");}
}
CommandLineRunner
@Component
public class HelloCommandLineRunner implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));}
}
十一、自定义Starter
starter:又叫场景启动器
1、这个场景需要使用到的依赖是什么?
2、如何编写自动配置
@Configuration //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter //指定自动配置类的顺序
@Bean //给容器中添加组件
@ConfigurationPropertie结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加入到容器中
自动配置类要能加载
将需要启动就加载的自动配置类,配置在META‐INF/spring.factories
3、模式
启动器只用来做依赖导入;
专门来写一个自动配置模块;
启动器依赖自动配置;别人只需要引入启动器(starter)
启动器命名规约:
- 官方命名空间
- 前缀:“spring-boot-starter-”
- 模式:“spring-boot-starter-模块名”
- 如:spring-boot-starter-web、spring-boot-starter-jdbc
- 自定义命名空间
- 后缀:“-spring-boot-starter”
- 模式:模块-spring-boot-starter
- 如:mybatis-spring-boot-starter
即:自定义启动器名-spring-boot-starter