您的位置:首页 > 其它

设计模式——模板方法(2)

2016-03-16 21:25 127 查看
上篇大概介绍了模板方法,那么在现实开发中模板方法大概有哪些应用呢?

实际上这个模式是我个人最喜欢的模式之一,它可以说是大部分框架的重要基石,最近我在看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是如何通过模板方法做到实现基础逻辑的同时提供扩展性的。其实我们不难看出来,模板方法就是框架的灵魂(框架本身就是一种模板:-))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: