当前位置:首页 > 软件开发 > 正文

throwable exception?SpringBoot是如何动起来的

throwable exception?SpringBoot是如何动起来的

各位老铁们好,相信很多人对throwable exception都不是特别的了解,因此呢,今天就来为大家分享下关于throwable exception以及Spring...

各位老铁们好,相信很多人对throwable exception都不是特别的了解,因此呢,今天就来为大家分享下关于throwable exception以及SpringBoot是如何动起来的的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!

java web项目中如何优雅的处理异常

如果Java方法不能按照正常的流程执行,那么可以通过另外一种途径退出:抛出一个封装了错误信息的对象,这个就是Java的异常;当发生异常时,后面的代码无法继续执行,而是由异常处理器继续执行。

01.异常的分类

Throwable是所有异常的超类,下一级可以分为Error和Exception:

1.Error

Error是指Java运行时系统内部的错误,或者说它代表了JVM本身的错误,通常都是比较严重的错误,比如内存溢出,虚拟机错误等等;

Error通常和硬件或JVM有关,和程序本身无关,所以不能被代码捕获和处理。

2.Exception

我们经常说的异常是指Exception,又可以分成运行时异常和检查异常。

RuntimeException:运行时异常,这类异常在编译期间不强制代码捕捉,但是可能在在JVM运行期间抛出异常;出现此类异常,通常是代码的问题,所以需要修改程序避免这类异常。常见的运行时异常,比如:NullPointerException、ClassCastException等等。

CheckedException:检查异常,这种异常发生在编译阶段,Java编译器会强制代码去捕获和处理此类异常;比如:ClassNotFoundException、IllegalAccessException等等。

02.异常的处理方法

捕获异常使用try...catch语句,把可能发生异常的代码放到try{...}中,然后使用catch捕获对应的异常;

我们也可以在代码块中使用Throw向上级代码抛出异常;

在方法中使用throws关键字,向上级代码抛出异常;

03.Throw和throws的区别

Throw在方法内,后面跟着异常对象;而throws是用在方法上,后面跟异常类;

Throw会抛出具体的异常对象,当执行到Throw的时候,方法内的代码也就执行结束了;throws用来声明异常,提醒调用方这个方法可能会出现这种异常,请做好处理的准备,但是不一定会真的出现异常。

04.如何优雅地处理异常

不要试图通过异常来控制程序流程,比如开发一个接口,正确的做法是对入参进行非空验证,当参数为空的时候返回“参数不允许为空”,而不应该捕捉到空指针的时候返回错误提示。

仅捕获有必要的代码,尽量不要用一个try...catch包住大段甚至整个方法内所有的代码,因为这样会影响JVM对代码进行优化,从而带来额外的性能开销。

很多程序员喜欢catch(Exceptione),其实应该尽可能地精确地指出是什么异常。

不要忽略异常,捕捉到异常之后千万不能什么也不做,要么在catch{...}中输出异常信息,要么通过Throw或throws抛出异常,让上层代码处理。

尽量不要在catch{...}中输出异常后,又向上层代码抛出异常,因为这样会输出多条异常信息,而且它们还是相同的,这样可能会产生误导。

不要在finally{...}中写return,因为try{...}在执行return之前执行finally{...},如果finally{...}中有return,那么将不再执行try{...}中的return。

我将持续分享Java开发、架构设计、程序员职业发展等方面的见解,希望能得到你的关注。

SpringBoot是如何动起来的

程序入口

SpringApplication.run(BeautyApplication.class,args);

执行此方法来加载整个SpringBoot的环境。

1.从哪儿开始?

SpringApplication.java

/**

*RuntheSpringapplication,creatingandrefreshinganew

*{@linkApplicationContext}.

*@paramargstheapplicationarguments(usuallypassedfromaJavamainmethod)

*@returnarunning{@linkApplicationContext}

*/

publicConfigurableApplicationContextrun(String...args){

//...

}

调用SpringApplication.java中的run方法,目的是加载SpringApplication,同时返回ApplicationContext。

2.执行了什么?

2.1计时

记录整个SpringApplication的加载时间!

StopWatchstopWatch=newStopWatch();

stopWatch.start();

//...

stopWatch.stop();

if(this.logStartupInfo){

newStartupInfoLogger(this.mainApplicationClass)

.logStarted(getApplicationLog(),stopWatch);

}

2.2声明

指定java.awt.headless,默认是true一般是在程序开始激活headless模式,告诉程序,现在你要工作在Headlessmode下,就不要指望硬件帮忙了,你得自力更生,依靠系统的计算能力模拟出这些特性来。

privatevoidconfigureHeadlessProperty(){

System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,System.getProperty(

SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,Boolean.toString(this.headless)));

}

2.4配置监听并发布应用启动事件

SpringApplicationRunListener负责加载ApplicationListener事件。

SpringApplicationRunListenerslisteners=getRunListeners(args);

//开始

listeners.starting();

//处理所有propertysources配置和profiles配置,准备环境,分为标准Servlet环境和标准环境

ConfigurableEnvironmentenvironment=prepareEnvironment(listeners,applicationArguments);

//准备应用上下文

prepareContext(context,environment,listeners,applicationArguments,printedBanner);

//完成

listeners.started(context);

//异常

handleRunFailure(context,ex,exceptionReporters,listeners);

//执行

listeners.running(context);

getRunListeners中根据type=SpringApplicationRunListener.class去拿到了所有的Listener并根据优先级排序。

对应的就是META-INF/spring.factories文件中的org.springframework.boot.SpringApplicationRunListener=org.springframework.boot.context.event.EventPublishingRunListener

private<T>Collection<T>getSpringFactoriesInstances(Class<T>type,

Class<?>[]parameterTypes,Object...args){

ClassLoaderclassLoader=Thread.currentThread().getContextClassLoader();

//Usenamesandensureuniquetoprotectagainstduplicates

Set<String>names=newLinkedHashSet<>(

SpringFactoriesLoader.loadFactoryNames(type,classLoader));

List<T>instances=createSpringFactoriesInstances(type,parameterTypes,

classLoader,args,names);

AnnotationAwareOrderComparator.sort(instances);

returninstances;

}

复制代码

在ApplicationListener中,可以针对任何一个阶段插入处理代码。

publicinterfaceSpringApplicationRunListener{

/**

*Calledimmediatelywhentherunmethodhasfirststarted.Canbeusedforvery

*earlyinitialization.

*/

voidstarting();

/**

*Calledoncetheenvironmenthasbeenprepared,butbeforethe

*{@linkApplicationContext}hasbeencreated.

*@paramenvironmenttheenvironment

*/

voidenvironmentPrepared(ConfigurableEnvironmentenvironment);

/**

*Calledoncethe{@linkApplicationContext}hasbeencreatedandprepared,but

*beforesourceshavebeenloaded.

*@paramcontexttheapplicationcontext

*/

voidcontextPrepared(ConfigurableApplicationContextcontext);

/**

*Calledoncetheapplicationcontexthasbeenloadedbutbeforeithasbeen

*refreshed.

*@paramcontexttheapplicationcontext

*/

voidcontextLoaded(ConfigurableApplicationContextcontext);

/**

*Thecontexthasbeenrefreshedandtheapplicationhasstartedbut

*{@linkCommandLineRunnerCommandLineRunners}and{@linkApplicationRunner

*ApplicationRunners}havenotbeencalled.

*@paramcontexttheapplicationcontext.

*@since2.0.0

*/

voidstarted(ConfigurableApplicationContextcontext);

/**

*Calledimmediatelybeforetherunmethodfinishes,whentheapplicationcontexthas

*beenrefreshedandall{@linkCommandLineRunnerCommandLineRunners}and

*{@linkApplicationRunnerApplicationRunners}havebeencalled.

*@paramcontexttheapplicationcontext.

*@since2.0.0

*/

voidrunning(ConfigurableApplicationContextcontext);

/**

*Calledwhenafailureoccurswhenrunningtheapplication.

*@paramcontexttheapplicationcontextor{@codenull}ifafailureoccurredbefore

*thecontextwascreated

*@paramexceptionthefailure

*@since2.0.0

*/

voidfailed(ConfigurableApplicationContextcontext,Throwableexception);

}

3.每个阶段执行的内容

3.1listeners.starting();

在加载SpringApplication之前执行,所有资源和环境未被加载。

3.2prepareEnvironment(listeners,applicationArguments);

创建ConfigurableEnvironment;将配置的环境绑定到SpringApplication中;

privateConfigurableEnvironmentprepareEnvironment(

SpringApplicationRunListenerslisteners,

ApplicationArgumentsapplicationArguments){

//Createandconfiguretheenvironment

ConfigurableEnvironmentenvironment=getOrCreateEnvironment();

configureEnvironment(environment,applicationArguments.getSourceArgs());

listeners.environmentPrepared(environment);

bindToSpringApplication(environment);

if(this.webApplicationType==WebApplicationType.NONE){

environment=newEnvironmentConverter(getClassLoader())

.convertToStandardEnvironmentIfNecessary(environment);

}

ConfigurationPropertySources.attach(environment);

returnenvironment;

}

3.3prepareContext

配置忽略的Bean;

privatevoidconfigureIgnoreBeanInfo(ConfigurableEnvironmentenvironment){

if(System.getProperty(

CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME)==null){

Booleanignore=environment.getProperty("spring.beaninfo.ignore",

Boolean.class,Boolean.TRUE);

System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,

ignore.toString());

}

}

打印日志-加载的资源

BannerprintedBanner=printBanner(environment);

根据不同的WebApplicationType创建Context

context=createApplicationContext();

3.4refreshContext

支持定制刷新

/**

*RegisterashutdownhookwiththeJVMruntime,closingthiscontext

*onJVMshutdownunlessithasalreadybeenclosedatthattime.

*<p>Thismethodcanbecalledmultipletimes.Onlyoneshutdownhook

*(atmax)willberegisteredforeachcontextinstance.

*@seejava.lang.Runtime#addShutdownHook

*@see#close()

*/

voidregisterShutdownHook();

3.5afterRefresh

刷新后的实现方法暂未实现

/**

*Calledafterthecontexthasbeenrefreshed.

*@paramcontexttheapplicationcontext

*@paramargstheapplicationarguments

*/

protectedvoidafterRefresh(ConfigurableApplicationContextcontext,

ApplicationArgumentsargs){

}

3.6listeners.started(context);

到此为止,SpringApplication的环境和资源都加载完毕了;发布应用上下文启动完成事件;执行所有Runner运行器-执行所有ApplicationRunner和CommandLineRunner这两种运行器

//启动

callRunners(context,applicationArguments);

3.7listeners.running(context);

触发所有SpringApplicationRunListener监听器的running事件方法

希望对你有帮助

好了,关于throwable exception和SpringBoot是如何动起来的的问题到这里结束啦,希望可以解决您的问题哈!

最新文章