文档章节

springmvc的大体流程理解

j
 java小学生儿
发布于 2016/12/08 12:54
字数 2729
阅读 178
收藏 2
点赞 0
评论 0

故事是这样开始的。。。。。

        sprng和springmvc是属于两个不同的容器

   Spring的容器属于父容器,springmvc的容器是子容器

父容器不能访问子容器的bean,但是子容器可以访问父容器的bean

因此,不能再spring的配置中扫面所有的包,这样的话,springmvc就扫不到controller了

这样的话,当请求到达时,springmvc没有handler,就无法做出响应。  

      首先来说web.xml中的一个配置

  <listener>        <!--用来设定Listener接口-->  

        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

    </listener>    

        这个配置定义了一个上下文加载监听器,当监听到web程序启动时就会执行该类的方法:

 /**

     * Initialize the root web application context.

     */

    public void contextInitialized(ServletContextEvent event) {

        this.contextLoader.initWebApplicationContext(event.getServletContext());

    }

    可以看到执行了contextLoader的initWebApplicationContext(servletContext)该方法会初始化web的上下文

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {

                   //省掉了部分代码

//这个方法的用途主要是用来解决Spring共享环境的,即,如果我们有多个WAR包部署在同一个服务器上,而且这些WAR都共享某一套业务逻辑层。如何共享//一套业务逻辑包配置而不要每个WAR都单独配置,这时我们就可能需要Spring的共享环境了。

            // Determine parent for root web application context, if any.

            ApplicationContext parent = loadParentContext(servletContext);

            // Store context in local instance variable, to guarantee that

            // it is available on ServletContext shutdown.

            this.context = createWebApplicationContext(servletContext, parent);

//将得到的web上下文设为全web域的属性

            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

        我们来看下是怎么创建web上下文的

protected WebApplicationContext createWebApplicationContext(ServletContext sc, ApplicationContext parent) {

//通过servlet的初始化参数得到定义的contextclass

Class<?> contextClass = determineContextClass(sc);

//首先判断自定义的或默认的webcontext类是不是ConfigurableWebApplicationContext的子类

if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {

throw new ApplicationContextException("Custom context class [" + contextClass.getName() +

"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");

}

ConfigurableWebApplicationContext wac =

(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

try {

String contextPath = (String) ServletContext.class.getMethod("getContextPath").invoke(sc);

wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +

ObjectUtils.getDisplayString(contextPath));

}

catch (Exception ex) {

throw new IllegalStateException("Failed to invoke Servlet 2.5 getContextPath method", ex);

}

//为wac设置相应的属性

wac.setParent(parent);

wac.setServletContext(sc);

//设置contextConfigLocation,这个属性在web.xml中配置

wac.setConfigLocation(sc.getInitParameter(CONFIG_LOCATION_PARAM));

customizeContext(sc, wac);

//最核心的方法,完成bean的初始化和实例化

wac.refresh();

return wac;

}

 来看下refresh()这个核心的方法

//待更新。。。。。。

到此为止在web.xml中配置的contextConfigLocation的spring.xml已经加载完毕,已经加载完了spring.xml中配置的所有的bean对象。

接下来就是要加载web.xml中的springmvc的内容了

先看一下web.xml的相应配置

<servlet>

<servlet-name>springmvc</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:spring-mvc.xml</param-value>

</init-param>

</servlet>

<servlet-mapping>

<servlet-name>springmvc</servlet-name>

<url-pattern>/</url-pattern>

</servlet-mapping>

从以上配置可以看到springmvc其实就是一个servlet而已,因为它的配置和普通的servlet一样,唯一不同的,就是servlet-class也就是DispatcherServlet会拦截所有的符合的请求,并执行处理操作,最后返回试图。

首先加载httpServletBean的init()方法
 

@Override

public final void init() throws ServletException {

// Set bean properties from init parameters.

try {

PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);

BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);

ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());

bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));

initBeanWrapper(bw);

bw.setPropertyValues(pvs, true);

}

// Let subclasses do whatever initialization they like.

initServletBean();

}

加载HttpServletBean的initServletBean()方法,它没有写这个方法,于是调用它的子类FrameworkServlet的该方法:

protected final void initServletBean() throws ServletException {

try {

this.webApplicationContext = initWebApplicationContext();

//* This method will be invoked after any bean properties have been set and

      * the WebApplicationContext has been loaded. The default implementation is empt;

      * subclasses may override this method to perform any initialization they require.

initFrameworkServlet();

}

}

主要就是这个两个方法,先看下initWebApplicationContext()

protected WebApplicationContext initWebApplicationContext() {

WebApplicationContext rootContext =

WebApplicationContextUtils.getWebApplicationContext(getServletContext());

WebApplicationContext wac = null;

if (this.webApplicationContext != null) {

// A context instance was injected at construction time -> use it

wac = this.webApplicationContext;

if (wac instanceof ConfigurableWebApplicationContext) {

ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;

if (!cwac.isActive()) {

// The context has not yet been refreshed -> provide services such as

// setting the parent context, setting the application context id, etc

if (cwac.getParent() == null) {

// The context instance was injected without an explicit parent -> set

// the root application context (if any; may be null) as the parent

cwac.setParent(rootContext);

}

configureAndRefreshWebApplicationContext(cwac);

}

}

}

if (wac == null) {

// No context instance was injected at construction time -> see if one

// has been registered in the servlet context. If one exists, it is assumed

// that the parent context (if any) has already been set and that the

// user has performed any initialization such as setting the context id

wac = findWebApplicationContext();

}

if (wac == null) {

// No context instance is defined for this servlet -> create a local one

wac = createWebApplicationContext(rootContext);

}

 

if (!this.refreshEventReceived) {

// Either the context is not a ConfigurableApplicationContext with refresh

// support or the context injected at construction time had already been

// refreshed -> trigger initial onRefresh manually here.

onRefresh(wac);

}

 

if (this.publishContext) {

// Publish the context as a servlet context attribute.

String attrName = getServletContextAttributeName();

getServletContext().setAttribute(attrName, wac);

if (this.logger.isDebugEnabled()) {

this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +

"' as ServletContext attribute with name [" + attrName + "]");

}

}

return wac;

}

这里最核心的还是configureAndRefreshWebApplicationContext(cwac)

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {

// Generate default id...

ServletContext sc = getServletContext();

wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + servletContextName +

"." + getServletName());

else {

wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + getServletName());

}

wac.setServletContext(getServletContext());

//设置该servlet的servletConfig对象

wac.setServletConfig(getServletConfig());

wac.setNamespace(getNamespace());

wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

postProcessWebApplicationContext(wac);

applyInitializers(wac);

wac.refresh();

}

就这样springmvc的上下文也解析完了。

DispatcherServlet  负责拦截所有request,并返回试图

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

HttpServletRequest processedRequest = request;

HandlerExecutionChain mappedHandler = null;

int interceptorIndex = -1;

try {

ModelAndView mv;

boolean errorView = false;

try {

processedRequest = checkMultipart(request);

// Determine handler for the current request.

//得到这个request,具体来说是url对应的处理类,并将该类以及相应的inteceptors封装在HandlerExecuteChain类中,这个地方使用了策略模式,优点是十分方便的扩展

mappedHandler = getHandler(processedRequest, false)

// Determine handler adapter for the current request.

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler.

String method = request.getMethod();

boolean isGet = "GET".equals(method);

// Apply preHandle methods of registered interceptors.

HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();

if (interceptors != null) {

for (int i = 0; i < interceptors.length; i++) {

HandlerInterceptor interceptor = interceptors[i];

if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {

triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);

return;

}

interceptorIndex = i;

}

}

 

// Actually invoke the handler.

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

 

// Do we need view name translation?

if (mv != null && !mv.hasView()) {

mv.setViewName(getDefaultViewName(request));

}

 

// Apply postHandle methods of registered interceptors.

if (interceptors != null) {

for (int i = interceptors.length - 1; i >= 0; i--) {

HandlerInterceptor interceptor = interceptors[i];

interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);

}

}

}

finally {

// Clean up any resources used by a multipart request.

if (processedRequest != request) {

cleanupMultipart(processedRequest);

}

}

}

  首先来说下HandlerExecuteChain

mappedHandler = getHandler(processedRequest, false);

//首先这里的实现原理是循环调用springmvc默认的或者是自定义的(优先级高)HandlerMapping
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

for (HandlerMapping hm : this.handlerMappings) {

HandlerExecutionChain handler = hm.getHandler(request);

if (handler != null) {

return handler;

}

}

return null;

}

 

最常用的就是BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping分别通过配置的
bean的id以及添加的注解获取对应的处理器类,然后将相应的inteceptor添加到HandlerExecuteChain
对象中去,这样的做法可以符合框架设计的开闭原则,保证不会修改代码,只需要添加然后进行相应的配置就好了。
这里使用了策略模式。

接下来是handlerAdapter

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

在这里使用了适配器原则,首先说一下HandlerAdapter,大家想一下,如果没有这个类的话,那我们在执行处理器方法时,是不是需要

使用大量的if...else...而且还不能扩展,所以这里使用了适配器模式,每一个处理器类都会有一个对应的HandlerAdapter,每一个HandlerAdapter类都会有一个Handle方法和supports方法

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {

for (HandlerAdapter ha : this.handlerAdapters) {

if (ha.supports(handler)) {

return ha;

}

}

}

可以看到这里会遍历springmvc定义的HandlerAdapter,如果是这个处理器对应的适配器,就返回这个适配器。这样的做法就十分有利于扩展

开始执行处理器方法返回一个ModelAndView对象

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

这是的AnnotationMethodHandlerAdapter的handle方法,最后返回一个ModelAndView

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

        //先判断是不是被@SesionAttribute注解了,分别处理

Class<?> clazz = ClassUtils.getUserClass(handler);

Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);

if (annotatedWithSessionAttributes == null) {

annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);

this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);

}

if (annotatedWithSessionAttributes) {

// Always prevent caching in case of session attribute management.

checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);

// Prepare cached set of session attributes names.

}

else {

// Uses configured default cacheSeconds setting.

checkAndPrepare(request, response, true);

}

// Execute invokeHandlerMethod in synchronized block if required.

if (this.synchronizeOnSession) {

HttpSession session = request.getSession(false);

if (session != null) {

Object mutex = WebUtils.getSessionMutex(session);

synchronized (mutex) {

return invokeHandlerMethod(request, response, handler);

}

}

}

return invokeHandlerMethod(request, response, handler);

}

接下来是执行invokeHandlerMethod方法

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

//得到处理器的处理方法

ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);

Method handlerMethod = methodResolver.resolveHandlerMethod(request);

ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);

//得到请求对象

ServletWebRequest webRequest = new ServletWebRequest(request, response);

ExtendedModelMap implicitModel = new BindingAwareModelMap()

//得到处理器方法返回的模型数据

Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel)

//将模型数据和视图信息封装进ModelAndView对象中

ModelAndView mav =

methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);

//做一些更新操作

methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);

return mav;

}

首先看下invokeHandlerMethod方法

public final Object invokeHandlerMethod(Method handlerMethod, Object handler,

NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {

 

Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);

try {

boolean debug = logger.isDebugEnabled();

//查找@sessionAttribute绑定的参数,如果存在就加入model中,不存在则不处理

for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {

Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);

if (attrValue != null) {

implicitModel.addAttribute(attrName, attrValue);

}

}

//循环处理@modelAttribute绑定的方法

for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {

Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);

//得到这个方法的所有的参数

Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);

//得到@ModelAttribute绑定的数据的名字

String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); //如果之前已经得到了这个数据,就执行下一个@ModelAttribute方法,这意味着如果sessionAttribute中已经有了这个数据,就不会再接受这个方法返回的数据

if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {

continue;

}

ReflectionUtils.makeAccessible(attributeMethodToInvoke);

Object attrValue = attributeMethodToInvoke.invoke(handler, args);

if ("".equals(attrName)) {

Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());

attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);

}

//如果sessionAttribute中没有这个数据,则将它放进model中

if (!implicitModel.containsAttribute(attrName)) {

implicitModel.addAttribute(attrName, attrValue);

}

}

//得到处理器方法的所有的参数

Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);

ReflectionUtils.makeAccessible(handlerMethodToInvoke);

return handlerMethodToInvoke.invoke(handler, args);

}

}

接下来看看怎么得到的modelAndView

ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);

不论处理器方法返回什么值,最终都会组装成modelAndView对象。

另外在handle执行的前后都会先进行拦截器的处理

if (interceptors != null) {

for (int i = 0; i < interceptors.length; i++) {

HandlerInterceptor interceptor = interceptors[i];

if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {

triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);

return;

}

interceptorIndex = i;

}

}

// Actually invoke the handler.

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

// Do we need view name translation?

if (mv != null && !mv.hasView()) {

mv.setViewName(getDefaultViewName(request));

}

// Apply postHandle methods of registered interceptors.

if (interceptors != null) {

for (int i = interceptors.length - 1; i >= 0; i--) {

HandlerInterceptor interceptor = interceptors[i];

interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);

}

}

}

在handle之前会执行inteceptor的preHandle方法,当执行完handle后会执行inteceptor的postHandle方法,最后在执行inteceptor的

afterCompletion方法

springmvc的配置:

<mvc:interceptors>

<!-- XXX会拦截所有的请求 -->

<bean class="cn.zcm.interceptor.XXX"></bean>

<mvc:interceptor>

<!-- AAA会拦截所有的"/user"的请求 -->

<mvc:mapping path="/user"/>

<bean class="cn.zcm.interceptor.AAA"></bean>

</mvc:interceptor>

</mvc:interceptors>

解析并渲染视图

render(mv, processedRequest, response);

首先解析modelAndView得到一个视图

view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);

这里与HandlerAdapter类似,也使用了策略模式,当我们要添加其他视图技术时,只需要在springmvc配置文件中配置就好了,然后就会出现在viewResolvers里面,然后视图解析器就能通过逻辑视图名解析出具体的视图。

protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,

HttpServletRequest request) throws Exception {

for (ViewResolver viewResolver : this.viewResolvers) {

View view = viewResolver.resolveViewName(viewName, locale);

if (view != null) {

return view;

}

}

return null;

}

 

最后就只差一步渲染视图了,将模型数据添加到视图中

view.render(mv.getModelInternal(), request, response);

主要是:有许多的具体的视图类

renderMergedOutputModel(mergedModel, request, response);

这些视图类会根据视图的不同利用不同的技术将模型数据进行相应的处理加工,形成自己需要的数据,然后将该视图以重定向或者转发的方式返回给用户,其实也是用的servlet的response.sendDirect和DispatcherServlet.forword();

到此大体流程就结束了。

© 著作权归作者所有

共有 人打赏支持
j
粉丝 0
博文 1
码字总数 2729
作品 0
BeanPostProcessor —— 连接Spring IOC和AOP的桥梁

之前都是从大Boss的视角,来介绍Spring,比如IOC、AOP。 今天换个视角,从一个小喽啰出发,来加深对Spring的理解。 这个小喽啰就是,BeanPostProcessor(下面简称BBP)。 讲解思路: BBP怎么...

SexyCode ⋅ 06/19 ⋅ 0

Spring对@ComponentScan注解的解析处理

上篇文章Spring对@Configuration的解析处理在解析@ComponentScan注解的时候跳过了,只是说了一下他大体的过程,今天我们看下他的在扫描BeanDefinition的处理流程。 代码开始于中的下面一段代...

数齐 ⋅ 05/27 ⋅ 0

shiro登录流程

ShiroFilter Shiro提供了与Web集成的支持,其通过一个ShiroFilter入口来拦截需要安全控制的URL,然后进行相应的控制,ShiroFilter类似于如Strut2/SpringMVC这种web框架的前端 其是安全控制的...

嘿嘿!! ⋅ 2016/10/20 ⋅ 0

SpringMvc的使用

目录结构 一、SpringMvc相关知识 11、SpringMvc的大体认识 ? 12、什么是MVC ? 13、SpringMvc内部是怎么样工作的? 二、环境以及第三方技术的说明 三、我们进入正题,下边通过一个个实例来介...

丈量大地 ⋅ 2015/11/26 ⋅ 4

程序猿的日常——SpringMVC系统架构与流程回顾

web开发经历了很漫长的时间,在国内也快有十几年的时间了。从最开始的进程级到现在的MVC经历了很多的改进和优化,本篇就主要复习了解下Spring MVC相关的知识。 发展历程 第一阶段 CGI进程响应...

青夜之衫 ⋅ 2017/12/05 ⋅ 0

SpringMVC源码剖析(二)- DispatcherServlet的前世今生

上一篇文章《SpringMVC源码剖析(一)- 从抽象和接口说起》中,我介绍了一次典型的SpringMVC请求处理过程中,相继粉墨登场的各种核心类和接口。我刻意忽略了源码中的处理细节,只列出最简单的...

相见欢 ⋅ 2013/01/05 ⋅ 25

SpringMVC知识梳理(一)

什么是SpringMVC SpringMVC其实就是spring框架的一个模块,SpringMVC和spring之间可以无缝整合,SpringMVC也是一个非常优秀的基于MVC的web框架,什么是MVC这里就不多说了,下面来了解一下spr...

iHuawen ⋅ 2017/12/28 ⋅ 0

ehuacui/ehuacui-bbs

介绍 该项目源于pybbs,使用Spring等框架进行服务端重写,优化了 源工程部分实现逻辑,前台模板和数据库表结构目前大体与pybbs 保持一致。后续计划与pybbs保持独立开发和维护。目前部分功能仍...

ehuacui ⋅ 2016/10/13 ⋅ 0

初学spring-mvc

今天初步了解了一下springMVC,把自己对springmvc的一些理解总结了一下。 一、springmvc类似于Struts2的一种Web框架。 springmvc处理请求的流程: 1、用户发送请求,请求被Spring 前端控制S...

梁荣良 ⋅ 2016/05/12 ⋅ 0

十分钟认识Activiti6.0工作流引擎

概述 了解Activiti 假如你还不知道Activiti是什么,那么工作流引擎对你来说一定也是新的,解决Activiti和工作流知识盲点,所以看到到这里就对了,还有Android同学会误以为是“Activity”,工...

JimmyNo1 ⋅ 06/13 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

20.zip压缩 tar打包 打包并压缩

6月25日任务 6.5 zip压缩工具 6.6 tar打包 6.7 打包并压缩 6.5 zip压缩工具: zip支持压缩目录 zip压缩完之后原来的文件不删除 不同的文件内容其实压缩的效果不一样 文件内有很多重复的用xz压...

王鑫linux ⋅ 刚刚 ⋅ 0

double类型数据保留四位小数的另一种思路

来源:透析公式处理,有时候数据有很长的小数位,有的时候由在四位以内,如果用一般的处理方法,那么不足四位的小树会补充0到第四位,这样子有点画蛇添足的感觉,不太好看。所以要根据小数的...

young_chen ⋅ 7分钟前 ⋅ 0

Python 优化 回溯下降算法

使用sympy构造表达式,实现回溯下降算法 完整代码 from matplotlib import pyplot as pltimport numpy as npfrom mpl_toolkits.mplot3d import Axes3Dfrom sympy import *import mat......

阿豪boy ⋅ 11分钟前 ⋅ 0

Django配置163邮箱出现 authentication failed(535)错误解决方法

最近用Django写某网站,当配置163邮箱设置完成后,出现535错误即:smtplib.SMTPAuthenticationError: (535, b'Error: authentication failed') Django初始配置邮箱设置 EMAIL_HOST = "smtp.1...

陈墨轩_CJX ⋅ 13分钟前 ⋅ 0

用接口模拟可伸缩枚举(34)

1、枚举的可伸缩性最后证明都不是什么好点子 扩展类型的元素是基本类型实例,基本类型的实例却不是扩展类型的元素,很混乱 目前还没有很好的方法来枚举基本类型的所有元素,及其扩展 可伸缩性...

职业搬砖20年 ⋅ 16分钟前 ⋅ 0

Ubuntu18.04 IDEA快捷键无法使用

IDEA默认的回退到上一视图的快捷键是Ctrl + Alt + Left,在ubuntu中这个快捷键被占用了,在16.04中可以在界面中取消这个快捷键,但是18.04就看不到了,可以使用以下命令解决 gsettings set ...

Iceberg_XTY ⋅ 21分钟前 ⋅ 0

如何解决s权限位引发postfix及crontab异常

一、问题现象 业务反馈某台应用服务器,普通用户使用mutt程序发送邮件时,提示“postdrop warning: mail_queue_enter: create file maildrop/713410.6065: Permission denied”,而且普通用法...

问题终结者 ⋅ 33分钟前 ⋅ 0

Unable to load database on disk

由于磁盘空间满了以后,导致zookeeper异常退出,清理磁盘空间后,zk启动报错,信息如下: 2018-06-25 17:18:46,904 INFO org.apache.zookeeper.server.quorum.QuorumPeerConfig: Reading co...

刀锋 ⋅ 52分钟前 ⋅ 0

css3 box-sizing:border-box 实现div一行多列

<!DOCTYPE html><html><head><style> div.container{ background:green; padding:10px 10px;}div.box{box-sizing:border-box;-moz-box-sizing:border-box; /* Fir......

qimh ⋅ 58分钟前 ⋅ 0

Homebrew简介和基本使用

一、Homebrew是什么 Homebrew是一款Mac OS平台下的软件包管理工具,拥有安装、卸载、更新、查看、搜索等很多实用的功能。简单的一条指令,就可以实现包管理,而不用你关心各种依赖和文件路径...

说回答 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部