08 CRUD

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刪除指定的本地鏡像

https://hub.docker.com/

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;? ? }}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市癣猾,隨后出現(xiàn)的幾起案子敛劝,更是在濱河造成了極大的恐慌,老刑警劉巖纷宇,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夸盟,死亡現(xiàn)場離奇詭異,居然都是意外死亡像捶,警方通過查閱死者的電腦和手機(jī)上陕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來作岖,“玉大人唆垃,你說我怎么就攤上這事《焕埽” “怎么了辕万?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沉删。 經(jīng)常有香客問我渐尿,道長,這世上最難降的妖魔是什么矾瑰? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任砖茸,我火速辦了婚禮,結(jié)果婚禮上殴穴,老公的妹妹穿的比我還像新娘凉夯。我一直安慰自己货葬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布劲够。 她就那樣靜靜地躺著震桶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪征绎。 梳的紋絲不亂的頭發(fā)上蹲姐,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機(jī)與錄音人柿,去河邊找鬼柴墩。 笑死,一個胖子當(dāng)著我的面吹牛凫岖,可吹牛的內(nèi)容都是我干的江咳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼隘截,長吁一口氣:“原來是場噩夢啊……” “哼扎阶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起婶芭,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤东臀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后犀农,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惰赋,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年呵哨,在試婚紗的時候發(fā)現(xiàn)自己被綠了赁濒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡孟害,死狀恐怖拒炎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挨务,我是刑警寧澤击你,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站谎柄,受9級特大地震影響丁侄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜朝巫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一鸿摇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧劈猿,春花似錦拙吉、人聲如沸潮孽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恩商。三九已至,卻和暖如春必逆,著一層夾襖步出監(jiān)牢的瞬間听系,已是汗流浹背岭接。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留污尉,地道東北人凰棉。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓损拢,卻偏偏與公主長得像,于是被迫代替她去往敵國和親撒犀。 傳聞我的和親對象是個殘疾皇子福压,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容