保定网站排名优化wordpress 文章的标签
web/
2025/10/2 23:28:00/
文章来源:
保定网站排名优化,wordpress 文章的标签,seo千享科技,某网站安全建设方案重新启动企业应用程序时#xff0c;客户打开Web浏览器时会看到什么#xff1f; 他们什么也没看到#xff0c;服务器还没有响应#xff0c;因此Web浏览器显示ERR_CONNECTION_REFUSED 应用程序前面的Web代理#xff08;如果有#xff09;注意到它已关闭并显示“友好”错误… 重新启动企业应用程序时客户打开Web浏览器时会看到什么 他们什么也没看到服务器还没有响应因此Web浏览器显示ERR_CONNECTION_REFUSED 应用程序前面的Web代理如果有注意到它已关闭并显示“友好”错误消息 该网站需要永久加载-它接受了套接字连接和HTTP请求但是等待响应直到应用程序实际启动 您的应用程序进行了横向扩展以便其他节点可以快速处理请求而不会发出通知并且会话始终得以复制 …或应用程序启动速度如此之快以至于没有人注意到任何中断嘿普通的Spring Boot Hello world应用程序从点击java -jar ... [Enter]开始服务请求不到3秒。 顺便说一句请检出SPR-8767启动过程中的并行bean初始化 。 处于情况4和5.绝对更好。但是在本文中我们将介绍对情况1和3的更强大的处理。 典型的Spring Boot应用程序会在所有Bean都加载完毕时状态1在最后启动Web容器例如Tomcat。这是一个非常合理的默认值因为它会阻止客户端在完全配置之前无法访问我们的端点。 但是这意味着我们无法区分启动了几秒钟的应用程序和关闭了的应用程序。 因此想法是要有一个应用程序在加载时显示一些有意义的启动页面类似于显示“ 服务不可用 ”的Web代理。 但是由于此类启动页面是我们应用程序的一部分因此它可能会更深入地了解启动进度。 我们希望在初始化生命周期中更早地启动Tomcat但是要提供特殊目的的启动页面直到Spring完全引导为止。 这个特殊页面应该拦截所有可能的请求-因此听起来像一个servlet过滤器。 渴望并尽早启动Tomcat。 在Spring启动servlet容器通过初始化EmbeddedServletContainerFactory创建的实例EmbeddedServletContainer 。 我们有机会使用EmbeddedServletContainerCustomizer拦截此过程。 容器是在应用程序生命周期的早期创建的但是在整个上下文完成后才开始 。 所以我想我将只在自己的定制器中调用start()就是这样。 不幸的是ConfigurableEmbeddedServletContainer没有公开这样的API所以我不得不像这样装饰EmbeddedServletContainerFactory class ProgressBeanPostProcessor implements BeanPostProcessor {//...Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof EmbeddedServletContainerFactory) {return wrap((EmbeddedServletContainerFactory) bean);} else {return bean;}}private EmbeddedServletContainerFactory wrap(EmbeddedServletContainerFactory factory) {return new EmbeddedServletContainerFactory() {Overridepublic EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers) {final EmbeddedServletContainer container factory.getEmbeddedServletContainer(initializers);log.debug(Eagerly starting {}, container);container.start();return container;}};}
} 您可能会认为BeanPostProcessor是一个过大的功能但是稍后它将变得非常有用。 我们在这里所做的是如果遇到从应用程序上下文中被请求的EmbeddedServletContainerFactory 我们将返回一个装饰器该装饰器急切地启动Tomcat。 这给我们带来了相当不稳定的设置即Tomcat接受到尚未初始化的上下文的连接。 因此让我们放置一个servlet过滤器来拦截所有请求直到上下文完成为止。 启动期间拦截请求 我只是通过在Spring上下文中添加FilterRegistrationBean来开始的希望它会拦截传入的请求直到上下文启动为止。 这是徒劳的我不得不等待很长时间直到注册过滤器并准备就绪因此从用户的角度来看应用程序已挂起。 后来我什至尝试使用Servlet API javax.servlet.ServletContext.addFilter() 在Tomcat中直接注册过滤器但是显然必须预先引导整个DispatcherServlet 。 记住我想要的只是来自即将初始化的应用程序的快速反馈。 因此我最终得到了Tomcat的专有API org.apache.catalina.Valve 。 Valve与Servlet过滤器类似但它是Tomcat体系结构的一部分。 Tomcat自己捆绑了多个阀门以处理各种容器功能例如SSL会话群集和X-Forwarded-For处理。 Logback Access也使用此API因此我不会感到内。 阀门看起来像这样 package com.nurkiewicz.progress;import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
import org.apache.tomcat.util.http.fileupload.IOUtils;import javax.servlet.ServletException;
import java.io.IOException;
import java.io.InputStream;public class ProgressValve extends ValveBase {Overridepublic void invoke(Request request, Response response) throws IOException, ServletException {try (InputStream loadingHtml getClass().getResourceAsStream(loading.html)) {IOUtils.copy(loadingHtml, response.getOutputStream());}}
} 阀门通常委托给链中的下一个阀门但是这次我们只为每个单个请求返回static loading.html页面。 注册这样的阀门非常简单Spring Boot为此提供了一个API if (factory instanceof TomcatEmbeddedServletContainerFactory) {((TomcatEmbeddedServletContainerFactory) factory).addContextValves(new ProgressValve());
} 定制阀门原来是一个好主意它从Tomcat立即开始并且非常易于使用。 但是您可能已经注意到即使在应用程序启动后我们也不会放弃提供loading.html 。 那很糟。 Spring上下文可以通过多种方式发出初始化信号例如使用ApplicationListenerContextRefreshedEvent Component
class Listener implements ApplicationListenerContextRefreshedEvent {private static final CompletableFutureContextRefreshedEvent promise new CompletableFuture();public static CompletableFutureContextRefreshedEvent initialization() {return promise;}public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {promise.complete(event);}} 我知道您的想法是“ static ”吗 但是在Valve内部我根本不想接触Spring上下文因为如果我在错误的时间点从随机线程请求某个bean它可能会引入阻塞甚至死锁。 完成promise Valve注销其自身 public class ProgressValve extends ValveBase {public ProgressValve() {Listener.initialization().thenRun(this::removeMyself);}private void removeMyself() {getContainer().getPipeline().removeValve(this);}//...} 这是令人惊讶的干净解决方案当不再需要Valve我们无需从处理管道中删除它而不必为每个请求支付费用。 我不会演示它如何工作以及为什么起作用让我们直接转向目标解决方案。 监控进度 监视Spring应用程序上下文启动的进度非常简单。 另外与基于API和规范驱动的框架如EJB或JSF相反我也惊讶于Spring框架的“可破解性”。 在Spring中我可以简单地实现BeanPostProcessor 以通知每个正在创建和初始化的bean 完整的源代码 package com.nurkiewicz.progress;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import rx.Observable;
import rx.subjects.ReplaySubject;
import rx.subjects.Subject;class ProgressBeanPostProcessor implements BeanPostProcessor, ApplicationListenerContextRefreshedEvent {private static final SubjectString, String beans ReplaySubject.create();public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {beans.onNext(beanName);return bean;}Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {beans.onCompleted();}static ObservableString observe() {return beans;}
} 每次初始化新bean时我将其名称发布到RxJava的可观察对象中。 整个应用程序初始化后我完成了Observable 。 任何人都可以使用此Observable 例如我们的自定义ProgressValve 完整的源代码 public class ProgressValve extends ValveBase {public ProgressValve() {super(true);ProgressBeanPostProcessor.observe().subscribe(beanName - log.trace(Bean found: {}, beanName),t - log.error(Failed, t),this::removeMyself);}Overridepublic void invoke(Request request, Response response) throws IOException, ServletException {switch (request.getRequestURI()) {case /init.stream:final AsyncContext asyncContext request.startAsync();streamProgress(asyncContext);break;case /health:case /info:response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);break;default:sendHtml(response, loading.html);}}//...} ProgressValve现在变得更复杂了我们还没有完成。 它可以处理多个不同的请求例如我有意在/health和/info Actuator端点上返回503以便该应用程序看起来像在启动期间处于关闭状态。 除了所有其他请求init.stream表明熟悉loading.html 。 /init.stream是特殊的。 这是服务器发送的事件端点它将在每次初始化新bean时推送消息很抱歉上面没有代码 private void streamProgress(AsyncContext asyncContext) throws IOException {final ServletResponse resp asyncContext.getResponse();resp.setContentType(text/event-stream);resp.setCharacterEncoding(UTF-8);resp.flushBuffer();final Subscription subscription ProgressBeanPostProcessor.observe().map(beanName - data: beanName).subscribeOn(Schedulers.io()).subscribe(event - stream(event, asyncContext.getResponse()),e - log.error(Error in observe(), e),() - complete(asyncContext));unsubscribeOnDisconnect(asyncContext, subscription);
}private void complete(AsyncContext asyncContext) {stream(event: complete\ndata:, asyncContext.getResponse());asyncContext.complete();
}private void unsubscribeOnDisconnect(AsyncContext asyncContext, final Subscription subscription) {asyncContext.addListener(new AsyncListener() {Overridepublic void onComplete(AsyncEvent event) throws IOException {subscription.unsubscribe();}Overridepublic void onTimeout(AsyncEvent event) throws IOException {subscription.unsubscribe();}Overridepublic void onError(AsyncEvent event) throws IOException {subscription.unsubscribe();}Overridepublic void onStartAsync(AsyncEvent event) throws IOException {}});
}private void stream(String event, ServletResponse response) {try {final PrintWriter writer response.getWriter();writer.println(event);writer.println();writer.flush();} catch (IOException e) {log.warn(Failed to stream, e);}
} 这意味着我们可以使用简单的HTTP接口来跟踪Spring应用程序上下文启动的进度 $ curl -v localhost:8090/init.streamGET /init.stream HTTP/1.1User-Agent: curl/7.35.0Host: localhost:8090Accept: */* HTTP/1.1 200 OKContent-Type: text/event-stream;charsetUTF-8Transfer-Encoding: chunkeddata: org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$EmbeddedTomcatdata: org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration$TomcatWebSocketConfigurationdata: websocketContainerCustomizerdata: org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfigurationdata: toStringFriendlyJsonNodeToStringConverterdata: org.hibernate.validator.internal.constraintvalidators.bv.NotNullValidatordata: serverPropertiesdata: org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration...data: beanNameViewResolverdata: basicErrorControllerdata: org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration$JpaWebConfiguration$JpaWebMvcConfiguration 该端点将实时初始化请参阅 使用RxJava和SseEmitter的服务器发送的事件 每个初始化的单个bean名称。 有了如此出色的工具我们将构建更强大的 反应性的 在这里我说过 loading.html页面。 花式进度前端 首先我们需要确定哪些Spring bean代表了系统中的哪些子系统 高级组件甚至可能是有限的上下文 。 我使用data-bean自定义属性在HTML内部对此进行了编码 h2 data-beanwebsocketContainerCustomizer classwaitingWeb socket support
/h2h2 data-beanmessageConverters classwaitingSpring MVC
/h2h2 data-beanmetricFilter classwaitingMetrics
/h2h2 data-beanendpointMBeanExporter classwaitingActuator
/h2h2 data-beanmongoTemplate classwaitingMongoDB
/h2h2 data-beandataSource classwaitingDatabase
/h2h2 data-beanentityManagerFactory classwaitingHibernate
/h2 CSS classwaiting表示给定的模块尚未初始化即给定的bean尚未出现在SSE流中。 最初所有组件都处于waiting状态。 然后我订阅init.stream并更改CSS类以反映模块状态更改 var source new EventSource(init.stream);
source.addEventListener(message, function (e) {var h2 document.querySelector(h2[data-bean e.data ]);if(h2) {h2.className done;}
}); 简单吧 显然没有jQuery的人就可以使用纯JavaScript编写前端。 加载所有bean后 Observable在服务器端event: complete SSE发出event: complete 让我们处理一下 source.addEventListener(complete, function (e) {window.location.reload();
}); 因为前端是在应用程序上下文启动时通知的所以我们可以简单地重新加载当前页面。 到那时我们的ProgressValve已经注销因此重新加载将打开真实的应用程序而不是loading.html占位符。 我们的工作完成了。 另外我还计算了启动的bean数量并知道总共有多少bean我用JavaScript对其进行了硬编码请原谅我可以用百分比来计算启动进度。 图片值一千个字下面的屏幕截图向您展示了我们所取得的成果 后续模块启动良好我们不再关注浏览器错误。 以百分比衡量的进度使整个启动进度感觉非常顺利。 最后但并非最不重要的一点是当应用程序启动时我们将自动重定向。 希望您喜欢这个概念证明整个工作示例应用程序都可以在GitHub上找到。 翻译自: https://www.javacodegeeks.com/2015/09/displaying-progress-of-spring-application-startup-in-web-browser.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/85890.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!