publiccms多站点下静态资源获取过程(war外部web容器启动方式)

publiccms多站点下静态资源获取过程(war外部web容器启动方式)

原理:

1.在servlet 3.0+ 中,可以以 Code-based Approach 方式动态取代 以前 web.xml方式的配置,如配置 servlet, filter, listener.

       为了支持可以不使用web.xml。提供了ServletContainerInitializer,它可以通过SPI(Serial Peripheral Interface)机制。
       SPI机制使用:
       1.当启动web容器的时候(eg:tomcat容器),会自动到添加的相应jar包下找到META-INF/services下以ServletContainerInitializer的全路径名称命名的文件;
       2.它的内容为ServletContainerInitializer实现类的全路径,并将它们实例化。
       3.既然这样的话,那么SpringServletContainerInitializer作为ServletContainerInitializer的实现类,它的jar包下也应该有相应的文件。

       如:spring-web-4.3.7.RELEASE.jar 包下的/META-INF/services/javax.servlet.ServletContainerInitializer 就存在了一个SPI,其内容为 对ServletContainerInitializer实现类的全路径:org.springframework.web.SpringServletContainerInitializer
       
       4.对ServletContainerInitializer的实现类SpringServletContainerInitializer分析:

@HandlesTypes({WebApplicationInitializer.class}) 
public class SpringServletContainerInitializer implements ServletContainerInitializer {   //实现ServletContainerInitializer接口,用于取代web.xml编写。
	public SpringServletContainerInitializer() {}
	@Override
	public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
		List<WebApplicationInitializer> initializers = new LinkedList();
		Iterator var4;
		if(webAppInitializerClasses != null) {
			var4 = webAppInitializerClasses.iterator();
 
			while(var4.hasNext()) {
				Class<?> waiClass = (Class)var4.next();
				if(!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
					try {
						initializers.add((WebApplicationInitializer)waiClass.newInstance());
					} catch (Throwable var7) {
						throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
					}
				}
			}
		}
 
		if(initializers.isEmpty()) {
			servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
		} else {
			servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
			AnnotationAwareOrderComparator.sort(initializers);
			var4 = initializers.iterator();
 
			while(var4.hasNext()) {
				WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
				initializer.onStartup(servletContext);//重点:循环调用WebApplicationInitializer实现类的onStartup(..)方法。
			}
 
		}
	}
}

                1.如上的SpringServletContainerInitializer作为ServletContainerInitializer的实现类,通过SPI机制,在web容器加载的时会自动调用SpringServletContainerInitializer类,并实例化。
                2.这个类上还有一个注解@HandlesTypes,它的作用是将感兴趣的一些类注入到ServletContainerInitializerde), 而这个类的方法又会扫描找到WebApplicationInitializer的实现类,调用它的onStartup方法,从而起到启动web.xml相同的作用。
                  eg:该注解会将{}内的类的 全部实现类打包 作为 SpringServletContainerInitializer类 中的onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)函数的第一个参数(Set<Class<?>> webAppInitializerClasses) 传入给该类中的onStartup函数使用。

        5.如此一来,我们可以通过实现WebApplicationInitializer接口来达到在初始化容器的时候,动态完成类似web.xml路由配置。
        
        
2.通过code-base方式配置servlet,filter等。

    功能:站点静态页面处理器 (多站点下,分别获取对应站点下的静态文件)
    
    1.创建ResourceInitializer类,用于注册多站点静态资源servlet

    package config.initializer;

    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRegistration.Dynamic;

    import org.springframework.web.WebApplicationInitializer;
    import org.springframework.web.context.support.HttpRequestHandlerServlet;

    /**
     * 
     * ResourceInitializer Servlet3.0 工程入口类
     *
     */
    public class ResourceInitializer implements WebApplicationInitializer {

        public void onStartup(ServletContext servletContext) throws ServletException {
            Dynamic registration = servletContext.addServlet("defaultServlet", new HttpRequestHandlerServlet());
            registration.setLoadOnStartup(1);
            registration.addMapping(new String[] { "/resource/*", "/favicon.ico" });
            Dynamic webfileRegistration = servletContext.addServlet("webfileServlet", new HttpRequestHandlerServlet());
            webfileRegistration.setLoadOnStartup(0);
            webfileRegistration.addMapping(new String[] { "/webfile/*" });
        }
    }

    代码讲解:
        servletContext.addServlet("webfileServlet", new HttpRequestHandlerServlet());
        原型:ServletRegistration.Dynamic addServlet(java.lang.String servletName, Servlet servlet)//注册一个servlet到对应的context容器里;
                1.servletName:servlet名称 
                2.servlet 对应需要执行的servlet对象实例
                    
                
                注意:由于出于性能考虑,可以使用spring的ioc功能;
                      所以,需要使用到由spring提供的简单HttpServlet作为一个从spring容器中获取对象的一个中转标识类-->HttpRequestHandlerServlet
                            HttpRequestHandlerServlet:
                                  #简单的HttpServlet,它委托给Spring的根Web应用程序上下文(Spring root WebApplicationContext)中定义的HttpRequestHandler bean。
                               #目标bean名称必须与web.xml(如果是code-base方式,即上述addServlet函数中的servletName)中定义的HttpRequestHandlerServlet servlet-name匹配。

                3.由上述可知,只要在Spring配置类中添加一个名字与servletName一样的,并且返回一个 HttpRequestHandler 类型的bean就好了;
          eg:
        1.由于需要返回不同站点的静态资源,所以需要使用org.springframework.web.servlet.resource.ResourceHttpRequestHandler用于对静态资源的读取返回。“locations”属性获取一个Spring Resource位置列表,该处理程序允许从该位置提供静态资源。资源可以从类路径位置提供,例如。 “classpath:/ META-INF / public-web-resources /”,允许在jar文件中方便地打包和提供诸如.js,.css等资源。

自定义资源处理器:

public class MultiSiteWebHttpRequestHandler extends ResourceHttpRequestHandler {
	private UrlPathHelper urlPathHelper = new UrlPathHelper();
	private SiteComponent siteComponent;

	public MultiSiteWebHttpRequestHandler(SiteComponent siteComponent) {
		this.siteComponent = siteComponent;
	}
	
	/*重写父类的getResource,用于获取对应站点的静态资源路径*/
	@Override
	protected Resource getResource(HttpServletRequest request) throws IOException {
		String path = urlPathHelper.getLookupPathForRequest(request);
		if (path.endsWith(Base.SEPARATOR)) {
			path += getDefaultPage();
		}
		Resource resource = new FileSystemResource(
				siteComponent.getWebFilePath(siteComponent.getSite(request.getServerName()), path));  //直接通过siteComponent.getWebFilePath获得对应站点的资源绝对路径获取静态资源到Resoure对象实例
		if (resource.exists() && resource.isReadable()) {
			return resource;
		} else {
			return null;
		}
	}
}

  
    2.在springboot的配置类中注册一个servlet到对应的context容器里;(即addServlet中同名的bean)

 /**
     * <p>
     * 资源处理器
     * </p>
     * <p>
     * DefaultServletHttpRequestHandler
     * </p>
     * 
     * @return
     */
    @Bean
    public HttpRequestHandler defaultServlet() {
        DefaultServletHttpRequestHandler bean = new DefaultServletHttpRequestHandler();
        return bean;
    }

    /**
     * <p>
     * 站点静态页面处理器
     * </p>
     * <p>
     * DefaultServletHttpRequestHandler
     * </p>
     * 
     * @return
     */
    @Bean
    public HttpRequestHandler webfileServlet(SiteComponent siteComponent) {
        MultiSiteWebHttpRequestHandler bean = new MultiSiteWebHttpRequestHandler(siteComponent);
        return bean;
    }

    注意:如有错,请不吝赐教哦!!!

展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值