SpringMVC Interceptor 解析,加载源码流程
本文说什么
interceptor从哪里来,怎么创建,怎么加载,在哪里被使用,以xml的配置形式为例
xml配置解析阶段
直接打开spring-webmvc的源码包找到spring.handlers,这个是spring对于组件xml解析模块。
打开后一看说明,mvc这个标签是,是通过这个 org.springframework.web.servlet.config.MvcNamespaceHandler,解析的直接找到看一下
http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
发现是
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("velocity-configurer", new VelocityConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
}
}
这个就直接找到<mvc:*> 的所有表现对应的解析类了,直接找到
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
打开看一下,
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compDefinition);
RuntimeBeanReference pathMatcherRef = null;
if (element.hasAttribute("path-matcher")) {
pathMatcherRef = new RuntimeBeanReference(element.getAttribute("path-matcher"));
}
List<Element> interceptors = DomUtils.getChildElementsByTagName(element, "bean", "ref", "interceptor");
for (Element interceptor : interceptors) {
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
mappedInterceptorDef.setSource(parserContext.extractSource(interceptor));
mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
ManagedList<String> includePatterns = null;
ManagedList<String> excludePatterns = null;
Object interceptorBean;
if ("interceptor".equals(interceptor.getLocalName())) {
includePatterns = getIncludePatterns(interceptor, "mapping");
excludePatterns = getIncludePatterns(interceptor, "exclude-mapping");
Element beanElem = DomUtils.getChildElementsByTagName(interceptor, "bean", "ref").get(0);
interceptorBean = parserContext.getDelegate().parsePropertySubElement(beanElem, null);
}
else {
interceptorBean = parserContext.getDelegate().parsePropertySubElement(interceptor, null);
}
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, includePatterns);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, excludePatterns);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(2, interceptorBean);
if (pathMatcherRef != null) {
mappedInterceptorDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
}
String beanName = parserContext.getReaderContext().registerWithGeneratedName(mappedInterceptorDef);
parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, beanName));
}
parserContext.popAndRegisterContainingComponent();
return null;
}
就找到了对于这些标签的解析,然后把 interceptors 节点全部生成对应的RootBeanDefinition放入到spring容器中,对于xml的解析都结束了容器中已经都全部的interceptor了
加载interceptor
直接找 AbstractHandlerMapping 这个类,handlerMapping的基础实现类,里面把interceptor 初始化,分类。因为他继承实现了webapplicationObjectSupport。有几个初始化方法,这就是初始化把interceptor的入口
org.springframework.web.servlet.handler.AbstractHandlerMapping
sping注入applicationContext,就是调用 初始化的时候调用 initApplicationContext 中开始填充handlerMapping中的intercetor 集合
入口代码展示
pjavaublic abstract class ApplicationObjectSupport implements ApplicationContextAware {
.........
@Override
public final void setApplicationContext(ApplicationContext context) throws BeansException {
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
this.messageSourceAccessor = null;
}
else if (this.applicationContext == null) {
// Initialize with passed-in context.
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(
"Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
}
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
initApplicationContext(context); // 入口 入口 入口 入口 入口 入口
}
else {
// Ignore reinitialization if same context passed in.
if (this.applicationContext != context) {
throw new ApplicationContextException(
"Cannot reinitialize with different application context: current one is [" +
this.applicationContext + "], passed-in one is [" + context + "]");
}
}
}
protected void initApplicationContext(ApplicationContext context) throws BeansException {
initApplicationContext();
}
protected void initApplicationContext() throws BeansException {
//子类实现
}
.........
}
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
implements HandlerMapping, Ordered {
.......
@Override
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.mappedInterceptors);//从spring中找到interceptor
initInterceptors();
}
/**
* 在容器中找到所有的interceptor,一个个放入 AbstractHandlerMapping,然后在对其初始化分类,后面就可以用了
**/
protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
getApplicationContext(), MappedInterceptor.class, true, false).values());
}
/**
* 分类
**/
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
if (interceptor instanceof MappedInterceptor) {
this.mappedInterceptors.add((MappedInterceptor) interceptor);
}
else {
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
}
......
}
这样整个流程就搞一段落
总结
mvc自己的包,自己定义标签,解析xml把所有的interceptor放入spring中,在初始化handlerMapping 中在一个个找出来,放到 handlermapping 中,在初始化分类准备后面使用
ps:
MappedInterceptor 包换 MappedInterceptor
public final class MappedInterceptor {
// 需要拦截的url
private final String[] includePatterns;
// 排除的url
private final String[] excludePatterns;
private final HandlerInterceptor interceptor;
// 判断是否符合
private PathMatcher pathMatcher;