5)贫悄、CRUD-員工列表
實(shí)驗(yàn)要求:
1)、RestfulCRUD:CRUD滿足Rest風(fēng)格跟狱;
URI: /資源名稱/資源標(biāo)識 HTTP請求方式區(qū)分對資源CRUD操作
普通CRUD(uri來區(qū)分操作)RestfulCRUD
查詢getEmpemp---GET
添加addEmp?xxxemp---POST
修改updateEmp?id=xxx&xxx=xxemp/{id}---PUT
刪除deleteEmp?id=1emp/{id}---DELETE
2)敞曹、實(shí)驗(yàn)的請求架構(gòu);
實(shí)驗(yàn)功能請求URI請求方式
查詢所有員工empsGET
查詢某個員工(來到修改頁面)emp/1GET
來到添加頁面empGET
添加員工empPOST
來到修改頁面(查出員工進(jìn)行信息回顯)emp/1GET
修改員工empPUT
刪除員工emp/1DELETE
3)、員工列表:
thymeleaf公共頁面元素抽取
1祖能、抽取公共片段?
2011 The Good Thymes Virtual
Grocery2、引入公共片段~{templatename::selector}:模板名::選擇器~{templatename::fragmentname}:模板名::片段名3蛾洛、默認(rèn)效果:insert的公共片段在div標(biāo)簽中如果使用th:insert等屬性進(jìn)行引入养铸,可以不用寫~{}:行內(nèi)寫法可以加上:[[~{}]];[(~{})];
三種引入公共片段的th屬性:
th:insert:將公共片段整個插入到聲明引入的元素中
th:replace:將聲明引入的元素替換為公共片段
th:include:將被引入的片段的內(nèi)容包含進(jìn)這個標(biāo)簽中
? 2011 The Good Thymes Virtual Grocery引入方式效果
? 2011 The Good Thymes Virtual Grocery
? 2011 The Good Thymes Virtual Grocery
? 2011 The Good Thymes Virtual Grocery
引入片段的時候傳入?yún)?shù):
Dashboard(current)
6)雅潭、CRUD-員工添加
添加頁面
LastNameEmailGender
男女department12345Birth添加
提交的數(shù)據(jù)格式不對:生日:日期揭厚;
2017-12-12却特;2017/12/12扶供;2017.12.12;
日期的格式化裂明;SpringMVC將頁面提交的值需要轉(zhuǎn)換為指定的類型;
2017-12-12---Date椿浓; 類型轉(zhuǎn)換,格式化;
默認(rèn)日期是按照/的方式闽晦;
7)扳碍、CRUD-員工修改
修改添加二合一表單
<!--發(fā)送put請求修改員工數(shù)據(jù)--><!--
1、SpringMVC中配置HiddenHttpMethodFilter;(SpringBoot自動配置好的)
2仙蛉、頁面創(chuàng)建一個post表單
3笋敞、創(chuàng)建一個input項(xiàng),name="_method";值就是我們指定的請求方式
-->LastNameEmailGender
男女department1Birth添加
8)荠瘪、CRUD-員工刪除
[[${emp.lastName}]]編輯刪除
7夯巷、錯誤處理機(jī)制
1)、SpringBoot默認(rèn)的錯誤處理機(jī)制
默認(rèn)效果:
? 1)哀墓、瀏覽器趁餐,返回一個默認(rèn)的錯誤頁面
瀏覽器發(fā)送請求的請求頭:
? 2)、如果是其他客戶端篮绰,默認(rèn)響應(yīng)一個json數(shù)據(jù)
?
原理:
? 可以參照ErrorMvcAutoConfiguration后雷;錯誤處理的自動配置;
給容器中添加了以下組件
? 1吠各、DefaultErrorAttributes:
幫我們在頁面共享信息臀突;@OverridepublicMapgetErrorAttributes(RequestAttributes
requestAttributes,booleanincludeStackTrace){MaperrorAttributes
=newLinkedHashMap();errorAttributes.put("timestamp",newDate());addStatus(errorAttributes,
requestAttributes);addErrorDetails(errorAttributes, requestAttributes,
includeStackTrace);addPath(errorAttributes,
requestAttributes);returnerrorAttributes;}
? 2、BasicErrorController:處理默認(rèn)/error請求
@Controller@RequestMapping("${server.error.path:${error.path:/error}}")publicclassBasicErrorControllerextendsAbstractErrorController{@RequestMapping(produces
="text/html")//產(chǎn)生html類型的數(shù)據(jù)贾漏;瀏覽器發(fā)送的請求來到這個方法處理publicModelAndViewerrorHtml(HttpServletRequest
request,
HttpServletResponse
response){HttpStatus status = getStatus(request);Mapmodel =
Collections.unmodifiableMap(getErrorAttributes(request,
isIncludeStackTrace(request,
MediaType.TEXT_HTML)));response.setStatus(status.value());//去哪個頁面作為錯誤頁面候学;包含頁面地址和頁面內(nèi)容ModelAndView
modelAndView = resolveErrorView(request, response, status,
model);return(modelAndView ==null?newModelAndView("error", model) :
modelAndView);}@RequestMapping@ResponseBody//產(chǎn)生json數(shù)據(jù),其他客戶端來到這個方法處理磕瓷;publicResponseEntity>
error(HttpServletRequest request) {Mapbody =
getErrorAttributes(request,isIncludeStackTrace(request,
MediaType.ALL));HttpStatus status =
getStatus(request);returnnewResponseEntity>(body, status);}
? 3盒齿、ErrorPageCustomizer:
@Value("${error.path:/error}")privateString path ="/error";? 系統(tǒng)出現(xiàn)錯誤以后來到error請求進(jìn)行處理航闺;(web.xml注冊的錯誤頁面規(guī)則)
? 4蹭越、DefaultErrorViewResolver:
@OverridepublicModelAndViewresolveErrorView(HttpServletRequest request, HttpStatus status,
Map<String, Object> model){ModelAndView modelAndView =
resolve(String.valueOf(status), model);if(modelAndView ==null&&
SERIES_VIEWS.containsKey(status.series())) {modelAndView =
resolve(SERIES_VIEWS.get(status.series()),
model);}returnmodelAndView;}privateModelAndViewresolve(String viewName,
Map<String, Object> model){//默認(rèn)SpringBoot可以去找到一個頁面??
error/404String errorViewName ="error/"+
viewName;//模板引擎可以解析這個頁面地址就用模板引擎解析TemplateAvailabilityProvider provider
=this.templateAvailabilityProviders.getProvider(errorViewName,this.applicationContext);if(provider
!=null)
{//模板引擎可用的情況下返回到errorViewName指定的視圖地址returnnewModelAndView(errorViewName,
model);}//模板引擎不可用,就在靜態(tài)資源文件夾下找errorViewName對應(yīng)的頁面??
error/404.htmlreturnresolveResource(errorViewName, model);}
? 步驟:
?一但系統(tǒng)出現(xiàn)4xx或者5xx之類的錯誤务漩;ErrorPageCustomizer就會生效(定制錯誤的響應(yīng)規(guī)則);就會來到/error請求蕴潦;就會被BasicErrorController處理害碾;
?1)響應(yīng)頁面;去哪個頁面是由DefaultErrorViewResolver解析得到的啊胶;
protectedModelAndViewresolveErrorView(HttpServletRequest request,
? ? HttpServletResponse response, HttpStatus status, Map<String,
Object>
model){//所有的ErrorViewResolver得到ModelAndViewfor(ErrorViewResolver
resolver :this.errorViewResolvers) {? ? ? ModelAndView modelAndView =
resolver.resolveErrorView(request, status, model);if(modelAndView
!=null) {returnmodelAndView;? ? ? }?? }returnnull;}
2)甸各、如果定制錯誤響應(yīng):
1)、如何定制錯誤的頁面焰坪;
?1)趣倾、有模板引擎的情況下;error/狀態(tài)碼;【將錯誤頁面命名為 錯誤狀態(tài)碼.html 放在模板引擎文件夾里面的 error文件夾下】某饰,發(fā)生此狀態(tài)碼的錯誤就會來到 對應(yīng)的頁面儒恋;
? 我們可以使用4xx和5xx作為錯誤頁面的文件名來匹配這種類型的所有錯誤,精確優(yōu)先(優(yōu)先尋找精確的狀態(tài)碼.html)黔漂;
? 頁面能獲取的信息诫尽;
? timestamp:時間戳
? status:狀態(tài)碼
? error:錯誤提示
? exception:異常對象
? message:異常消息
? errors:JSR303數(shù)據(jù)校驗(yàn)的錯誤都在這里
? 2)、沒有模板引擎(模板引擎找不到這個錯誤頁面)炬守,靜態(tài)資源文件夾下找牧嫉;
? 3)、以上都沒有錯誤頁面减途,就是默認(rèn)來到SpringBoot默認(rèn)的錯誤提示頁面酣藻;
2)、如何定制錯誤的json數(shù)據(jù)观蜗;
? 1)臊恋、自定義異常處理&返回定制json數(shù)據(jù);
@ControllerAdvicepublicclassMyExceptionHandler{@ResponseBody@ExceptionHandler(UserNotExistException.class)publicMaphandleException(Exception
e){? ? ? ? Map map =newHashMap<>();? ? ? ?
map.put("code","user.notexist");? ? ?
? map.put("message",e.getMessage());returnmap;? ? }}//沒有自適應(yīng)效果...
? 2)墓捻、轉(zhuǎn)發(fā)到/error進(jìn)行自適應(yīng)響應(yīng)效果處理
@ExceptionHandler(UserNotExistException.class)publicStringhandleException(Exception
e, HttpServletRequest request){? ? ? ? Map map
=newHashMap<>();//傳入我們自己的錯誤狀態(tài)碼? 4xx 5xx抖仅,否則就不會進(jìn)入定制錯誤頁面的解析流程/**
? ? ? ?? * Integer statusCode = (Integer) request
? ? ? ?? .getAttribute("javax.servlet.error.status_code");
? ? ?? */request.setAttribute("javax.servlet.error.status_code",500);? ?
? ? map.put("code","user.notexist");? ? ? ?
map.put("message",e.getMessage());//轉(zhuǎn)發(fā)到/errorreturn"forward:/error";? ? }
3)、將我們的定制數(shù)據(jù)攜帶出去砖第;
出現(xiàn)錯誤以后撤卢,會來到/error請求,會被BasicErrorController處理梧兼,響應(yīng)出去可以獲取的數(shù)據(jù)是由getErrorAttributes得到的(是AbstractErrorController(ErrorController)規(guī)定的方法)放吩;
? 1、完全來編寫一個ErrorController的實(shí)現(xiàn)類【或者是編寫AbstractErrorController的子類】羽杰,放在容器中渡紫;
? 2到推、頁面上能用的數(shù)據(jù),或者是json返回能用的數(shù)據(jù)都是通過errorAttributes.getErrorAttributes得到惕澎;
? 容器中DefaultErrorAttributes.getErrorAttributes()莉测;默認(rèn)進(jìn)行數(shù)據(jù)處理的;
自定義ErrorAttributes
//給容器中加入我們自己定義的ErrorAttributes@ComponentpublicclassMyErrorAttributesextendsDefaultErrorAttributes{@OverridepublicMapgetErrorAttributes(RequestAttributes
requestAttributes,booleanincludeStackTrace){? ? ? ? Map map
=super.getErrorAttributes(requestAttributes, includeStackTrace);? ? ? ?
map.put("company","atguigu");returnmap;? ? }}
最終的效果:響應(yīng)是自適應(yīng)的唧喉,可以通過定制ErrorAttributes改變需要返回的內(nèi)容捣卤,
8、配置嵌入式Servlet容器
SpringBoot默認(rèn)使用Tomcat作為嵌入式的Servlet容器八孝;
問題董朝?
1)、如何定制和修改Servlet容器的相關(guān)配置干跛;
1子姜、修改和server有關(guān)的配置(ServerProperties【也是EmbeddedServletContainerCustomizer】);
server.port=8081
server.context-path=/crud
server.tomcat.uri-encoding=UTF-8
//通用的Servlet容器設(shè)置
server.xxx
//Tomcat的設(shè)置
server.tomcat.xxx
2驯鳖、編寫一個EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器闲询;來修改Servlet容器的配置
@Bean//一定要將這個定制器加入到容器中publicEmbeddedServletContainerCustomizerembeddedServletContainerCustomizer(){returnnewEmbeddedServletContainerCustomizer()
{//定制嵌入式的Servlet容器相關(guān)的規(guī)則@Overridepublicvoidcustomize(ConfigurableEmbeddedServletContainer
container){? ? ? ? ? ? container.setPort(8083);? ? ? ? }? ? };}
2)久免、注冊Servlet三大組件【Servlet浅辙、Filter、Listener】
由于SpringBoot默認(rèn)是以jar包的方式啟動嵌入式的Servlet容器來啟動SpringBoot的web應(yīng)用阎姥,沒有web.xml文件记舆。
注冊三大組件用以下方式
ServletRegistrationBean
//注冊三大組件@BeanpublicServletRegistrationBeanmyServlet(){?
? ServletRegistrationBean registrationBean
=newServletRegistrationBean(newMyServlet(),"/myServlet");returnregistrationBean;}
FilterRegistrationBean
@BeanpublicFilterRegistrationBeanmyFilter(){?
? FilterRegistrationBean registrationBean
=newFilterRegistrationBean();? ?
registrationBean.setFilter(newMyFilter());? ?
registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));returnregistrationBean;}
ServletListenerRegistrationBean
@BeanpublicServletListenerRegistrationBeanmyListener(){?
? ServletListenerRegistrationBean registrationBean
=newServletListenerRegistrationBean<>(newMyListener());returnregistrationBean;}
SpringBoot幫我們自動SpringMVC的時候,自動的注冊SpringMVC的前端控制器呼巴;DIspatcherServlet泽腮;
DispatcherServletAutoConfiguration中:
@Bean(name
=
DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)@ConditionalOnBean(value
= DispatcherServlet.class, name =
DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)publicServletRegistrationBeandispatcherServletRegistration(
? ? DispatcherServlet dispatcherServlet){?? ServletRegistrationBean
registration =newServletRegistrationBean(? ? ? ??
dispatcherServlet,this.serverProperties.getServletMapping());//默認(rèn)攔截: /?
所有請求;包靜態(tài)資源衣赶,但是不攔截jsp請求诊赊;??
/*會攔截jsp//可以通過server.servletPath來修改SpringMVC前端控制器默認(rèn)攔截的請求路徑registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);?
registration.setLoadOnStartup(this.webMvcProperties.getServlet().getLoadOnStartup());if(this.multipartConfig
!=null) {? ? ? registration.setMultipartConfig(this.multipartConfig);?
}returnregistration;}
2)、SpringBoot能不能支持其他的Servlet容器府瞄;
3)碧磅、替換為其他嵌入式Servlet容器
默認(rèn)支持:
Tomcat(默認(rèn)使用)
org.springframework.bootspring-boot-starter-web引入web模塊默認(rèn)就是使用嵌入式的Tomcat作為Servlet容器;
Jetty
org.springframework.bootspring-boot-starter-webspring-boot-starter-tomcatorg.springframework.bootspring-boot-starter-jettyorg.springframework.boot
Undertow
org.springframework.bootspring-boot-starter-webspring-boot-starter-tomcatorg.springframework.bootspring-boot-starter-undertoworg.springframework.boot
4)遵馆、嵌入式Servlet容器自動配置原理鲸郊;
EmbeddedServletContainerAutoConfiguration:嵌入式的Servlet容器自動配置?
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)@Configuration@ConditionalOnWebApplication@Import(BeanPostProcessorsRegistrar.class)//導(dǎo)入BeanPostProcessorsRegistrar:Spring注解版货邓;給容器中導(dǎo)入一些組件//導(dǎo)入了EmbeddedServletContainerCustomizerBeanPostProcessor://后置處理器:bean初始化前后(創(chuàng)建完對象秆撮,還沒賦值賦值)執(zhí)行初始化工作publicclassEmbeddedServletContainerAutoConfiguration{@Configuration@ConditionalOnClass({
Servlet.class, Tomcat.class
})//判斷當(dāng)前是否引入了Tomcat依賴;@ConditionalOnMissingBean(value =
EmbeddedServletContainerFactory.class, search =
SearchStrategy.CURRENT)//判斷當(dāng)前容器沒有用戶自己定義EmbeddedServletContainerFactory:嵌入式的Servlet容器工廠换况;作用:創(chuàng)建嵌入式的Servlet容器publicstaticclassEmbeddedTomcat{@BeanpublicTomcatEmbeddedServletContainerFactorytomcatEmbeddedServletContainerFactory(){returnnewTomcatEmbeddedServletContainerFactory();}}/**
* Nested configuration if Jetty is being used.
*/@Configuration@ConditionalOnClass({ Servlet.class, Server.class,
Loader.class,WebAppContext.class })@ConditionalOnMissingBean(value =
EmbeddedServletContainerFactory.class, search =
SearchStrategy.CURRENT)publicstaticclassEmbeddedJetty{@BeanpublicJettyEmbeddedServletContainerFactoryjettyEmbeddedServletContainerFactory(){returnnewJettyEmbeddedServletContainerFactory();}}/**
* Nested configuration if Undertow is being used.
*/@Configuration@ConditionalOnClass({ Servlet.class, Undertow.class,
SslClientAuthMode.class })@ConditionalOnMissingBean(value =
EmbeddedServletContainerFactory.class, search =
SearchStrategy.CURRENT)publicstaticclassEmbeddedUndertow{@BeanpublicUndertowEmbeddedServletContainerFactoryundertowEmbeddedServletContainerFactory(){returnnewUndertowEmbeddedServletContainerFactory();}}
1)职辨、EmbeddedServletContainerFactory(嵌入式Servlet容器工廠)
publicinterfaceEmbeddedServletContainerFactory{//獲取嵌入式的Servlet容器EmbeddedServletContainergetEmbeddedServletContainer(
? ? ? ?? ServletContextInitializer... initializers);}
2)盗蟆、EmbeddedServletContainer:(嵌入式的Servlet容器)
3)、以TomcatEmbeddedServletContainerFactory為例
@OverridepublicEmbeddedServletContainergetEmbeddedServletContainer(
? ? ServletContextInitializer... initializers){//創(chuàng)建一個TomcatTomcat
tomcat =newTomcat();//配置Tomcat的基本環(huán)節(jié)File baseDir = (this.baseDirectory
!=null?this.baseDirectory? ? ? ?? : createTempDir("tomcat"));??
tomcat.setBaseDir(baseDir.getAbsolutePath());?? Connector connector
=newConnector(this.protocol);??
tomcat.getService().addConnector(connector);??
customizeConnector(connector);?? tomcat.setConnector(connector);??
tomcat.getHost().setAutoDeploy(false);??
configureEngine(tomcat.getEngine());for(Connector additionalConnector
:this.additionalTomcatConnectors) {? ? ?
tomcat.getService().addConnector(additionalConnector);?? }??
prepareContext(tomcat.getHost(),
initializers);//將配置好的Tomcat傳入進(jìn)去舒裤,返回一個EmbeddedServletContainer姆涩;并且啟動Tomcat服務(wù)器returngetTomcatEmbeddedServletContainer(tomcat);}
4)、我們對嵌入式容器的配置修改是怎么生效惭每?
ServerProperties骨饿、EmbeddedServletContainerCustomizer
EmbeddedServletContainerCustomizer:定制器幫我們修改了Servlet容器的配置?
怎么修改的原理台腥?
5)宏赘、容器中導(dǎo)入了EmbeddedServletContainerCustomizerBeanPostProcessor
//初始化之前@OverridepublicObjectpostProcessBeforeInitialization(Object
bean, String
beanName)throwsBeansException{//如果當(dāng)前初始化的是一個ConfigurableEmbeddedServletContainer類型的組件if(beaninstanceofConfigurableEmbeddedServletContainer)
{//postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer)
bean);?? }returnbean;}privatevoidpostProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer
bean){//獲取所有的定制器,調(diào)用每一個定制器的customize方法來給Servlet容器進(jìn)行屬性賦值黎侈;for(EmbeddedServletContainerCustomizer
customizer : getCustomizers()) {? ? ? ? customizer.customize(bean);? ?
}}privateCollectiongetCustomizers(){if(this.customizers ==null) {// Look
up does not include the parent contextthis.customizers
=newArrayList(this.beanFactory//從容器中獲取所有這葛類型的組件:EmbeddedServletContainerCustomizer//定制Servlet容器察署,給容器中可以添加一個EmbeddedServletContainerCustomizer類型的組件.getBeansOfType(EmbeddedServletContainerCustomizer.class,false,false)?
? ? ? ? ? .values());? ? ? ? Collections.sort(this.customizers,
AnnotationAwareOrderComparator.INSTANCE);this.customizers =
Collections.unmodifiableList(this.customizers);? ?
}returnthis.customizers;}ServerProperties也是定制器
步驟:
1)、SpringBoot根據(jù)導(dǎo)入的依賴情況峻汉,給容器中添加相應(yīng)的EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】
2)贴汪、容器中某個組件要創(chuàng)建對象就會驚動后置處理器;EmbeddedServletContainerCustomizerBeanPostProcessor休吠;
只要是嵌入式的Servlet容器工廠扳埂,后置處理器就工作;
3)瘤礁、后置處理器阳懂,從容器中獲取所有的EmbeddedServletContainerCustomizer,調(diào)用定制器的定制方法
###5)柜思、嵌入式Servlet容器啟動原理岩调;
什么時候創(chuàng)建嵌入式的Servlet容器工廠?什么時候獲取嵌入式的Servlet容器并啟動Tomcat赡盘;
獲取嵌入式的Servlet容器工廠:
1)号枕、SpringBoot應(yīng)用啟動運(yùn)行run方法
2)、refreshContext(context);SpringBoot刷新IOC容器【創(chuàng)建IOC容器對象陨享,并初始化容器葱淳,創(chuàng)建容器中的每一個組件】;如果是web應(yīng)用創(chuàng)建AnnotationConfigEmbeddedWebApplicationContext霉咨,否則:AnnotationConfigApplicationContext
3)蛙紫、refresh(context);刷新剛才創(chuàng)建好的ioc容器;
publicvoidrefresh()throwsBeansException,
IllegalStateException{synchronized(this.startupShutdownMonitor) {//
Prepare this context for refreshing.prepareRefresh();// Tell the
subclass to refresh the internal bean
factory.ConfigurableListableBeanFactory beanFactory =
obtainFreshBeanFactory();// Prepare the bean factory for use in this
context.prepareBeanFactory(beanFactory);try{// Allows post-processing of
the bean factory in context
subclasses.postProcessBeanFactory(beanFactory);// Invoke factory
processors registered as beans in the
context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean
processors that intercept bean
creation.registerBeanPostProcessors(beanFactory);// Initialize message
source for this context.initMessageSource();// Initialize event
multicaster for this context.initApplicationEventMulticaster();//
Initialize other special beans in specific context
subclasses.onRefresh();// Check for listener beans and register
them.registerListeners();// Instantiate all remaining (non-lazy-init)
singletons.finishBeanFactoryInitialization(beanFactory);// Last step:
publish corresponding event.finishRefresh();? ? ? }catch(BeansException
ex) {if(logger.isWarnEnabled()) {? ? ? ? ? ? logger.warn("Exception
encountered during context initialization - "+"cancelling refresh
attempt: "+ ex);? ? ? ?? }// Destroy already created singletons to avoid
dangling resources.destroyBeans();// Reset 'active'
flag.cancelRefresh(ex);// Propagate exception to caller.throwex;? ? ?
}finally{// Reset common introspection caches in Spring's core, since
we// might not ever need metadata for singleton beans
anymore...resetCommonCaches();? ? ? }?? }}
4)途戒、 onRefresh(); web的ioc容器重寫了onRefresh方法
5)坑傅、webioc容器會創(chuàng)建嵌入式的Servlet容器;createEmbeddedServletContainer();
6)喷斋、獲取嵌入式的Servlet容器工廠:
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
?從ioc容器中獲取EmbeddedServletContainerFactory 組件唁毒;TomcatEmbeddedServletContainerFactory創(chuàng)建對象蒜茴,后置處理器一看是這個對象,就獲取所有的定制器來先定制Servlet容器的相關(guān)配置浆西;
7)粉私、使用容器工廠獲取嵌入式的Servlet容器:this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer());
8)、嵌入式的Servlet容器創(chuàng)建對象并啟動Servlet容器近零;
先啟動嵌入式的Servlet容器诺核,再將ioc容器中剩下沒有創(chuàng)建出的對象獲取出來;
==IOC容器啟動創(chuàng)建嵌入式的Servlet容器==
9久信、使用外置的Servlet容器
嵌入式Servlet容器:應(yīng)用打成可執(zhí)行的jar
? 優(yōu)點(diǎn):簡單窖杀、便攜;
?
缺點(diǎn):默認(rèn)不支持JSP裙士、優(yōu)化定制比較復(fù)雜(使用定制器【ServerProperties入客、自定義EmbeddedServletContainerCustomizer】,自己編寫嵌入式Servlet容器的創(chuàng)建工廠【EmbeddedServletContainerFactory】)腿椎;
外置的Servlet容器:外面安裝Tomcat---應(yīng)用war包的方式打包桌硫;
步驟
1)、必須創(chuàng)建一個war項(xiàng)目啃炸;(利用idea創(chuàng)建好目錄結(jié)構(gòu))
2)铆隘、將嵌入式的Tomcat指定為provided;
org.springframework.bootspring-boot-starter-tomcatprovided
3)肮帐、必須編寫一個SpringBootServletInitializer的子類咖驮,并調(diào)用configure方法
publicclassServletInitializerextendsSpringBootServletInitializer{@OverrideprotectedSpringApplicationBuilderconfigure(SpringApplicationBuilder
application){//傳入SpringBoot應(yīng)用的主程序returnapplication.sources(SpringBoot04WebJspApplication.class);?
? }}
4)、啟動服務(wù)器就可以使用训枢;
原理
jar包:執(zhí)行SpringBoot主類的main方法,啟動ioc容器忘巧,創(chuàng)建嵌入式的Servlet容器恒界;
war包:啟動服務(wù)器,服務(wù)器啟動SpringBoot應(yīng)用【SpringBootServletInitializer】砚嘴,啟動ioc容器十酣;
servlet3.0(Spring注解版):
8.2.4 Shared libraries / runtimes pluggability:
規(guī)則:
? 1)、服務(wù)器啟動(web應(yīng)用啟動)會創(chuàng)建當(dāng)前web應(yīng)用里面每一個jar包里面ServletContainerInitializer實(shí)例:
?
2)际长、ServletContainerInitializer的實(shí)現(xiàn)放在jar包的META-INF/services文件夾下耸采,有一個名為javax.servlet.ServletContainerInitializer的文件,內(nèi)容就是ServletContainerInitializer的實(shí)現(xiàn)類的全類名
? 3)工育、還可以使用@HandlesTypes虾宇,在應(yīng)用啟動的時候加載我們感興趣的類;
流程:
1)如绸、啟動Tomcat
2)嘱朽、org\springframework\spring-web\4.3.14.RELEASE\spring-web-4.3.14.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer:
Spring的web模塊里面有這個文件:org.springframework.web.SpringServletContainerInitializer
3)旭贬、SpringServletContainerInitializer將@HandlesTypes(WebApplicationInitializer.class)標(biāo)注的所有這個類型的類都傳入到onStartup方法的Set<Class<?>>;為這些WebApplicationInitializer類型的類創(chuàng)建實(shí)例搪泳;
4)稀轨、每一個WebApplicationInitializer都調(diào)用自己的onStartup;
5)岸军、相當(dāng)于我們的SpringBootServletInitializer的類會被創(chuàng)建對象奋刽,并執(zhí)行onStartup方法
6)、SpringBootServletInitializer實(shí)例執(zhí)行onStartup的時候會createRootApplicationContext艰赞;創(chuàng)建容器
protectedWebApplicationContextcreateRootApplicationContext(
? ? ServletContext
servletContext){//1杨名、創(chuàng)建SpringApplicationBuilderSpringApplicationBuilder
builder = createSpringApplicationBuilder();?? StandardServletEnvironment
environment =newStandardServletEnvironment();??
environment.initPropertySources(servletContext,null);??
builder.environment(environment);?? builder.main(getClass());??
ApplicationContext parent =
getExistingRootWebApplicationContext(servletContext);if(parent !=null)
{this.logger.info("Root context already created (using as parent).");? ?
? servletContext.setAttribute(? ? ? ? ? ?
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,null);? ? ?
builder.initializers(newParentContextApplicationContextInitializer(parent));?
? }??
builder.initializers(newServletContextApplicationContextInitializer(servletContext));?
builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);//調(diào)用configure方法,子類重寫了這個方法猖毫,將SpringBoot的主程序類傳入了進(jìn)來builder
= configure(builder);//使用builder創(chuàng)建一個Spring應(yīng)用SpringApplication
application = builder.build();if(application.getSources().isEmpty()
&& AnnotationUtils? ? ? ?? .findAnnotation(getClass(),
Configuration.class) !=null) {? ? ?
application.getSources().add(getClass());?? }??
Assert.state(!application.getSources().isEmpty(),"No SpringApplication
sources have been defined. Either override the "+"configure method or
add an @Configuration annotation");// Ensure error pages are
registeredif(this.registerErrorPageFilter) {? ? ?
application.getSources().add(ErrorPageFilterConfiguration.class);??
}//啟動Spring應(yīng)用returnrun(application);}
7)台谍、Spring的應(yīng)用就啟動并且創(chuàng)建IOC容器
publicConfigurableApplicationContextrun(String...
args){?? StopWatch stopWatch =newStopWatch();?? stopWatch.start();??
ConfigurableApplicationContext context =null;?? FailureAnalyzers
analyzers =null;?? configureHeadlessProperty();??
SpringApplicationRunListeners listeners = getRunListeners(args);??
listeners.starting();try{? ? ? ApplicationArguments applicationArguments
=newDefaultApplicationArguments(? ? ? ? ? ? args);? ? ?
ConfigurableEnvironment environment = prepareEnvironment(listeners,? ? ?
? ? ? applicationArguments);? ? ? Banner printedBanner =
printBanner(environment);? ? ? context = createApplicationContext();? ? ?
analyzers =newFailureAnalyzers(context);? ? ? prepareContext(context,
environment, listeners, applicationArguments,? ? ? ? ? ?
printedBanner);//刷新IOC容器refreshContext(context);? ? ?
afterRefresh(context, applicationArguments);? ? ?
listeners.finished(context,null);? ? ?
stopWatch.stop();if(this.logStartupInfo)
{newStartupInfoLogger(this.mainApplicationClass)? ? ? ? ? ? ??
.logStarted(getApplicationLog(), stopWatch);? ? ? }returncontext;??
}catch(Throwable ex) {? ? ? handleRunFailure(context, listeners,
analyzers, ex);thrownewIllegalStateException(ex);?? }}
==啟動Servlet容器,再啟動SpringBoot應(yīng)用==
五吁断、Docker
1趁蕊、簡介
Docker是一個開源的應(yīng)用容器引擎;是一個輕量級容器技術(shù)仔役;
Docker支持將軟件編譯成一個鏡像掷伙;然后在鏡像中各種軟件做好配置,將鏡像發(fā)布出去又兵,其他使用者可以直接使用這個鏡像任柜;
運(yùn)行中的這個鏡像稱為容器,容器啟動是非撑娉快速的宙地。
2、核心概念
docker主機(jī)(Host):安裝了Docker程序的機(jī)器(Docker直接安裝在操作系統(tǒng)之上)逆皮;
docker客戶端(Client):連接docker主機(jī)進(jìn)行操作宅粥;
docker倉庫(Registry):用來保存各種打包好的軟件鏡像;
docker鏡像(Images):軟件打包好的鏡像电谣;放在docker倉庫中秽梅;
docker容器(Container):鏡像啟動后的實(shí)例稱為一個容器;容器是獨(dú)立運(yùn)行的一個或一組應(yīng)用
使用Docker的步驟:
1)剿牺、安裝Docker
2)企垦、去Docker倉庫找到這個軟件對應(yīng)的鏡像;
3)晒来、使用Docker運(yùn)行這個鏡像钞诡,這個鏡像就會生成一個Docker容器;
4)、對容器的啟動停止就是對軟件的啟動停止臭增;
3懂酱、安裝Docker
1)、安裝linux虛擬機(jī)
? 1)誊抛、VMWare列牺、VirtualBox(安裝);
? 2)拗窃、導(dǎo)入虛擬機(jī)文件centos7-atguigu.ova瞎领;
? 3)、雙擊啟動linux虛擬機(jī);使用 root/ 123456登陸
? 4)随夸、使用客戶端連接linux服務(wù)器進(jìn)行命令操作九默;
? 5)、設(shè)置虛擬機(jī)網(wǎng)絡(luò)宾毒;
? 橋接網(wǎng)絡(luò)===選好網(wǎng)卡====接入網(wǎng)線驼修;
? 6)、設(shè)置好網(wǎng)絡(luò)以后使用命令重啟虛擬機(jī)的網(wǎng)絡(luò)
service network restart
? 7)诈铛、查看linux的ip地址
ip addr
? 8)乙各、使用客戶端連接linux;
2)幢竹、在linux虛擬機(jī)上安裝docker
步驟:
1耳峦、檢查內(nèi)核版本,必須是3.10及以上
uname -r
2焕毫、安裝docker
yum install docker
3蹲坷、輸入y確認(rèn)安裝
4、啟動docker
[root@localhost ~]# systemctl start docker
[root@localhost ~]# docker -v
Docker version 1.12.6, build 3e8e77d/1.12.6
5邑飒、開機(jī)啟動docker
[root@localhost ~]# systemctl enable docker
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
6循签、停止docker
systemctl stop docker
4、Docker常用命令&操作
1)幸乒、鏡像操作
操作命令說明
檢索docker search 關(guān)鍵字 eg:docker search redis我們經(jīng)常去docker hub上檢索鏡像的詳細(xì)信息懦底,如鏡像的TAG。
拉取docker pull 鏡像名:tag:tag是可選的罕扎,tag表示標(biāo)簽,多為軟件的版本丐重,默認(rèn)是latest
列表docker images查看所有本地鏡像
刪除docker rmi image-id刪除指定的本地鏡像
2)腔召、容器操作
軟件鏡像(QQ安裝程序)----運(yùn)行鏡像----產(chǎn)生一個容器(正在運(yùn)行的軟件,運(yùn)行的QQ)扮惦;
步驟:
1臀蛛、搜索鏡像
[root@localhost ~]# docker search tomcat
2、拉取鏡像
[root@localhost ~]# docker pull tomcat
3、根據(jù)鏡像啟動容器
docker run --name mytomcat -d tomcat:latest
4浊仆、docker ps?
查看運(yùn)行中的容器
5客峭、 停止運(yùn)行中的容器
docker stop? 容器的id
6、查看所有的容器
docker ps -a
7抡柿、啟動容器
docker start 容器id
8舔琅、刪除一個容器
docker rm 容器id
9、啟動一個做了端口映射的tomcat
[root@localhost ~]# docker run -d -p 8888:8080 tomcat
-d:后臺運(yùn)行
-p: 將主機(jī)的端口映射到容器的一個端口? ? 主機(jī)端口:容器內(nèi)部的端口
10洲劣、為了演示簡單關(guān)閉了linux的防火墻
service firewalld status 备蚓;查看防火墻狀態(tài)
service firewalld stop:關(guān)閉防火墻
11、查看容器的日志
docker logs container-name/container-id
更多命令參看
https://docs.docker.com/engine/reference/commandline/docker/
可以參考每一個鏡像的文檔
3)囱稽、安裝MySQL示例
docker pull mysql
錯誤的啟動
[root@localhost ~]# docker run --name mysql01 -d mysql
42f09819908bb72dd99ae19e792e0a5d03c48638421fa64cce5f8ba0f40f5846
mysql退出了
[root@localhost ~]# docker ps -a
CONTAINER
ID? ? ? ? IMAGE? ? ? ? ? ? ?? COMMAND? ? ? ? ? ? ? ? ? CREATED? ? ? ? ?
?? STATUS? ? ? ? ? ? ? ? ? ? ? ? ?? PORTS? ? ? ? ? ? ?? NAMES
42f09819908b?
? ? ? mysql? ? ? ? ? ? ?? "docker-entrypoint.sh"?? 34 seconds ago? ? ?
Exited (1) 33 seconds ago? ? ? ? ? ? ? ? ? ? ? ? ? ? mysql01
538bde63e500?
? ? ? tomcat? ? ? ? ? ? ? "catalina.sh run"? ? ? ? About an hour ago??
Exited (143) About an hour ago? ? ? ? ? ? ? ? ? ? ?? compassionate_
goldstine
c4f1ac60b3fc?
? ? ? tomcat? ? ? ? ? ? ? "catalina.sh run"? ? ? ? About an hour ago??
Exited (143) About an hour ago? ? ? ? ? ? ? ? ? ? ?? lonely_fermi
81ec743a5271?
? ? ? tomcat? ? ? ? ? ? ? "catalina.sh run"? ? ? ? About an hour ago??
Exited (143) About an hour ago? ? ? ? ? ? ? ? ? ? ?? sick_ramanujan
//錯誤日志
[root@localhost ~]# docker logs 42f09819908b
error: database is uninitialized and password option is not specified
? You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD郊尝;這個三個參數(shù)必須指定一個
正確的啟動
[root@localhost ~]# docker run --name mysql01 -e MYSQL_ROOT_PASSWORD=123456 -d mysql
b874c56bec49fb43024b3805ab51e9097da779f2f572c22c695305dedd684c5f
[root@localhost ~]# docker ps
CONTAINER
ID? ? ? ? IMAGE? ? ? ? ? ? ?? COMMAND? ? ? ? ? ? ? ? ? CREATED? ? ? ? ?
?? STATUS? ? ? ? ? ? ? PORTS? ? ? ? ? ? ?? NAMES
b874c56bec49? ? ?
? mysql? ? ? ? ? ? ?? "docker-entrypoint.sh"?? 4 seconds ago? ? ?? Up 3
seconds? ? ? ? 3306/tcp? ? ? ? ? ? mysql01
做了端口映射
[root@localhost ~]# docker run -p 3306:3306 --name mysql02 -e MYSQL_ROOT_PASSWORD=123456 -d mysql
ad10e4bc5c6a0f61cbad43898de71d366117d120e39db651844c0e73863b9434
[root@localhost ~]# docker ps
CONTAINER
ID? ? ? ? IMAGE? ? ? ? ? ? ?? COMMAND? ? ? ? ? ? ? ? ? CREATED? ? ? ? ?
?? STATUS? ? ? ? ? ? ? PORTS? ? ? ? ? ? ? ? ? ? NAMES
ad10e4bc5c6a?
? ? ? mysql? ? ? ? ? ? ?? "docker-entrypoint.sh"?? 4 seconds ago? ? ??
Up 2 seconds? ? ? ? 0.0.0.0:3306->3306/tcp?? mysql02
幾個其他的高級操作
docker run --name mysql03 -v /conf/mysql:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
把主機(jī)的/conf/mysql文件夾掛載到 mysqldocker容器的/etc/mysql/conf.d文件夾里面
改mysql的配置文件就只需要把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的一些配置參數(shù)
六、SpringBoot與數(shù)據(jù)訪問
1战惊、JDBC
org.springframework.bootspring-boot-starter-jdbcmysqlmysql-connector-javaruntime
spring:?
datasource:? ? username:root? ? password:123456? ?
url:jdbc:mysql://192.168.15.22:3306/jdbc? ?
driver-class-name:com.mysql.jdbc.Driver
效果:
? 默認(rèn)是用org.apache.tomcat.jdbc.pool.DataSource作為數(shù)據(jù)源流昏;
? 數(shù)據(jù)源的相關(guān)配置都在DataSourceProperties里面;
自動配置原理:
org.springframework.boot.autoconfigure.jdbc:
1吞获、參考DataSourceConfiguration况凉,根據(jù)配置創(chuàng)建數(shù)據(jù)源,默認(rèn)使用Tomcat連接池衫哥;可以使用spring.datasource.type指定自定義的數(shù)據(jù)源類型茎刚;
2、SpringBoot默認(rèn)可以支持撤逢;
org.apache.tomcat.jdbc.pool.DataSource膛锭、HikariDataSource、BasicDataSource蚊荣、
3初狰、自定義數(shù)據(jù)源類型
/**
* Generic DataSource configuration.
*/@ConditionalOnMissingBean(DataSource.class)@ConditionalOnProperty(name
="spring.datasource.type")staticclassGeneric{@BeanpublicDataSourcedataSource(DataSourceProperties
properties){//使用DataSourceBuilder創(chuàng)建數(shù)據(jù)源,利用反射創(chuàng)建響應(yīng)type的數(shù)據(jù)源互例,并且綁定相關(guān)屬性returnproperties.initializeDataSourceBuilder().build();?
? }}
4奢入、DataSourceInitializer:ApplicationListener;
? 作用:
? 1)媳叨、runSchemaScripts();運(yùn)行建表語句腥光;
? 2)、runDataScripts();運(yùn)行插入數(shù)據(jù)的sql語句糊秆;
默認(rèn)只需要將文件命名為:
schema-*.sql武福、data-*.sql
默認(rèn)規(guī)則:schema.sql,schema-all.sql痘番;
可以使用??
schema:
? ? ? - classpath:department.sql
? ? ? 指定位置
5捉片、操作數(shù)據(jù)庫:自動配置了JdbcTemplate操作數(shù)據(jù)庫
2平痰、整合Druid數(shù)據(jù)源
導(dǎo)入druid數(shù)據(jù)源@ConfigurationpublicclassDruidConfig{@ConfigurationProperties(prefix
="spring.datasource")@BeanpublicDataSourcedruid(){returnnewDruidDataSource();?
}//配置Druid的監(jiān)控//1、配置一個管理后臺的Servlet@BeanpublicServletRegistrationBeanstatViewServlet(){?
? ? ? ServletRegistrationBean bean
=newServletRegistrationBean(newStatViewServlet(),"/druid/*");? ? ? ?
MapinitParams =newHashMap<>();? ? ? ?
initParams.put("loginUsername","admin");? ? ? ?
initParams.put("loginPassword","123456");? ? ? ?
initParams.put("allow","");//默認(rèn)就是允許所有訪問initParams.put("deny","192.168.15.21");?
? ? ? bean.setInitParameters(initParams);returnbean;? ?
}//2伍纫、配置一個web監(jiān)控的filter@BeanpublicFilterRegistrationBeanwebStatFilter(){? ?
? ? FilterRegistrationBean bean =newFilterRegistrationBean();? ? ? ?
bean.setFilter(newWebStatFilter());? ? ? ? Map initParams
=newHashMap<>();? ? ? ?
initParams.put("exclusions","*.js,*.css,/druid/*");? ? ? ?
bean.setInitParameters(initParams);? ? ? ?
bean.setUrlPatterns(Arrays.asList("/*"));returnbean;? ? }}
3宗雇、整合MyBatis
org.mybatis.spring.bootmybatis-spring-boot-starter1.3.1
步驟:
? 1)、配置數(shù)據(jù)源相關(guān)屬性(見上一節(jié)Druid)
? 2)莹规、給數(shù)據(jù)庫建表
? 3)赔蒲、創(chuàng)建JavaBean
4)、注解版
//指定這是一個操作數(shù)據(jù)庫的mapper@MapperpublicinterfaceDepartmentMapper{@Select("select
* from department where id=#{id}")publicDepartmentgetDeptById(Integer
id);@Delete("delete from department where
id=#{id}")publicintdeleteDeptById(Integer id);@Options(useGeneratedKeys
=true,keyProperty ="id")@Insert("insert into department(departmentName)
values(#{departmentName})")publicintinsertDept(Department
department);@Update("update department set
departmentName=#{departmentName} where
id=#{id}")publicintupdateDept(Department department);}
問題:
自定義MyBatis的配置規(guī)則访惜;給容器中添加一個ConfigurationCustomizer嘹履;
@org.springframework.context.annotation.ConfigurationpublicclassMyBatisConfig{@BeanpublicConfigurationCustomizerconfigurationCustomizer(){returnnewConfigurationCustomizer(){@Overridepublicvoidcustomize(Configuration
configuration){? ? ? ? ? ? ? ?
configuration.setMapUnderscoreToCamelCase(true);? ? ? ? ? ? }? ? ? ? };?
? }}
使用MapperScan批量掃描所有的Mapper接口;@MapperScan(value
="com.atguigu.springboot.mapper")@SpringBootApplicationpublicclassSpringBoot06DataMybatisApplication{publicstaticvoidmain(String[]
args){SpringApplication.run(SpringBoot06DataMybatisApplication.class,
args);}}
5)债热、配置文件版
mybatis:?
config-location:classpath:mybatis/mybatis-config.xml指定全局配置文件的位置?
mapper-locations:classpath:mybatis/mapper/*.xml指定sql映射文件的位置
更多使用參照
http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/
4砾嫉、整合SpringData JPA
1)、SpringData簡介
2)窒篱、整合SpringData JPA
JPA:ORM(Object Relational Mapping)焕刮;
1)、編寫一個實(shí)體類(bean)和數(shù)據(jù)表進(jìn)行映射墙杯,并且配置好映射關(guān)系配并;
//使用JPA注解配置映射關(guān)系@Entity//告訴JPA這是一個實(shí)體類(和數(shù)據(jù)表映射的類)@Table(name
="tbl_user")//@Table來指定和哪個數(shù)據(jù)表對應(yīng);如果省略默認(rèn)表名就是user;publicclassUser{@Id//這是一個主鍵@GeneratedValue(strategy
= GenerationType.IDENTITY)//自增主鍵privateInteger id;@Column(name
="last_name",length =50)//這是和數(shù)據(jù)表對應(yīng)的一個列privateString
lastName;@Column//省略默認(rèn)列名就是屬性名privateString email;
2)高镐、編寫一個Dao接口來操作實(shí)體類對應(yīng)的數(shù)據(jù)表(Repository)
//繼承JpaRepository來完成對數(shù)據(jù)庫的操作publicinterfaceUserRepositoryextendsJpaRepository{}
3)溉旋、基本的配置JpaProperties
spring: jpa:? ? hibernate:#? ?? 更新或者創(chuàng)建數(shù)據(jù)表結(jié)構(gòu)? ? ? ddl-auto:update#? ? 控制臺顯示SQL? ? show-sql:true
七、啟動配置原理
幾個重要的事件回調(diào)機(jī)制
配置在META-INF/spring.factories
ApplicationContextInitializer
SpringApplicationRunListener
只需要放在ioc容器中
ApplicationRunner
CommandLineRunner
啟動流程:
1嫉髓、創(chuàng)建SpringApplication對象
initialize(sources);privatevoidinitialize(Object[]
sources){//保存主配置類if(sources !=null&& sources.length >0)
{this.sources.addAll(Arrays.asList(sources));? ?
}//判斷當(dāng)前是否一個web應(yīng)用this.webEnvironment =
deduceWebEnvironment();//從類路徑下找到META-INF/spring.factories配置的所有ApplicationContextInitializer观腊;然后保存起來setInitializers((Collection)
getSpringFactoriesInstances(? ? ? ?
ApplicationContextInitializer.class));//從類路徑下找到ETA-INF/spring.factories配置的所有ApplicationListenersetListeners((Collection)
getSpringFactoriesInstances(ApplicationListener.class));//從多個配置類中找到有main方法的主配置類this.mainApplicationClass
= deduceMainApplicationClass();}
2、運(yùn)行run方法
publicConfigurableApplicationContextrun(String...
args){?? StopWatch stopWatch =newStopWatch();?? stopWatch.start();??
ConfigurableApplicationContext context =null;?? FailureAnalyzers
analyzers =null;??
configureHeadlessProperty();//獲取SpringApplicationRunListeners算行;從類路徑下META-INF/spring.factoriesSpringApplicationRunListeners
listeners =
getRunListeners(args);//回調(diào)所有的獲取SpringApplicationRunListener.starting()方法listeners.starting();try{//封裝命令行參數(shù)ApplicationArguments
applicationArguments =newDefaultApplicationArguments(? ? ? ? ? ?
args);//準(zhǔn)備環(huán)境ConfigurableEnvironment environment =
prepareEnvironment(listeners,? ? ? ? ? ?
applicationArguments);//創(chuàng)建環(huán)境完成后回調(diào)SpringApplicationRunListener.environmentPrepared()梧油;表示環(huán)境準(zhǔn)備完成Banner
printedBanner =
printBanner(environment);//創(chuàng)建ApplicationContext;決定創(chuàng)建web的ioc還是普通的ioccontext
= createApplicationContext();? ? ? ? ? ?? analyzers
=newFailureAnalyzers(context);//準(zhǔn)備上下文環(huán)境;將environment保存到ioc中州邢;而且applyInitializers()儡陨;//applyInitializers():回調(diào)之前保存的所有的ApplicationContextInitializer的initialize方法//回調(diào)所有的SpringApplicationRunListener的contextPrepared();//prepareContext(context,
environment, listeners, applicationArguments,? ? ? ? ? ?
printedBanner);//prepareContext運(yùn)行完成以后回調(diào)所有的SpringApplicationRunListener的contextLoaded()量淌;//s刷新容器骗村;ioc容器初始化(如果是web應(yīng)用還會創(chuàng)建嵌入式的Tomcat);Spring注解版//掃描呀枢,創(chuàng)建叙身,加載所有組件的地方;(配置類硫狞,組件,自動配置)refreshContext(context);//從ioc容器中獲取所有的ApplicationRunner和CommandLineRunner進(jìn)行回調(diào)//ApplicationRunner先回調(diào),CommandLineRunner再回調(diào)afterRefresh(context,
applicationArguments);//所有的SpringApplicationRunListener回調(diào)finished方法listeners.finished(context,null);?
? ? stopWatch.stop();if(this.logStartupInfo)
{newStartupInfoLogger(this.mainApplicationClass)? ? ? ? ? ? ??
.logStarted(getApplicationLog(), stopWatch);? ? ?
}//整個SpringBoot應(yīng)用啟動完成以后返回啟動的ioc容器残吩;returncontext;?? }catch(Throwable ex)
{? ? ? handleRunFailure(context, listeners, analyzers,
ex);thrownewIllegalStateException(ex);?? }}
3财忽、事件監(jiān)聽機(jī)制
配置在META-INF/spring.factories
ApplicationContextInitializer
publicclassHelloApplicationContextInitializerimplementsApplicationContextInitializer{@Overridepublicvoidinitialize(ConfigurableApplicationContext
applicationContext){? ? ? ?
System.out.println("ApplicationContextInitializer...initialize..."+applicationContext);?
? }}
SpringApplicationRunListener
publicclassHelloSpringApplicationRunListenerimplementsSpringApplicationRunListener{//必須有的構(gòu)造器publicHelloSpringApplicationRunListener(SpringApplication
application, String[] args){? ? }@Overridepublicvoidstarting(){? ? ? ?
System.out.println("SpringApplicationRunListener...starting...");? ?
}@OverridepublicvoidenvironmentPrepared(ConfigurableEnvironment
environment){? ? ? ? Object o =
environment.getSystemProperties().get("os.name");? ? ? ?
System.out.println("SpringApplicationRunListener...environmentPrepared.."+o);?
? }@OverridepublicvoidcontextPrepared(ConfigurableApplicationContext
context){? ? ? ?
System.out.println("SpringApplicationRunListener...contextPrepared...");?
? }@OverridepublicvoidcontextLoaded(ConfigurableApplicationContext
context){? ? ? ?
System.out.println("SpringApplicationRunListener...contextLoaded...");? ?
}@Overridepublicvoidfinished(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
@ComponentpublicclassHelloApplicationRunnerimplementsApplicationRunner{@Overridepublicvoidrun(ApplicationArguments
args)throwsException{? ? ? ?
System.out.println("ApplicationRunner...run....");? ? }}
CommandLineRunner
@ComponentpublicclassHelloCommandLineRunnerimplementsCommandLineRunner{@Overridepublicvoidrun(String...
args)throwsException{? ? ? ?
System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));? ?
}}
八、自定義starter
starter:
? 1泣侮、這個場景需要使用到的依賴是什么即彪?
? 2、如何編寫自動配置
@Configuration//指定這個類是一個配置類@ConditionalOnXXX//在指定條件成立的情況下自動配置類生效@AutoConfigureAfter//指定自動配置類的順序@Bean//給容器中添加組件@ConfigurationPropertie結(jié)合相關(guān)xxxProperties類來綁定相關(guān)的配置@EnableConfigurationProperties//讓xxxProperties生效加入到容器中自動配置類要能加載將需要啟動就加載的自動配置類活尊,配置在META-INF/spring.factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
? 3隶校、模式:
啟動器只用來做依賴導(dǎo)入;
專門來寫一個自動配置模塊蛹锰;
啟動器依賴自動配置深胳;別人只需要引入啟動器(starter)
mybatis-spring-boot-starter;自定義啟動器名-spring-boot-starter
步驟:
1)铜犬、啟動器模塊
4.0.0com.atguigu.starteratguigu-spring-boot-starter1.0-SNAPSHOTcom.atguigu.starteratguigu-spring-boot-starter-autoconfigurer0.0.1-SNAPSHOT
2)舞终、自動配置模塊
4.0.0com.atguigu.starteratguigu-spring-boot-starter-autoconfigurer0.0.1-SNAPSHOTjaratguigu-spring-boot-starter-autoconfigurerDemo
project for Spring
Bootorg.springframework.bootspring-boot-starter-parent1.5.10.RELEASE<!--
lookup parent from repository -->UTF-8UTF-81.8org.springframework.bootspring-boot-starter
packagecom.atguigu.starter;importorg.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix
="atguigu.hello")publicclassHelloProperties{privateString
prefix;privateString suffix;publicStringgetPrefix(){returnprefix;? ?
}publicvoidsetPrefix(String prefix){this.prefix = prefix;? ?
}publicStringgetSuffix(){returnsuffix;? ? }publicvoidsetSuffix(String
suffix){this.suffix = suffix;? ? }}
packagecom.atguigu.starter;publicclassHelloService{?
? HelloProperties
helloProperties;publicHelloPropertiesgetHelloProperties(){returnhelloProperties;?
? }publicvoidsetHelloProperties(HelloProperties
helloProperties){this.helloProperties = helloProperties;? ?
}publicStringsayHellAtguigu(String
name){returnhelloProperties.getPrefix()+"-"+name +
helloProperties.getSuffix();? ? }}
packagecom.atguigu.starter;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;importorg.springframework.boot.context.properties.EnableConfigurationProperties;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@Configuration@ConditionalOnWebApplication//web應(yīng)用才生效@EnableConfigurationProperties(HelloProperties.class)publicclassHelloServiceAutoConfiguration{@AutowiredHelloProperties
helloProperties;@BeanpublicHelloServicehelloService(){? ? ? ?
HelloService service =newHelloService();? ? ? ?
service.setHelloProperties(helloProperties);returnservice;? ? }}