设计模式——模板方法(2)
2016-03-16 21:25
127 查看
上篇大概介绍了模板方法,那么在现实开发中模板方法大概有哪些应用呢?
实际上这个模式是我个人最喜欢的模式之一,它可以说是大部分框架的重要基石,最近我在看spring mvc的源码,所以就那里面的一个使用来做例子吧:
Step1. AbstractAnnotationConfigDispatcherServletInitializer(以下简称A类):
第一次看到这个类的时候我默默地去查了一下JVM所支持的最长类名~~~~~~~言归正传注意到该类的两个方法:
可以看到在createServletApplicationContext和createRootApplicationContext中分别用到了用户定义的代码
Step2: AbstractDispatcherServletInitializer
A类实际上是继承了AbstractDispatcherServletInitializer,我们就主要关注以下代码就好:
可以看到createServletApplicationContext又怎么是在父类里面被使用的
Step3: WebApplicationInitializer
如果接着看AbstractDispatcherServletInitializer的父类WebApplicationInitializer就会发现createRootApplicationContext()就是在这类的registerContextLoaderListener方法中调用的。
总结:上面用配置DispatcherServlet做例子解释了Spring MVC是如何通过模板方法做到实现基础逻辑的同时提供扩展性的。其实我们不难看出来,模板方法就是框架的灵魂(框架本身就是一种模板:-))
实际上这个模式是我个人最喜欢的模式之一,它可以说是大部分框架的重要基石,最近我在看spring mvc的源码,所以就那里面的一个使用来做例子吧:
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class MyAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { RootConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { WebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } }上面是一个简单的Web项目的配置。是简单到逆天了吧~只需要继承AbstractAnnotationConfigDispatcherServletInitializer,再重写三个get方法就OK?没错,我们来分析一下spring mvc是怎么做的吧:
Step1. AbstractAnnotationConfigDispatcherServletInitializer(以下简称A类):
第一次看到这个类的时候我默默地去查了一下JVM所支持的最长类名~~~~~~~言归正传注意到该类的两个方法:
/** * {@inheritDoc} * <p>This implementation creates an {@link AnnotationConfigWebApplicationContext}, * providing it the annotated classes returned by {@link #getRootConfigClasses()}. * Returns {@code null} if {@link #getRootConfigClasses()} returns {@code null}. */ @Override protected WebApplicationContext createRootApplicationContext() { Class<?>[] configClasses = getRootConfigClasses(); // getRootConfigClasses()就是在这里被调用的 if (!ObjectUtils.isEmpty(configClasses)) { AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext(); rootAppContext.register(configClasses); return rootAppContext; } else { return null; } } /** * {@inheritDoc} * <p>This implementation creates an {@link AnnotationConfigWebApplicationContext}, * providing it the annotated classes returned by {@link #getServletConfigClasses()}. */ @Override protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext servletAppContext = new AnnotationConfigWebApplicationContext(); Class<?>[] configClasses = getServletConfigClasses(); // getServletConfigClasses()就是在这里被调用的 if (!ObjectUtils.isEmpty(configClasses)) { servletAppContext.register(configClasses); } return servletAppContext; }
可以看到在createServletApplicationContext和createRootApplicationContext中分别用到了用户定义的代码
Step2: AbstractDispatcherServletInitializer
A类实际上是继承了AbstractDispatcherServletInitializer,我们就主要关注以下代码就好:
/** * Register a {@link DispatcherServlet} against the given servlet context. * <p>This method will create a {@code DispatcherServlet} with the name returned by * {@link #getServletName()}, initializing it with the application context returned * from {@link #createServletApplicationContext()}, and mapping it to the patterns * returned from {@link #getServletMappings()}. * <p>Further customization can be achieved by overriding {@link * #customizeRegistration(ServletRegistration.Dynamic)}. * @param servletContext the context to register the servlet against */ protected void registerDispatcherServlet(ServletContext servletContext) { String servletName = getServletName(); Assert.hasLength(servletName, "getServletName() must not return empty or null"); WebApplicationContext servletAppContext = createServletApplicationContext(); // 创建ServletApplicationContext() Assert.notNull(servletAppContext, "createServletApplicationContext() did not return an application " + "context for servlet [" + servletName + "]"); DispatcherServlet dispatcherServlet = new DispatcherServlet(servletAppContext); ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); Assert.notNull(registration, "Failed to register servlet with name '" + servletName + "'." + "Check if there is another servlet registered under the same name."); registration.setLoadOnStartup(1); registration.addMapping(getServletMappings()); registration.setAsyncSupported(isAsyncSupported()); Filter[] filters = getServletFilters(); // 这个方法默认是返回null,重载就可以定义过滤器了 if (!ObjectUtils.isEmpty(filters)) { for (Filter filter : filters) { registerServletFilter(servletContext, filter); } } customizeRegistration(registration); // 这个方法的默认实现是空,重载就可以对DispatcherServlet做一些定制 }
可以看到createServletApplicationContext又怎么是在父类里面被使用的
Step3: WebApplicationInitializer
如果接着看AbstractDispatcherServletInitializer的父类WebApplicationInitializer就会发现createRootApplicationContext()就是在这类的registerContextLoaderListener方法中调用的。
总结:上面用配置DispatcherServlet做例子解释了Spring MVC是如何通过模板方法做到实现基础逻辑的同时提供扩展性的。其实我们不难看出来,模板方法就是框架的灵魂(框架本身就是一种模板:-))