网站怎么做图片动态图片大全wordpress网站很慢
news/
2025/9/24 4:32:27/
文章来源:
网站怎么做图片动态图片大全,wordpress网站很慢,网站建设费如何核算,工信部网站备案登录作者#xff1a;木木匠 http://my.oschina.net/luozhou/blog/3088908前言我们知道 SpringBoot 给我们带来了一个全新的开发体验#xff0c;我们可以直接把 web 程序达成 jar 包#xff0c;直接启动#xff0c;这就得益于 SpringBoot 内置了容器#xff0c;可以直接启动木木匠 http://my.oschina.net/luozhou/blog/3088908前言我们知道 SpringBoot 给我们带来了一个全新的开发体验我们可以直接把 web 程序达成 jar 包直接启动这就得益于 SpringBoot 内置了容器可以直接启动本文将以 Tomcat 为例来看看 SpringBoot 是如何启动 Tomcat 的同时也将展开学习下 Tomcat 的源码了解 Tomcat 的设计。从 Main 方法说起用过 SpringBoot 的人都知道首先要写一个 main 方法来启动SpringBootApplication
public class TomcatdebugApplication {public static void main(String[] args) {SpringApplication.run(TomcatdebugApplication.class, args);}}我们直接点击 run 方法的源码跟踪下来发下最终的 run 方法是调用 ConfigurableApplicationContext 方法源码如下public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch new StopWatch();stopWatch.start();ConfigurableApplicationContext context null;Collectionspringbootexceptionreporter exceptionReporters new ArrayListlt;gt;();//设置系统属性『java.awt.headless』为true则启用headless模式支持configureHeadlessProperty();//通过*SpringFactoriesLoader*检索*META-INF/spring.factories*//找到声明的所有SpringApplicationRunListener的实现类并将其实例化//之后逐个调用其started()方法广播SpringBoot要开始执行了SpringApplicationRunListeners listeners getRunListeners(args);//发布应用开始启动事件listeners.starting();try {//初始化参数ApplicationArguments applicationArguments new DefaultApplicationArguments(args);//创建并配置当前SpringBoot应用将要使用的Environment包括配置要使用的PropertySource以及Profile,//并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法广播Environment准备完毕。ConfigurableEnvironment environment prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);//打印bannerBanner printedBanner printBanner(environment);//创建应用上下文context createApplicationContext();//通过*SpringFactoriesLoader*检索*META-INF/spring.factories*获取并实例化异常分析器exceptionReporters getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);//为ApplicationContext加载environment之后逐个执行ApplicationContextInitializer的initialize()方法来进一步封装ApplicationContext//并调用所有的SpringApplicationRunListener的contextPrepared()方法【EventPublishingRunListener只提供了一个空的contextPrepared()方法】//之后初始化IoC容器并调用SpringApplicationRunListener的contextLoaded()方法广播ApplicationContext的IoC加载完成//这里就包括通过**EnableAutoConfiguration**导入的各种自动配置类。prepareContext(context, environment, listeners, applicationArguments, printedBanner);//刷新上下文refreshContext(context);//再一次刷新上下文,其实是空方法可能是为了后续扩展。afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}//发布应用已经启动的事件listeners.started(context);//遍历所有注册的ApplicationRunner和CommandLineRunner并执行其run()方法。//我们可以实现自己的ApplicationRunner或者CommandLineRunner来对SpringBoot的启动过程进行扩展。callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {//应用已经启动完成的监听事件listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;}其实这个方法我们可以简单的总结下步骤为 1. 配置属性 2. 获取监听器发布应用开始启动事件 3. 初始化输入参数 4. 配置环境输出 banner 5. 创建上下文 6. 预处理上下文 7. 刷新上下文 8. 再刷新上下文 9. 发布应用已经启动事件 10. 发布应用启动完成事件其实上面这段代码如果只要分析 tomcat 内容的话只需要关注两个内容即可上下文是如何创建的上下文是如何刷新的分别对应的方法就是 createApplicationContext() 和 refreshContext(context)接下来我们来看看这两个方法做了什么。protected ConfigurableApplicationContext createApplicationContext() {Class!--?-- contextClass this.applicationContextClass;if (contextClass null) {try {switch (this.webApplicationType) {case SERVLET:contextClass Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);break;case REACTIVE:contextClass Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);break;default:contextClass Class.forName(DEFAULT_CONTEXT_CLASS);}}catch (ClassNotFoundException ex) {throw new IllegalStateException(Unable create a default ApplicationContext, please specify an ApplicationContextClass,ex);}}return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);}这里就是根据我们的 webApplicationType 来判断创建哪种类型的 Servlet,代码中分别对应着 Web 类型(SERVLET),响应式 Web 类型REACTIVE),非 Web 类型default),我们建立的是 Web 类型所以肯定实例化 DEFAULT_SERVLET_WEB_CONTEXT_CLASS 指定的类也就是 AnnotationConfigServletWebServerApplicationContext 类我们来用图来说明下这个类的关系通过这个类图我们可以知道这个类继承的是 ServletWebServerApplicationContext,这就是我们真正的主角而这个类最终是继承了 AbstractApplicationContext了解完创建上下文的情况后我们再来看看刷新上下文相关代码如下//类SpringApplication.javaprivate void refreshContext(ConfigurableApplicationContext context) {//直接调用刷新方法refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments.}}}
//类SpringApplication.javaprotected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);((AbstractApplicationContext) applicationContext).refresh();}这里还是直接传递调用本类的 refresh(context)方法最后是强转成父类 AbstractApplicationContext 调用其 refresh()方法,该代码如下// 类AbstractApplicationContext
public void refresh() throws BeansException, 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()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.throw ex;}finally {// Reset common introspection caches in Springs core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}这里我们看到 onRefresh()方法是调用其子类的实现根据我们上文的分析我们这里的子类是 ServletWebServerApplicationContext。//类ServletWebServerApplicationContext
protected void onRefresh() {super.onRefresh();try {createWebServer();}catch (Throwable ex) {throw new ApplicationContextException(Unable to start web server, ex);}}private void createWebServer() {WebServer webServer this.webServer;ServletContext servletContext getServletContext();if (webServer null amp;amp; servletContext null) {ServletWebServerFactory factory getWebServerFactory();this.webServer factory.getWebServer(getSelfInitializer());}else if (servletContext ! null) {try {getSelfInitializer().onStartup(servletContext);}catch (ServletException ex) {throw new ApplicationContextException(Cannot initialize servlet context, ex);}}initPropertySources();}到这里其实庐山真面目已经出来了createWebServer()就是启动 web 服务但是还没有真正启动 Tomcat既然 webServer 是通过 ServletWebServerFactory 来获取的我们就来看看这个工厂的真面目。走进 Tomcat 内部根据上图我们发现工厂类是一个接口各个具体服务的实现是由各个子类来实现的所以我们就去看看 TomcatServletWebServerFactory.getWebServer()的实现。Overridepublic WebServer getWebServer(ServletContextInitializer... initializers) {Tomcat tomcat new Tomcat();File baseDir (this.baseDirectory ! null) ? this.baseDirectory : createTempDir(tomcat);tomcat.setBaseDir(baseDir.getAbsolutePath());Connector connector new Connector(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);return getTomcatWebServer(tomcat);}根据上面的代码我们发现其主要做了两件事情第一件事就是把 Connnctor(我们称之为连接器)对象添加到 Tomcat 中第二件事就是 configureEngine,这连接器我们勉强能理解不理解后面会述说那这个 Engine 是什么呢我们查看 tomcat.getEngine()的源码public Engine getEngine() {Service service getServer().findServices()[0];if (service.getContainer() ! null) {return service.getContainer();}Engine engine new StandardEngine();engine.setName( Tomcat );engine.setDefaultHost(hostname);engine.setRealm(createDefaultRealm());service.setContainer(engine);return engine;}根据上面的源码我们发现原来这个 Engine 是容器我们继续跟踪源码找到 Container 接口上图中我们看到了 4 个子接口分别是 Engine,Host,Context,Wrapper。我们从继承关系上可以知道他们都是容器那么他们到底有啥区别呢我看看他们的注释是怎么说的。/**If used, an Engine is always the top level Container in a Catalina* hierarchy. Therefore, the implementations codesetParent()/code method* should throw codeIllegalArgumentException/code.** author Craig R. McClanahan*/
public interface Engine extends Container {//省略代码
}
/*** p* The parent Container attached to a Host is generally an Engine, but may* be some other implementation, or may be omitted if it is not necessary.* /pp* The child containers attached to a Host are generally implementations* of Context (representing an individual servlet context).** author Craig R. McClanahan*/
public interface Host extends Container {
//省略代码}
/*** /pp* The parent Container attached to a Context is generally a Host, but may* be some other implementation, or may be omitted if it is not necessary.* /pp* The child containers attached to a Context are generally implementations* of Wrapper (representing individual servlet definitions).* /pp** author Craig R. McClanahan*/
public interface Context extends Container, ContextBind {//省略代码
}
/**/pp* The parent Container attached to a Wrapper will generally be an* implementation of Context, representing the servlet context (and* therefore the web application) within which this servlet executes.* /pp* Child Containers are not allowed on Wrapper implementations, so the* codeaddChild()/code method should throw an* codeIllegalArgumentException/code.** author Craig R. McClanahan*/
public interface Wrapper extends Container {//省略代码
}上面的注释翻译过来就是Engine 是最高级别的容器其子容器是 Host,Host 的子容器是 Context,Wrapper 是 Context 的子容器所以这 4 个容器的关系就是父子关系也就是 EngineHostContextWrapper。我们再看看 Tomcat 类的源码://部分源码其余部分省略。
public class Tomcat {
//设置连接器public void setConnector(Connector connector) {Service service getService();boolean found false;for (Connector serviceConnector : service.findConnectors()) {if (connector serviceConnector) {found true;}}if (!found) {service.addConnector(connector);}}//获取servicepublic Service getService() {return getServer().findServices()[0];}//设置Host容器public void setHost(Host host) {Engine engine getEngine();boolean found false;for (Container engineHost : engine.findChildren()) {if (engineHost host) {found true;}}if (!found) {engine.addChild(host);}}//获取Engine容器public Engine getEngine() {Service service getServer().findServices()[0];if (service.getContainer() ! null) {return service.getContainer();}Engine engine new StandardEngine();engine.setName( Tomcat );engine.setDefaultHost(hostname);engine.setRealm(createDefaultRealm());service.setContainer(engine);return engine;}//获取serverpublic Server getServer() {if (server ! null) {return server;}System.setProperty(catalina.useNaming, false);server new StandardServer();initBaseDir();// Set configuration sourceConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(new File(basedir), null));server.setPort( -1 );Service service new StandardService();service.setName(Tomcat);server.addService(service);return server;}//添加Context容器public Context addContext(Host host, String contextPath, String contextName,String dir) {silence(host, contextName);Context ctx createContext(host, contextPath);ctx.setName(contextName);ctx.setPath(contextPath);ctx.setDocBase(dir);ctx.addLifecycleListener(new FixContextListener());if (host null) {getHost().addChild(ctx);} else {host.addChild(ctx);}//添加Wrapper容器public static Wrapper addServlet(Context ctx,String servletName,Servlet servlet) {// will do class for name and set init paramsWrapper sw new ExistingStandardWrapper(servlet);sw.setName(servletName);ctx.addChild(sw);return sw;}}阅读 Tomcat 的 getServer()我们可以知道Tomcat 的最顶层是 Server,Server 就是 Tomcat 的实例一个 Tomcat 一个 Server;通过 getEngine()我们可以了解到 Server 下面是 Service而且是多个一个 Service 代表我们部署的一个应用而且我们还可以知道Engine 容器一个 service 只有一个根据父子关系我们看 setHost()源码可以知道host 容器有多个同理我们发现 addContext()源码下Context 也是多个addServlet()表明 Wrapper 容器也是多个而且这段代码也暗示了其实 Wrapper 和 Servlet 是一层意思。另外我们根据 setConnector 源码可以知道连接器(Connector)是设置在 service 下的而且是可以设置多个连接器(Connector)。根据上面分析我们可以小结下Tomcat 主要包含了 2 个核心组件连接器(Connector)和容器(Container),用图表示如下一个 Tomcat 是一个 Server,一个 Server 下有多个 service也就是我们部署的多个应用一个应用下有多个连接器(Connector)和一个容器Container,容器下有多个子容器关系用图表示如下Engine 下有多个 Host 子容器Host 下有多个 Context 子容器Context 下有多个 Wrapper 子容器。总结SpringBoot 的启动是通过 new SpringApplication()实例来启动的启动过程主要做如下几件事情 1. 配置属性 2. 获取监听器发布应用开始启动事件 3. 初始化输入参数 4. 配置环境输出 banner 5. 创建上下文 6. 预处理上下文 7. 刷新上下文 8. 再刷新上下文 9. 发布应用已经启动事件 10. 发布应用启动完成事件而启动 Tomcat 就是在第 7 步中“刷新上下文”Tomcat 的启动主要是初始化 2 个核心组件连接器(Connector)和容器Container一个 Tomcat 实例就是一个 Server一个 Server 包含多个 Service也就是多个应用程序每个 Service 包含多个连接器Connetor和一个容器Container),而容器下又有多个子容器按照父子关系分别为Engine,Host,Context,Wrapper其中除了 Engine 外其余的容器都是可以有多个。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/914848.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!