spring加载 启动tomcat服务器时,会读取项目中的web.xml文件来启动具体的服务;在servelet3.0后,web.xml文件消失,通过读取包目录中META-INF/services文件夹中描述文件加载启动指定的服务;这种机制称为spi机制;
描述文件名为服务接口类名称该接口由servelet提供,并需要实现onStartup方法;描述文件内容为具体服务启动对象类名称实现刚才的接口,由spring实现
在spring中如下
启动Spring
Spring实现Servelet3.0的SPI规范,实现了接口极其方法onStartup()
Tomcat依据规范调用这个接口的onStartup()方法
Spring依据HandlesTypes注解描述的接口,将所有实现类注入到onStartup()方法的Set集合参数中
下述接口是Spring提供的接口,也是HandlesTypes注解描述中的接口
根据Set集合中的类,创建对象
执行这些对象的onStartup方法
1 2 3 4 5 6 7 8 9 10 11 12 13 public interface WebApplicationInitializer { void onStartup (ServletContext servletContext) throws ServletException; }
启动配置类 由上分析可见spring的启动类为org.springframework.web.SpringServletContainerInitializer,该类负责加载spring所需的组件;
其中@HandlesTypes注解修饰的接口为具体要加载的配置类接口(WebApplicationInitializer),我们可以实现它完成spring框架的整合以及spring相关组件的配置
如下所示MyWebApplicationInitializer也是WebApplicationInitializer接口的子类实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup (ServletContext servletContext) { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext (); context.register(AppConfig.class); DispatcherServlet servlet = new DispatcherServlet (context); ServletRegistration.Dynamic registration = servletContext.addServlet("app" , servlet); registration.setLoadOnStartup(1 ); registration.addMapping("/app/*" ); } }
我们继承AbstractAnnotationConfigDispatcherServletInitializer并实现它的抽象方法以达到自定义配置的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 package com.db.common.config;import javax.servlet.FilterRegistration;import javax.servlet.ServletContext;import javax.servlet.ServletException;import org.springframework.web.filter.DelegatingFilterProxy;import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;public class AppWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override public void onStartup (ServletContext servletContext) throws ServletException { System.out.println("onStartup()" ); registerContextLoaderListener(servletContext); registerFilter(servletContext); registerDispatcherServlet(servletContext); } private void registerFilter (ServletContext servletContext) { FilterRegistration.Dynamic dy= servletContext.addFilter("filterProxy" , DelegatingFilterProxy.class); dy.setInitParameter("targetBeanName" ,"shiroFilterFactory" ); dy.addMappingForUrlPatterns( null , false ,"/*" ); } @Override protected Class<?>[] getRootConfigClasses() { System.out.println("getRootConfigClasses()" ); return new Class []{AppRootConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { System.out.println("getServletConfigClasses()" ); return new Class []{AppMvcConfig.class}; } @Override protected String[] getServletMappings() { System.out.println("getServletMappings()" ); return new String []{"*.do" }; } }
SpringIOC ioc容器核心来源于两个map,分别以Map<String beanName,BeanDefinition definition>,Map<String beanName,Object object>的方式存储数据;
他们都属于BeanFactory接口下的对象
IOC加载流程 核心控制类 AbstractApplicationContext类的refresh()方法控制了IOC容器的加载流程,其中比较关键的几步如下:
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();,创建BeanFactory,注册BeanDefinition
prepareBeanFactory(beanFactory);,准备类加载器,用于创建对象
finishBeanFactoryInitialization(beanFactory);,初始化singleton的Bean对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 @Override public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
创建BeanFactory,注册BeanDefinition 需要注意以下几点
初始三各类继承关系如下,AbstractApplicationContext→AbstractRefreshableApplicationContext→AbstractXmlApplicationContext
AbstractRefreshableApplicationContext类会创建Bean工厂“DefaultListableBeanFactory”该工厂内涵几个核心Map,后续流程中会被注入到BeanDefinitionReader对象中用于BeanDefinition的注入
DefaultBeanDefinitionDocumentReader通过委派BeanDefinitionParserDelegate来实现BeanDefinition的封装,核心流程均由这个被委派这完成
后续会通过BeanDefinitionReaderUtils的静态方法registerBeanDefinition()注册BeanDefition,实际上Spring框架在多个地方都调用该方法手动注册一些Spring核心类
准备类加载器 该方法主要职责在第一行,设置类加载器;
需要注意,目前该方法始终是在AbstractApplicationContext类中的,而AbstractApplicationContext继承自DefaultResourceLoader,在DefaultResourceLoader的无参构造函数中就通过this.classLoader = ClassUtils.getDefaultClassLoader();来创建获取类加载器
ClassUtils是Spring框架的类对象操作工具类,可提取出来学习利用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 protected void prepareBeanFactory (ConfigurableListableBeanFactory beanFactory) { beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver (beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar (this , getEnvironment())); beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor (this )); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this ); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this ); beanFactory.registerResolvableDependency(ApplicationContext.class, this ); beanFactory.addBeanPostProcessor(new ApplicationListenerDetector (this )); if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor (beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader (beanFactory.getBeanClassLoader())); } if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
后置处理器 后置处理器有两种,BeanFactoryPostProcessor和BeanPostProcessor
BeanFactoryPostProcessor:用于拓展Spring框架 ,内部可得到Bean容器,操作BeanDefinition
BeanPostProcessor:用于增加Bean生命周期操作
此时还没有创建Bean对象,这里只讲BeanFactoryPostProcessor,Spring主要的后置处理较多,这里距离三个常用到的
PropertySourcesPlaceholderConfigurer:处理配置类占位符${..}
ConfigurationClassParser:识别注解标签,创建对应的BeanDefiniton
初始化Bean对象 Bean对象的初始化利用到了反射技术,核心操作类如图可见为AbstractAutowireCapableBeanFactory.java,它负责了bean对象的创建,属性注入,init方法和后置处理器的调度使用
可将getBean()方法看作bean的初始化开启方法,我们经常通过applictionContext.getBean()方法获取bean,两者是同一个方法
SpringMVC SpringMVC核心是DispatcherServlet对象,核心方法是doDispatch()
由于DispatcherServlet是个Servlet对象,虽然没有doGet,doPost方法(实际已被父类实现),但请求最终会进入该类的doService()->doDispatch()
Controller对象中的方法和映射如何匹配?
1 2 3 4 5 6 7 @Controller public class MyController { @RequestMapping("doIndexUI") public String doIndexUI () { return "starter" ; } }
SpringMvc找Controller流程
扫描项目所有包,注册所有注解和配置描述的bean,由ioc容器预先完成
@拿到所有Controller类
遍历类中的所有方法对象Method.class
判断方法是否添加了@RequestMapping注解
将RequestMapping注解中的描述如:”doIndexUI”作为key,步骤4的方法对象作为value存入map集合中
容器启动完成
根据用户发送的请求,拦截获取URI 注:URL=http://localhost:80/test.do URI=/test.do
根据URI(/test.do)查找Map集合获取Method方法对象
通过反射调用Method方法
DispatcherSerblet主流程 注意,此时容器已启动完成,用户请求发送通过servlet传递进入doDispatch()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 protected void doDispatch (HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null ; boolean multipartRequestParsed = false ; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null ; Exception dispatchException = null ; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); mappedHandler = getHandler(processedRequest); if (mappedHandler == null ) { noHandlerFound(processedRequest, response); return ; } HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = "GET" .equals(method); if (isGet || "HEAD" .equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest (request, response).checkNotModified(lastModified) && isGet) { return ; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return ; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return ; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { dispatchException = new NestedServletException ("Handler dispatch failed" , err); } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException ("Handler processing failed" , err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null ) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
获取MethodHandler
通过getHandler(processedRequest);开启
MethodHandler可能是Controller控制器的封装类,也可能是对应Method对象的封装类
DispacherServlet对象有一个HandelrMapping对象集合,HandlerMapping对象里的Map集合用来存储之前描述的Method对象;之所以有不同的HandlerMapping是由于Spring有多种Controller的实现,需要不同的Handler处理
最终HandlerMapping们会通过自身集合中的Map集合获取到对应的Method或对象
上述代码最终返回HandlerMethod,它实际上是uri和对应Method对象的包装类,也可以理解为Controller
由图可见,不同的HandlerMapping有不同的Map集合,分情况进入
Controller案例1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Controller @RequestMapping("/ControllerType1/") public class ControllerType1 { @RequestMapping("getPathValue") @ResponseBody public String testController (@PathVariable String name) { System.out.println("Controller2执行" ); System.out.println("hello," +name); return "hello," +name; } }
Controller案例2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Component("/ControllerType2") public class ControllerType2 implements Controller { @Override public ModelAndView handleRequest (HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("Controller2执行" ); return new ModelAndView ("Controller2,say hello" ); } }
请求分发 handlerAdapter.handle()
根据情况调用适当的适配器后,通过适配器调用实际要进入的方法,这里分上述两个Controller案例分析
案例一,基于实现Controller接口 原理很简单,直接调用Controller对象的的对应方法即可
1 2 3 4 5 6 7 8 public class SimpleControllerHandlerAdapter implements HandlerAdapter { public ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); } }
案例二,基于注解RequestMapping 部分源码跳过
获取参数处理器 参数处理器中的参数指的时Controller中映射方法的参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private HandlerMethodArgumentResolver getArgumentResolver (MethodParameter parameter) { HandlerMethodArgumentResolver result = this .argumentResolverCache.get(parameter); if (result == null ) { for (HandlerMethodArgumentResolver resolver : this .argumentResolvers) { if (resolver.supportsParameter(parameter)) { result = resolver; this .argumentResolverCache.put(parameter, result); break ; } } } return result; }
举例几个参数处理器案例
当请求方法中有@RequestBody注解时,直接通过参数中的注解判断
1 2 3 4 @Override public boolean supportsParameter (MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); }
当请求方法参数中有@RequestParam时,通过是否含注解判断
1 2 3 4 5 6 @Override public boolean supportsParameter (MethodParameter parameter) { RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class); return (requestParam != null && Map.class.isAssignableFrom(parameter.getParameterType()) && !StringUtils.hasText(requestParam.name())); }
当请求方法参数中有@PathVariable也同理
1 2 3 4 5 6 @Override public boolean supportsParameter (MethodParameter parameter) { PathVariable ann = parameter.getParameterAnnotation(PathVariable.class); return (ann != null && Map.class.isAssignableFrom(parameter.getParameterType()) && !StringUtils.hasText(ann.value())); }
不同参数处理器有不同的操作,依据需要装配的类型而定,后续不一一例举了,可自行查看HandlerMethodArgumentResolver接口下的子类
SpringAOP 代理对象创建 代理对象创建在Bean生命周期init方法之后执行,由Spring内置的后置处理器BeanPostProcess实现
该方法在AbstractAutowireCapableBeanFactory类中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Override public Object applyBeanPostProcessorsAfterInitialization (Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null ) { return result; } result = current; } return result; }
代理对象创建主要逻辑
具体实现通知类为AbstractAutoProxyCreator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 protected Object wrapIfNecessary (Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this .targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this .advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this .advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null ); if (specificInterceptors != DO_NOT_PROXY) { this .advisedBeans.put(cacheKey, Boolean.TRUE); Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource (bean)); this .proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this .advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 protected Object createProxy (Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this .beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this .beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory (); proxyFactory.copyFrom(this ); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true ); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this .freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true ); } return proxyFactory.getProxy(getProxyClassLoader()); }
ProxyFactory 代理后置处理器会createAopProxy().getProxy(classLoader);方法依据条件调用后对应的代理创建方法;
工厂依据事先设置的属性判断创建何种代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public AopProxy createAopProxy (AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null ) { throw new AopConfigException ("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation." ); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy (config); } return new ObjenesisCglibAopProxy (config); } else { return new JdkDynamicAopProxy (config); } }
通知的执行 无论切面是基于JDK还是CGLIB实现,均会调用特定方法获取到通知集合(adviceChain) ,通过这个集合SpringAOP基于责任链的模式实现了通知方法的切入
通知通过传递MethodInvocation对象实现责任链模式
methodInvocation.proceed()能进入MethodInvocation对象中遍历数组找到下一个通知并进入对应invoke()方法,它们以类似递归的方式执行
invokeAdviceMethod()方法为调用通知,底层基于反射调用对应通知
通知具体分析 五种不同的通知实现的方式和承担的职责不同,以下对核心代码分析
arround环绕同通知 1 2 3 4 5 6 7 8 9 10 11 12 13 @Override public Object invoke (MethodInvocation mi) throws Throwable { if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException ("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); } ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); JoinPointMatch jpm = getJoinPointMatch(pmi); return invokeAdviceMethod(pjp, jpm, null , null ); }
before前置通知 1 2 3 4 5 6 7 @Override public Object invoke (MethodInvocation mi) throws Throwable { this .advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); }
after后置通知 1 2 3 4 5 6 7 8 9 10 11 public Object invoke (MethodInvocation mi) throws Throwable { try { return mi.proceed(); } finally { invokeAdviceMethod(getJoinPointMatch(), null , null ); } }
afterReturning返回通知 1 2 3 4 5 6 7 public Object invoke (MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); this .advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; }
afterThrowing异常通知 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public Object invoke (MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { invokeAdviceMethod(getJoinPointMatch(), null , ex); } throw ex; } }