错误处理原理(自动配置解析篇)

ErrorMvcAutoConfiguration里自动配置了异常处理规则。

DefaultErrorAttributes

ErrorMvcAutoConfiguration往容器中放入了一个DefaultErrorAttributes类型的组件,组件id为errorAttributes(即方法名为组件id)。

@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
	return new DefaultErrorAttributes();
}

DefaultErrorAttributes决定了响应中会包含哪些内容,如status、error、path、timestamp等。
DefaultErrorAttributes也实现了接口类HandlerExceptionResolver,因此也是一个处理器异常解析器

public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered {

	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception ex) {
		storeErrorAttributes(request, ex);
		return null;
	}

	private void storeErrorAttributes(HttpServletRequest request, Exception ex) {
		request.setAttribute(ERROR_INTERNAL_ATTRIBUTE, ex);
	}

	@Override
	public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
		Map<String, Object> errorAttributes = getErrorAttributes(webRequest, options.isIncluded(Include.STACK_TRACE));
		if (!options.isIncluded(Include.EXCEPTION)) {
			errorAttributes.remove("exception");
		}
		if (!options.isIncluded(Include.STACK_TRACE)) {
			errorAttributes.remove("trace");
		}
		if (!options.isIncluded(Include.MESSAGE) && errorAttributes.get("message") != null) {
			errorAttributes.remove("message");
		}
		if (!options.isIncluded(Include.BINDING_ERRORS)) {
			errorAttributes.remove("errors");
		}
		return errorAttributes;
	}

	private Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
		Map<String, Object> errorAttributes = new LinkedHashMap<>();
		errorAttributes.put("timestamp", new Date());
		addStatus(errorAttributes, webRequest);
		addErrorDetails(errorAttributes, webRequest, includeStackTrace);
		addPath(errorAttributes, webRequest);
		return errorAttributes;
	}

	private void addStatus(Map<String, Object> errorAttributes, RequestAttributes requestAttributes) {
		Integer status = getAttribute(requestAttributes, RequestDispatcher.ERROR_STATUS_CODE);
		if (status == null) {
			errorAttributes.put("status", 999);
			errorAttributes.put("error", "None");
			return;
		}
		errorAttributes.put("status", status);
		try {
			errorAttributes.put("error", HttpStatus.valueOf(status).getReasonPhrase());
		}
		catch (Exception ex) {
			// Unable to obtain a reason
			errorAttributes.put("error", "Http Status " + status);
		}
	}

	private void addErrorDetails(Map<String, Object> errorAttributes, WebRequest webRequest,
			boolean includeStackTrace) {
		Throwable error = getError(webRequest);
		if (error != null) {
			while (error instanceof ServletException && error.getCause() != null) {
				error = error.getCause();
			}
			errorAttributes.put("exception", error.getClass().getName());
			if (includeStackTrace) {
				addStackTrace(errorAttributes, error);
			}
		}
		addErrorMessage(errorAttributes, webRequest, error);
	}

	private void addErrorMessage(Map<String, Object> errorAttributes, WebRequest webRequest, Throwable error) {
		BindingResult result = extractBindingResult(error);
		if (result == null) {
			addExceptionErrorMessage(errorAttributes, webRequest, error);
		}
		else {
			addBindingResultErrorMessage(errorAttributes, result);
		}
	}

	private void addExceptionErrorMessage(Map<String, Object> errorAttributes, WebRequest webRequest, Throwable error) {
		errorAttributes.put("message", getMessage(webRequest, error));
	}

	protected String getMessage(WebRequest webRequest, Throwable error) {
		Object message = getAttribute(webRequest, RequestDispatcher.ERROR_MESSAGE);
		if (!ObjectUtils.isEmpty(message)) {
			return message.toString();
		}
		if (error != null && StringUtils.hasLength(error.getMessage())) {
			return error.getMessage();
		}
		return "No message available";
	}

	private void addBindingResultErrorMessage(Map<String, Object> errorAttributes, BindingResult result) {
		errorAttributes.put("message", "Validation failed for object='" + result.getObjectName() + "'. "
				+ "Error count: " + result.getErrorCount());
		errorAttributes.put("errors", result.getAllErrors());
	}

	private BindingResult extractBindingResult(Throwable error) {
		if (error instanceof BindingResult) {
			return (BindingResult) error;
		}
		return null;
	}

	private void addStackTrace(Map<String, Object> errorAttributes, Throwable error) {
		StringWriter stackTrace = new StringWriter();
		error.printStackTrace(new PrintWriter(stackTrace));
		stackTrace.flush();
		errorAttributes.put("trace", stackTrace.toString());
	}

	private void addPath(Map<String, Object> errorAttributes, RequestAttributes requestAttributes) {
		String path = getAttribute(requestAttributes, RequestDispatcher.ERROR_REQUEST_URI);
		if (path != null) {
			errorAttributes.put("path", path);
		}
	}

	@Override
	public Throwable getError(WebRequest webRequest) {
		Throwable exception = getAttribute(webRequest, ERROR_INTERNAL_ATTRIBUTE);
		if (exception == null) {
			exception = getAttribute(webRequest, RequestDispatcher.ERROR_EXCEPTION);
		}
		// store the exception in a well-known attribute to make it available to metrics
		// instrumentation.
		webRequest.setAttribute(ErrorAttributes.ERROR_ATTRIBUTE, exception, WebRequest.SCOPE_REQUEST);
		return exception;
	}

	@SuppressWarnings("unchecked")
	private <T> T getAttribute(RequestAttributes requestAttributes, String name) {
		return (T) requestAttributes.getAttribute(name, RequestAttributes.SCOPE_REQUEST);
	}

}
BasicErrorController

ErrorMvcAutoConfiguration往容器中放了一个BasicErrorController类的组件,组件id为basicErrorController。

@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,
		ObjectProvider<ErrorViewResolver> errorViewResolvers) {
	return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
			errorViewResolvers.orderedStream().collect(Collectors.toList()));
}

BasicErrorController的定义如下。

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
	//...
	@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
		HttpStatus status = getStatus(request);
		Map<String, Object> model = Collections
				.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
		response.setStatus(status.value());
		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
		return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
	}

	@RequestMapping
	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
		HttpStatus status = getStatus(request);
		if (status == HttpStatus.NO_CONTENT) {
			return new ResponseEntity<>(status);
		}
		Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
		return new ResponseEntity<>(body, status);
	}
}

@RequestMapping("${server.error.path:${error.path:/error}}"),控制器BasicErrorController可以处理的请求映射是:server.error.patherror.path/error,默认是/error
如果是浏览器客户端,则调用BasicErrorController#errorHTML方法进行处理,返回一个HTML格式的错误视图;如果是机器客户端,则调用BasicErrorController#error方法进行处理,返回一个JSON数据。

WhitelabelErrorViewConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", matchIfMissing = true)
@Conditional(ErrorTemplateMissingCondition.class)
protected static class WhitelabelErrorViewConfiguration {

	private final StaticView defaultErrorView = new StaticView();

	@Bean(name = "error")
	@ConditionalOnMissingBean(name = "error")
	public View defaultErrorView() {
		return this.defaultErrorView;
	}

	// If the user adds @EnableWebMvc then the bean name view resolver from
	// WebMvcAutoConfiguration disappears, so add it back in to avoid disappointment.
	@Bean
	@ConditionalOnMissingBean
	public BeanNameViewResolver beanNameViewResolver() {
		BeanNameViewResolver resolver = new BeanNameViewResolver();
		resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
		return resolver;
	}
}

往容器中放入了一个View类的组件,组件id为error。(默认错误视图
往容器中放入了一个BeanNameViewResolver类的组件,组件id为beanNameViewResolver,它可以根据组件id解析视图。(用于解析 默认错误视图的 视图解析器

默认错误视图是StaticView类,StaticView定义如下。
render方法中就是“whitelabel”错误视图的渲染过程。

private static class StaticView implements View {
	//...
	@Override
	public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (response.isCommitted()) {
			String message = getMessage(model);
			logger.error(message);
			return;
		}
		response.setContentType(TEXT_HTML_UTF8.toString());
		StringBuilder builder = new StringBuilder();
		Object timestamp = model.get("timestamp");
		Object message = model.get("message");
		Object trace = model.get("trace");
		if (response.getContentType() == null) {
			response.setContentType(getContentType());
		}
		builder.append("<html><body><h1>Whitelabel Error Page</h1>").append(
				"<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>")
				.append("<div id='created'>").append(timestamp).append("</div>")
				.append("<div>There was an unexpected error (type=").append(htmlEscape(model.get("error")))
				.append(", status=").append(htmlEscape(model.get("status"))).append(").</div>");
		if (message != null) {
			builder.append("<div>").append(htmlEscape(message)).append("</div>");
		}
		if (trace != null) {
			builder.append("<div style='white-space:pre-wrap;'>").append(htmlEscape(trace)).append("</div>");
		}
		builder.append("</body></html>");
		response.getWriter().append(builder.toString());
	}
	//...
}
DefaultErrorViewResolverConfiguration
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ WebProperties.class, WebMvcProperties.class })
static class DefaultErrorViewResolverConfiguration {

	private final ApplicationContext applicationContext;

	private final Resources resources;

	DefaultErrorViewResolverConfiguration(ApplicationContext applicationContext, WebProperties webProperties) {
		this.applicationContext = applicationContext;
		this.resources = webProperties.getResources();
	}

	@Bean
	@ConditionalOnBean(DispatcherServlet.class)
	@ConditionalOnMissingBean(ErrorViewResolver.class)
	DefaultErrorViewResolver conventionErrorViewResolver() {
		return new DefaultErrorViewResolver(this.applicationContext, this.resources);
	}

}

往容器中放了一个DefaultErrorViewResolver类的组件,id为conventionErrorViewResolver。(错误视图解析器

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ WebProperties.class, WebMvcProperties.class })
static class DefaultErrorViewResolverConfiguration {
	//...
	@Bean
	@ConditionalOnBean(DispatcherServlet.class)
	@ConditionalOnMissingBean(ErrorViewResolver.class)
	DefaultErrorViewResolver conventionErrorViewResolver() {
		return new DefaultErrorViewResolver(this.applicationContext, this.resources);
	}
}

DefaultErrorViewResolver的定义如下。

public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {

	private static final Map<Series, String> SERIES_VIEWS;

	static {
		Map<Series, String> views = new EnumMap<>(Series.class);
		views.put(Series.CLIENT_ERROR, "4xx");
		views.put(Series.SERVER_ERROR, "5xx");
		SERIES_VIEWS = Collections.unmodifiableMap(views);
	}
	//...
	@Override
	public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
		ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);
		if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
			modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
		}
		return modelAndView;
	}

	private ModelAndView resolve(String viewName, Map<String, Object> model) {
		String errorViewName = "error/" + viewName;
		TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
				this.applicationContext);
		if (provider != null) {
			return new ModelAndView(errorViewName, model);
		}
		return resolveResource(errorViewName, model);
	}

	private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
		for (String location : this.resources.getStaticLocations()) {
			try {
				Resource resource = this.applicationContext.getResource(location);
				resource = resource.createRelative(viewName + ".html");
				if (resource.exists()) {
					return new ModelAndView(new HtmlResourceView(resource), model);
				}
			}
			catch (Exception ex) {
			}
		}
		return null;
	}
}

"error/"+String.valueOf(status.value()),这也是为什么自定义错误页面时,要在error目录下放4xx.html5xx.html视图文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
 针对数据库的启动和关闭、控制文件与数据库初始化、参数及参数文件、数据字典、内存管理、Buffer Cache与Shared Pool原理、重做、回滚与撤销、等待事件、性能诊断与SQL优化等几大Oracle热点主题,本书从基础知识入手,深入研究相关技术,并结合性能调整及丰富的诊断案例,力图将Oracle知识全面、系统、深入地展现给读者。   本书给出了大量取自实际工作现场的实例,在分析实例的过程中,兼顾深度与广度,不仅对实际问题的现象、产生原因和相关的原理进行了深入浅出的讲解,更主要的是,结合实际应用环境,提供了一系列解决问题的思路和方法,包括详细的操作步骤,具有很强的实战性和可操作性,适用于具备一定数据库基础、打算深入学习Oracle技术的数据库从业人员,尤其适用于入门、进阶以及希望深入研究Oracle技术的数据库管理人员。 第1章 数据库的启动和关闭 1 1.1 数据库的启动 1 1.1.1 启动数据库到NOMOUNT状态的过程 2 1.1.2 启动数据库到MOUNT状态 18 1.1.3 启动数据库OPEN阶段 26 1.2 数据库的访问 37 1.2.1 客户端的TNSNAMES.ORA文件配置 37 1.2.2 服务器端的监听器文件listener.ora配置 39 1.2.3 通过不同服务器名对数据库的访问 41 1.2.4 动态监听器注册服务 42 1.3 数据库的关闭 46 1.3.1 数据库关闭的步骤 46 1.3.2 几种关闭方式的对比 48 第2章 控制文件与数据库初始化 51 2.1 控制文件的内容 51 2.2 SCN 53 2.2.1 SCN的定义 53 2.2.2 SCN的获取方式 53 2.2.3 SCN的进一步说明 54 2.3 检查点(Checkpoint) 57 2.3.1 检查点(Checkpoint)的工作原理 57 2.3.2 常规检查点与增量检查点 59 2.3.3 LOG_CHECKPOINT_TO_ALERT参数 63 2.3.4 控制文件与数据文件头信息 64 2.3.5 数据库的启动验证 66 2.3.6 使用备份的控制文件 70 2.3.7 FAST_START_MTTR_TARGET 71 2.3.8 关于检查点执行的案例 74 2.3.9 Oracle 10g自动检查点调整 75 2.3.10 检查点信息及恢复起点 78 2.3.11 正常关闭数据库的状况 78 2.3.12 数据库异常关闭的情况 80 2.3.13 数据库并行恢复案例一则 82 2.3.14 判断一个死事务的恢复进度 85 2.4 数据库的初始化 86 2.4.1 bootstrap$及数据库初始化过程 86 2.4.2 bootstrap$的定位 88 2.4.3 Oracle中独一无二的Cache对象 89 2.4.4 Oracle数据库的引导 91 2.4.5 系统对象与bootstrap$ 92 2.4.6 bootstrap$的重要性 94 2.4.7 BBED工具的简要介绍 95 2.4.8 坏块的处理与恢复 97 第3章 参数及参数文件 103 3.1 初始化参数的分类 103 3.1.1 推导参数(Derived Parameters) 103 3.1.2 操作系统依赖参数 104 3.1.3 可变参数 104 3.1.4 初始化参数的获取 105 3.2 参数文件 107 3.2.1 PFILE和SPFILE 108 3.2.2 获取参数的视图 110 3.2.3 SPFILE的创建 111 3.2.4 SPFILE的搜索顺序 112 3.2.5 使用PFILE/SPFILE启动数据库 112 3.2.6 修改参数 113 3.2.7 解决SPFILE参数修改错误 118 3.2.8 重置SPFILE中设置的参数 120 3.2.9 判断是否使用了SPFILE 120 3.2.10 SPFILE的备份与恢复 121 3.2.11 Oracle 11g参数文件恢复 127 3.2.12 如何设置Events事件 128 3.2.13 导出SPFILE文件 129 3.3 诊断案例之一:参数文件 131 3.3.1 登录系统检查告警日志文件 131 3.3.2 尝试重新启动数据库 132 3.3.3 检查数据文件 132 3.3.4 MOUNT数据库,检查系统参数 133 3.3.5 检查参数文件 133 3.3.6 再次检查alert文件 134 3.3.7 修正PFILE 135 3.3.8 启动数据库 135 3.4 诊断案例之二:RAC环境参数文件 135 3.4.1 数据库资源异常 135 3.4.2 问题的发现 136 3.4.3 参数文件问题的解决 137 第4
### 回答1: CuteCom是一个基于Qt框架开发的串口调试助手工具,用于在Linux和Windows系统上进行串口通信。该工具具有简单易用的界面和丰富的功能,可以方便地发送和接收串口数据。 CuteCom的源码主要包含三个部分:界面设计、串口通信和功能实现。 界面设计部分主要使用Qt的GUI库来创建用户界面,包括主窗口、菜单栏、工具栏、状态栏和各种控件。通过信号和槽机制,实现界面与业务逻辑的交互。例如,当用户点击发送按钮时,界面会发送一个信号通知程序发送串口数据。 串口通信部分使用Qt提供的串口通信类完成与串口的交互。通过调用串口类的方法,可以打开、关闭串口,设置串口参数(如波特率、数据位、校验位等),发送和接收数据。同时,通过使用Qt的事件循环机制,程序可以实时地接收串口数据。 功能实现部分是CuteCom提供的各种功能的具体实现代码,如发送数据、接收数据、清空接收缓冲区、保存接收数据等。这些功能代码通过调用串口通信部分的接口来完成具体的操作。 除了上述三个部分,CuteCom还利用了Qt框架的一些其他特性,如国际化支持(支持多语言界面)、日志记录、软件更新等。 总结起来,CuteCom的源码解析主要涉及界面设计、串口通信和功能实现三个方面。通过对源码的深入分析,可以了解CuteCom内部的工作原理,从而能够进行二次开发、定制和优化。 ### 回答2: CuteCom是一款开源的串口通信工具,使用C++语言编写。它提供了一个简单易用的用户界面,用于较低级别的设备通信,并支持常见的串口设置,如波特率、数据位、停止位和校验位等。 源码解析主要包括以下几个方面: 1. 界面设计:CuteCom的界面使用Qt框架进行设计。Qt提供了丰富的界面组件和布局管理器,可以方便地创建用户友好的界面。在源码中可以看到使用Qt的信号和槽机制进行事件传递和处理,以及使用Qt样式表进行界面美化。 2. 串口通信:CuteCom使用Linux的串口通信接口进行数据传输。在源码中可以找到对应的系统调用和API,如打开串口、设置串口参数、读取和写入数据等。同时,源码中还包括了一些错误处理和容错机制,以提高程序的稳定性和可靠性。 3. 数据解析:CuteCom可以将接收到的数据解析为ASCII码或十六进制表示,并支持显示时间戳。源码中解析数据的部分主要包括字符编码转换、格式化显示和时间戳计算。 4. 功能扩展:源码中还提供了一些可自定义的功能,如自动发送数据、周期性发送、延时发送等。这些功能可以根据用户的需求进行调整和扩展。 总之,CuteCom源码解析主要涉及界面设计、串口通信、数据解析和功能扩展等方面。通过分析源码,可以更好地了解和理解CuteCom的工作原理和实现方式,并可以根据需要进行个性化的二次开发和定制。 ### 回答3: cuteCom源码是一个基于Linux的串口通信工具源码。通过分析cuteCom源码,可以了解到其实现串口通信的一些关键细节。 首先,cuteCom利用Linux的串口通信API,如open()、tcgetattr()、tcsetattr()等函数,来与串口进行通信。通过open()函数打开串口设备文件,然后使用tcgetattr()和tcsetattr()函数对串口进行配置,如波特率、数据位、校验位等。 其次,cuteCom通过程序设计实现了如发送数据、接收数据、显示接收数据等功能。发送数据功能通过write()函数将数据写入串口设备文件,实现向外部设备发送数据。而接收数据功能则是通过read()函数从串口设备文件中读取从外部设备发送过来的数据。为了使用户能够直观地看到串口通信的结果,cuteCom还实现了显示接收数据的功能,即将接收到的数据打印出来。 另外,cuteCom还提供了一些界面操作,方便用户进行串口的打开、关闭、配置等操作。通过QT框架实现了基本的图形界面,并通过信号与槽机制,将界面与底层的串口通信功能连接起来。 总之,cuteCom源码实现了基于Linux的串口通信工具,通过对源码的分析,可以了解到串口通信的实现原理和细节。这对于串口通信的开发和调试非常有帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值