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

上篇大概介绍了模板方法,那么在现实开发中模板方法大概有哪些应用呢?

实际上这个模式是我个人最喜欢的模式之一,它可以说是大部分框架的重要基石,最近我在看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是如何通过模板方法做到实现基础逻辑的同时提供扩展性的。其实我们不难看出来,模板方法就是框架的灵魂(框架本身就是一种模板:-))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值