Spring IOC生命周期扩展点(二)——使用流程

在这里插入图片描述
上图描述了IOC容器使用过程(即getBean),其中红色的模块为spring为用户在spring ioc容器生命阶段内提供的扩展点。
在容器初始化阶段完成后,当用户使用getBean获取对象时,触发容器初始化对象的流程。

1、InstantiationAwareBeanPostProcessor

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

	Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
	
	boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
	
	PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;

}

简单介绍

在容器初始化的过程中,容器会检测所有BeanPostProcessor类型的bean,并将其向容器注册,在这个过程中,容器若发现当前bean为InstantiationAwareBeanPostProcessor类型时,会将此状态记录下来。在初始化bean的过程中,发现存在InstantiationAwareBeanPostProcessor时:

  • 在为其实例化之前,执行postProcessBeforeInstantiation方法,如果返回了一个实例,则不会执行容器默认的实例化方法;
  • 在实例化之后,设置属性值之前,会执行其postProcessAfterInstantiation方法,当返回false是,也不会在为其设置属性;
  • 在容器解析完属性值后,为bean设置属性值前,执行postProcessPropertyValues,允许对其属性值进行修改,当返回为null是,也不会为其设置属性值。

InstantiationAwareBeanPostProcessor是BeanPostProcessor的子类,所以也具有它其他的特性。

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import java.beans.PropertyDescriptor;

public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return false;
    }

    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        return null;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return null;
    }
}

注意:Instantiation为实例化,Initialization为初始化

应用实例——AbstractAutoProxyCreator

AbstractAutoProxyCreator是spring容器AOP实现的核心类之一,aop进行织入的bean较多时,简单采用ProxyFacotryBean无疑会增加很多工作量,同时由于要从ProxyFactoryBean获得代理对象,也会使应用和Spring之间的耦合度增加,并且可维护性不强。AbstractAutoProxyCreator将我们从这些繁琐的工作中解放出来,可批量的为某一类别的bean自动生成代理。

public abstract class AbstractAutoProxyCreator extends ProxyConfig
		implements SmartInstantiationAwareBeanPostProcessor, BeanClassLoaderAware, BeanFactoryAware,
		Ordered, AopInfrastructureBean {
	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(beanClass, beanName);
		if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}
		if (beanName != null) {
			TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
			// 是否包含自定义TagetSource
			if (targetSource != null) {
				this.targetSourcedBeans.add(beanName);
				Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
				// 创建代理对象
				Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
				this.proxyTypes.put(cacheKey, proxy.getClass());
				return proxy;
			}
		}
		return null;
	}
	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) {
		return true;
	}
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean;
	}
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			// 是否已经提前暴露引用(spring解决循环依赖问题)
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (this.nonAdvisedBeans.contains(cacheKey)) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.nonAdvisedBeans.add(cacheKey);
			return bean;
		}
		// 获取当前bean增强
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.add(cacheKey);
			// 生成代理
			Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.nonAdvisedBeans.add(cacheKey);
		return bean;
	}
	protected Object createProxy(
			Class<?> beanClass, String beanName, 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);
		for (Advisor advisor : advisors) {
			proxyFactory.addAdvisor(advisor);
		}
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
		return proxyFactory.getProxy(getProxyClassLoader());
	}
	protected abstract Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException;
}

上面是摘录的AbstractAutoProxyCreator的部分源码。自动代理发生的位置存在两个:

  • postProcessBeforeInstantiation对象实例化之前,当存在用户自定义TargetSource时,使用此TargetSource生成代理对象;
  • postProcessAfterInitialization对象初始化之后,为bean生成默认的SingletonTargetSource生成代理对象。

getAdvicesAndAdvisorsForBean是一个抽象方法,用户获取当前bean的增强,spring提供了几个默认实现:

  • BeanNameAutoProxyCreator:基于Bean配置名规则的自动代理生成器,允许为一组特定配置名的Bean自动创建代理实例的代理创建器;
  • DefaultAdvisorAutoProxyCreator:基于Advisor匹配机制的自动代理创建器,它会对容器中的所有Advisor进行扫描,自动将这些切面应用到匹配的Bean中,它也支持前缀匹配;
  • AspectJAwareAdvisorAutoProxyCreator:基于xml的AspectJ配置切入的Bean自动创建代理实例;
  • AnnotationAwareAspectJAutoProxyCreator:基于AspectJ注解切入的Bean自动创建代理实例。

拓展

spring aop
底层实现:
  • JDK的动态代理:在运行期,目标类加载后,为接口动态生成代理类,将切面织入到代理类中,切入的目标类需要实现接口;
  • CGLIB:在运行期,目标类加载后,动态生成目标类的子类,将切面逻辑加入到子类中,目标类的方法用final修饰时无法进行织入。
AspectJ与spring aop的关系:

AspectJ一款以静态AOP实现的框架,在编译期以字节码形式完成对目标类加强。spring aop提供了对AspectJ通过注解标签完成加强功能的支持,并未使用AspectJ的编译器等。

TargetSource机制
public interface TargetClassAware {
	Class<?> getTargetClass();
}

TargetSource(目标源)是被代理的target(目标对象)实例的来源。TargetSource被用于获取当前MethodInvocation(方法调用)所需要的target(目标对象),这个target通过反射的方式被调用(如:method.invode(target,args))。换句话说,proxy(代理对象)代理的不是target,而是TargetSource。

那么问题来了:为什么SpringAOP代理不直接代理target,而需要通过代理TargetSource(target的来源,其内部持有target),间接代理target呢?

通常情况下,一个proxy(代理对象)只能代理一个target,每次方法调用的目标也是唯一固定的target。但是,如果让proxy代理TargetSource,可以使得每次方法调用的target实例都不同(当然也可以相同,这取决于TargetSource实现)。这种机制使得方法调用变得灵活,可以扩展出很多高级功能。

TargetSource组件本身与SpringIoC容器无关,换句话说,target的生命周期不一定是受spring容器管理的,我们以往的XML中的AOP配置,只是对受容器管理的bean而言的,我们当然可以手动创建一个target,同时使用Spring的AOP框架(而不使用IoC容器)。

  • SingletonTargetSource:单例的TargetSource;
  • PrototypeTargetSource:多例的TargetSource;
  • HotSwappableTargetSource:可热替换的TargetSource;
  • CommonsPool2TargetSource:对象池TargetSource;
  • ThreadLocalTargetSource:线程单独持有的TargetSource;
  • LazyInitTargetSource:延迟加载的TargetSource。
循环依赖问题

在AbstractAutoProxyCreator为目标类生成代理前,有if(!this.earlyProxyReferences.contains(cacheKey)) 这样一个判断,是否已经提前将引用暴露出去,避免了重复创建,这个earlyProxyReferences就是spring解决循环依赖的缓存。下面我们就分步骤解析一下spring是如何解决的。

  1. 在容器为bean实例化前,首先会通过getSingleton()从缓存中获取,spring为我们提供了三级缓存。
// 单例对象的缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
// 单例对象工厂的缓存	
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
// 提前暴光的单例对象的缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}
  • Spring首先从一级缓存singletonObjects中获取。
  • 如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取;
  • 如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取;
  • 获取到以后,将其从三级缓存移动到了二级缓存;
  • 缓存不存在,进入实例化流程。
  1. 在对象实例化成功后,通过addSingletonFactory将其放入singletonFactories缓存中。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
			throws BeanCreationException {
	// 实例化对象
	......
	addSingletonFactory(beanName, new ObjectFactory<Object>() {
					@Override
					public Object getObject() throws BeansException {
						return getEarlyBeanReference(beanName, mbd, bean);
					}
	});
	......
	// 对象初始化
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
}

Spring的循环依赖的理论依据其实是基于Java的引用传递,当我们获取到对象的引用时,对象的属性是可以延后设置的,但是构造器必须是在获取引用之前,所以在spring实例化对象成功后,为其构造了一个ObjectFactory放入缓存,当其他的bean在初始化需要依赖他是,可以提前从缓存中获取到他的引用。

  1. 通过getEarlyBeanReference获取对象引用。
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
					if (exposedObject == null) {
						return null;
					}
				}
			}
		}
		return exposedObject;
}

spring检查是否存在SmartInstantiationAwareBeanPostProcessor类型的实现,如果存在执行其getEarlyBeanReference方法获取对象,否则使用原对象。

  1. AbstractAutoProxyCreator为其生成代理对象。
@Override
	public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (!this.earlyProxyReferences.contains(cacheKey)) {
			this.earlyProxyReferences.add(cacheKey);
		}
		return wrapIfNecessary(bean, beanName, cacheKey);
}

wrapIfNecessary的流程和上文相同,即开始创建代理对象并将其加入earlyProxyReferences缓存中。当对象存在循环引用时,对象的代理可能会提前发生,所以在postProcessAfterInitialization创建代理对象是会先检测是否已经提前创建,避免了重复创建。

注意:spring循环依赖解决的方法是基于Java的引用传递,所有必须在对象实例化后获取到引用,所以spring只能解决setter注入的循环依赖,而不能解决构造方法产生的循环依赖

AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator是spring对AspectJ注解生成代理提供的支持,它是目前最实用方便的自动代理使用方式。

  • 如何启用AnnotationAwareAspectJAutoProxyCreator?
    spring提供了几种方式启用:
  1. 通过@EnableAspectJAutoProxy注解启用,它借助了前文提到的ImportBeanDefinitionRegistrar机制,自动注入;
  2. xml配置aop,spring通过aop命名空间处理类AopNamespaceHandler自动注入;
  • 如何使用自动代理?

通过使用AspectJ注解,可以很方便的为指定目标类创建代理。下面是一个通过注解,对方法请求权限校验的一个简单实现。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthorityVerify {
    Class<? extends AuthorityChecker> value();
    String[] param() default {};
}

public interface AuthorityChecker {
    /**
     * 校验
     */
    JSONResult check(Object... obj);
}

@Aspect
@Component
public class AuthorityAspect {
    private ExpressionParser parser = new SpelExpressionParser();

    private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();

    @Pointcut("@annotation(authorityVerify)")
    public void pointcut(AuthorityVerify authorityVerify) {
    }

    @Around("pointcut(authorityVerify)")
    public Object doAroundAdvice(ProceedingJoinPoint pjp, AuthorityVerify authorityVerify) throws Throwable {
        Class<? extends AuthorityChecker> value = authorityVerify.value();
        // 获取注解指定参数
        String[] params = authorityVerify.param();
        // 获取指定的校验器
        AuthorityChecker authorityChecker = ApplicationContextHolder.getContext().getBean(value);
        JSONResult checkResult;
        if (params.length == 0) {
           // 执行校验器
            checkResult = authorityChecker.check();
        } else {
            Method method = this.getMethod(pjp);
            Object[] args = pjp.getArgs();
            // 通过spel表达式获取请求参数
            EvaluationContext context = this.bindParam(method, args);
            Expression expression;
            Object[] checkerParams = new Object[params.length];
            for (int i = 0; i < params.length; i++) {
                expression = parser.parseExpression(params[i]);
                checkerParams[i] = expression.getValue(context);
            }
            // 执行校验器
            checkResult = authorityChecker.check(checkerParams);
        }
        if (checkResult != null && checkResult.getStatus() == ActionStatus.NORMAL_RETURNED.inValue()) {
           // 校验成功,执行正常逻辑
            return pjp.proceed();
        }
        // 校验失败,返回错误信息
        return checkResult;
    }

    private Method getMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException {
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        Method method = methodSignature.getMethod();
        Method targetMethod = pjp.getTarget().getClass().getMethod(method.getName(), method.getParameterTypes());
        return targetMethod;
    }

    private EvaluationContext bindParam(Method method, Object[] args) {
        String[] params = discoverer.getParameterNames(method);
        EvaluationContext context = new StandardEvaluationContext();
        for (int len = 0; len < params.length; len++) {
            context.setVariable(params[len], args[len]);
        }
        return context;
    }

}

@Aspect :声明该类为一个切面;
@Pointcut:切点表达式;
@Around:切面。
除了@Around(环绕通知),还提供了@Before(前置通知),@After(后置通知),@AfterRunning(返回通知),@AfterThrowing(异常通知)。

2、实例化Bean

容器进入实例化过程,分为一下三个步骤:

  • 通过bean配置中factory-name和factory-method指定的工厂方法实例化对象;
  • 通过@autowire注解实例化对象;
  • 通过构造方法实例化对象。

3、BeanNameAware、BeanClassLoaderAware、BeanFactoryAware

在bean初始化之前,容器检测当前bean是否为BeanNameAware、BeanClassLoaderAware、BeanFactoryAware的子类,并分别执行其setBeanName、setBeanClassLoader、setBeanFactory,为用户获取beanName、beanClassLoader和beanFactory提供通道。

4、@PostConstruct

当容器启用了注解扫描,spring会向容器中自动注入一个InitDestroyAnnotationBeanPostProcessor的子类CommonAnnotationBeanPostProcessor,利用BeanPostProcessor的特性,在bean初始化之前,会调用其postProcessBeforeInitialization方法,完成@PostConstruct指定方法的调用。

5、InitializingBean

public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}

简单介绍

在容器为bean初始化的过程中,如果容器发现其实现了InitializingBean接口,会执行其afterPropertiesSet方法。

应用实例——RequestMappingHandlerMapping和RequestMappingHandlerAdapter

RequestMappingHandlerMapping和RequestMappingHandlerAdapter是spring mvc模块实现的核心处理类。

RequestMappingHandlerMapping是HandlerMapping的子类,它的作用主要是根据request请求匹配/映射上能够处理当前request的handler;
RequestMappingHandlerAdapter是HandlerAdapter的子类,它作用在于将request中的各个属性,如request param适配为handler能够处理的形式,执行真正开发者开发的处理方法,自动帮我们完成数据绑定、视图渲染等等一切周边工作。

在为大家介绍RequestMappingHandlerMapping和RequestMappingHandlerAdapter之前,先简单为大家介绍一下spring mvc模块。

spring mvc
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>weli.pikpik.web.listener.StartBizListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                classpath:mvc-dispatcher-servlet.xml,
                classpath:swagger-dispatcher-servlet.xml
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

上面是Tomcat作为Web容器的例子,在web.xml中常常看到与spring相关的部署描述。ContextLoaderListener被定义为一个监听器,负责Ioc容器在web环境中的启动工作,DispatcherServlet是一个servlet对象,定义了对应的URL映射,起着分发请求的作用。

ContextLoaderListener

ContextLoaderListener实现了ServletContextListener接口,这个接口是在Servlet API中定义的,提供了与Servlet生命周期结合的回掉,通过其contextInitialized和contextDestroyed完成ioc容器的初始化和关闭过程,具体的流程是由其父类ContextLoader完成的。

初始化IOC容器
public class ContextLoader {
	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		......
			if (this.context == null) {
				// 创建上下文WebApplicationContext
				this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				if (!cwac.isActive()) {
					if (cwac.getParent() == null) {
						// 加载父上下文ApplicationContext并完成初始化,默认情况没有
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					// 启动上下文初始化
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
		......
	}
}
创建上下文WebApplicationContext
public class ContextLoader {
	protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
		// 获取上下文类型
		Class<?> contextClass = determineContextClass(sc);
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
					"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
		}
		// 实例化上下文
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	}
	protected Class<?> determineContextClass(ServletContext servletContext) {
		// 获取启动参数contextClass指定的上下文类型
		String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
		if (contextClassName != null) {
			try {
				// 返回指定的类型
				return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load custom context class [" + contextClassName + "]", ex);
			}
		}
		else {
			// 未指定,使用文件ContextLoader.properties指定的默认类型(XmlWebApplicationContext)
			contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
			try {
				return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load default context class [" + contextClassName + "]", ex);
			}
		}
	}
}
创建父上下文
public class ContextLoader {
	protected ApplicationContext loadParentContext(ServletContext servletContext) {
		ApplicationContext parentContext = null;
		// 父容器初始化资源路径,默认classpath*:beanRefContext.xml
		String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);
		// 父容器名称
		String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);
		// 未显示指定父容器直接返回null
		if (parentContextKey != null) {
			// 获取父容器定位器(ContextSingletonBeanFactoryLocator)
			BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
			Log logger = LogFactory.getLog(ContextLoader.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Getting parent context definition: using parent context key of '" +
						parentContextKey + "' with BeanFactoryLocator");
			}
			// 创建父容器并启动,默认创建了ClassPathXmlApplicationContext
			this.parentContextRef = locator.useBeanFactory(parentContextKey);
			parentContext = (ApplicationContext) this.parentContextRef.getFactory();
		}
		return parentContext;
	}
}
启动上下文初始化
public class ContextLoader {
	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
		// 设置上下文id
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// The application context id is still set to its original default value
			// -> assign a more useful id based on available information
			String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
			if (idParam != null) {
				wac.setId(idParam);
			}
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(sc.getContextPath()));
			}
		}
		// 设置servlet上下文
		wac.setServletContext(sc);
		// 设置初始化资源
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			wac.setConfigLocation(configLocationParam);
		}
		// 初始化环境参数
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}
		// 获取指定的ApplicationContextInitializer,在容器初始化前,完成回掉
		customizeContext(sc, wac);
		// 容器初始化
		wac.refresh();
	}
}

此时IOC容器已经成功在web环境中建立起来,这个上下文是作为根上下文存在,再此基础上,还会创建一个用于保存控制器(DispatcherServlet)需要的MVC对象的子上下文,构成一个层次化的上下文体系。spring的ioc容器具有双亲委派的机制,所有根上下文对于子上下文是可见的。

DispatcherServlet

作为Servlet,DispatcherServlet的启动与Servlet的启动过程是相联系的。在Servlet的初始化过程中,init方法会被调用,以进行初始,大部分初始化逻辑由其父类FrameworkServlet提供实现。

初始化servletBean
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
	@Override
	protected final void initServletBean() throws ServletException {
		......
		// 初始化子上下文
		this.webApplicationContext = initWebApplicationContext();
		// 初始化FrameworkServlet,空实现
		initFrameworkServlet();
		......
	}
}
初始化子上下文
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
	protected WebApplicationContext initWebApplicationContext() {
		// 获取创建的根上下文
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;
		if (this.webApplicationContext != null) {
			// 已经通过构造器指定了子上下文
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					if (cwac.getParent() == null) {
						// 设置父上下文
						cwac.setParent(rootContext);
					}
					// 初始化上下文
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			// 查找子上下文是否已经指定
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// 创建并启动子上下文,与根上下文的创建大体相同,不在赘述
			wac = createWebApplicationContext(rootContext);
		}
		if (!this.refreshEventReceived) {
			// 刷新FrameworkServlet,由子类实现
			onRefresh(wac);
		}
		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			String attrName = getServletContextAttributeName();
			// 向ServletContext注册子上下文
			getServletContext().setAttribute(attrName, wac);
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
						"' as ServletContext attribute with name [" + attrName + "]");
			}
		}
		return wac;
	}
}

DispatcherServlet的父类FrameworkServlet对于初始化子上下文提供了三种策略:
(1)由构造器实例化时设置,指定上下文;
(2)FrameworkServlet实现了ApplicationContextAware接口,通过向指定容器注入的方式初始化时,自动设置其上下文;
(3)使用默认方式创建的上下文(XmlWebApplicationContext)。

刷新FrameworkServlet,DispatcherServlet实现
public class DispatcherServlet extends FrameworkServlet {
	@Override
	protected void onRefresh(ApplicationContext context) {
		// 初始化组件
		initStrategies(context);
	}
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}
}

关于各个组件如何初始化和他们的作用是什么有兴趣的同学可以参考这篇文章。我们只为大家简单介绍一下HandlerMapping和HandlerAdapter的初始化流程。

HandlerMapping和HandlerAdapter的初始化
public class DispatcherServlet extends FrameworkServlet {
	/**
	  * HandlerMapping的初始化
	**/
	private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;
		if (this.detectAllHandlerMappings) {
			// 获取容器中已经注册的HandlerMapping,根据双亲委派原则,先查找父容器,在查找子容器
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
				// 根据order排序
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
				// 使用以handlerMapping命名的唯一HandlerMapping
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}
		if (this.handlerMappings == null) {
			// 未注册HandlerMapping,使用DispatcherServlet.properties文件中指定的默认HandlerMapping(BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping)
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}
	/**
	  * HandlerAdapter的初始化
	**/
	private void initHandlerAdapters(ApplicationContext context) {
		this.handlerAdapters = null;
		if (this.detectAllHandlerAdapters) {
			// 获取容器中已经注册的HandlerAdapter,根据双亲委派原则,先查找父容器,在查找子容器
			Map<String, HandlerAdapter> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
				// 根据order排序
				AnnotationAwareOrderComparator.sort(this.handlerAdapters);
			}
		}
		else {
			try {
				// 使用以handlerAdapter命名的唯一HandlerAdapter
				HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
				this.handlerAdapters = Collections.singletonList(ha);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerAdapter later.
			}
		}
		if (this.handlerAdapters == null) {
			// 未注册HandlerAdapter,使用DispatcherServlet.properties文件中指定的默认HandlerAdapter
			this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
			}
		}
	}
}

至此,DispatcherServlet已经全部完成了初始化过程,进入就绪状态,当有请求触发时,DispatcherServlet开始执行分发逻辑。

分发请求
  • 遍历所有HandlerMapping获取对应的HandlerExecutionChain;
  • 获取拦截器,执行前置处理;
  • 遍历所有HandlerAdapter获取对应的处理器;
  • 使用HandlerMapping执行Handler并获取返回的ModelAndView;
  • 获取拦截器,执行后置处理。
RequestMappingHandlerMapping
public interface HandlerMapping {
	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

RequestMappingHandlerMapping的父类HandlerMapping定义了唯一的抽象方法,负责通过request获取其对应的HandlerExecutionChain处理链。RequestMappingHandlerMapping是目前使用最广泛的HandlerMapping实现,通过对@RequestMapping注解的解析,构造了基于Method级别的MethodHandler。

RequestMappingHandlerMapping的工作大体上分为初始化过程和获取Handler的使用过程。

初始化流程

RequestMappingHandlerMapping实现了InitializingBean接口,所以在容器为其初始化时,为自动执行其afterPropertiesSet方法,开始触发其初始化流程,默认实现由它的父类AbstractHandlerMethodMapping实现。

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {

	@Override
	public void afterPropertiesSet() {
		initHandlerMethods();
	}
	
	protected void initHandlerMethods() {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking for request mappings in application context: " + getApplicationContext());
		}
		// 获取所有bean
		String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
				getApplicationContext().getBeanNamesForType(Object.class));

		for (String beanName : beanNames) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				Class<?> beanType = null;
				try {
					// 获取bean类型
					beanType = getApplicationContext().getType(beanName);
				}
				catch (Throwable ex) {
					// An unresolvable bean type, probably from a lazy bean - let's ignore it.
					if (logger.isDebugEnabled()) {
						logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
					}
				}
				// 判断当前类型是否为handler,isHandler为抽象方法,具体实现交由子类
				if (beanType != null && isHandler(beanType)) {
					// 开始处理当前handler
					detectHandlerMethods(beanName);
				}
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}
	
	protected void detectHandlerMethods(final Object handler) {
		// 获取当前类的class
		Class<?> handlerType = (handler instanceof String ?
				getApplicationContext().getType((String) handler) : handler.getClass());
		final Class<?> userType = ClassUtils.getUserClass(handlerType);
		// 解析获取当前类的所有method和其对应的RequestMappingInfo
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				new MethodIntrospector.MetadataLookup<T>() {
					@Override
					public T inspect(Method method) {
						try {
							// 通过getMappingForMethod构造其对应的RequestMappingInfo,具体实现交由子类
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
						}
					}
				});

		if (logger.isDebugEnabled()) {
			logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
		}
		for (Map.Entry<Method, T> entry : methods.entrySet()) {
			Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
			T mapping = entry.getValue();
			// 开始注册,使用默认的MappingRegistry,将url、RequestMappingInfo、HandlerMethod等对应信息保存到本地Map缓存,用于以后查找
			registerHandlerMethod(handler, invocableMethod, mapping);
		}
	}
}

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
		implements MatchableHandlerMapping, EmbeddedValueResolverAware {
	
	@Override
	protected boolean isHandler(Class<?> beanType) {
		// 判断其是否包含注解@Controller或者@RequestMapping
		return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
	}
	
	@Override
	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
		// 根据method信息构造RequestMappingInfo
		RequestMappingInfo info = createRequestMappingInfo(method);
		if (info != null) {
			// 根据handler信息构造RequestMappingInfo
			RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
			if (typeInfo != null) {
				// 合并信息
				info = typeInfo.combine(info);
			}
		}
		return info;
	}

	private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
		// 获取@RequestMapping注解信息
		RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element,RequestMapping.class);
		RequestCondition<?> condition = (element instanceof Class ?
				getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
		// 根据注解信息构造RequestMappingInfo
		return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
	}
}

流程比较清楚,大概分为三步,遍历获取所有Handler、解析所有method、注册绑定关系。

使用流程

前文已经为大家介绍过,当接受到请求后,DispatcherServlet会遍历所有HandlerMapping,通过其getHandler方法查找符合的hander,它的实现也是在其父类AbstractHandlerMapping中实现的。

public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
	@Override
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		// 获取Handler,由子类实现
		Object handler = getHandlerInternal(request);
		if (handler == null) {
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		// Bean name or resolved handler?
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = getApplicationContext().getBean(handlerName);
		}
		// 结合拦截器,构造HandlerExecutionChain
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		if (CorsUtils.isCorsRequest(request)) {
			CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}
		return executionChain;
	}
}

public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		// 获取url
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		if (logger.isDebugEnabled()) {
			logger.debug("Looking up handler method for path " + lookupPath);
		}
		this.mappingRegistry.acquireReadLock();
		try {
			// 从缓存中查找HandlerMethod
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			if (logger.isDebugEnabled()) {
				if (handlerMethod != null) {
					logger.debug("Returning handler method [" + handlerMethod + "]");
				}
				else {
					logger.debug("Did not find handler method for [" + lookupPath + "]");
				}
			}
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			this.mappingRegistry.releaseReadLock();
		}
	}
}

上面的流程也很清楚,解析url,然后从本地缓存中查找,与拦截器组合后返回。

RequestMappingHandlerAdapter
public interface HandlerAdapter {
	boolean supports(Object handler);
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
	long getLastModified(HttpServletRequest request, Object handler);
}

RequestMappingHandlerAdapter的父类HandlerAdapter,定义了处理器基本能力的三个方法:

  • supports():判断当前HandlerAdapter是否支持处理此handler;
  • handle():执行handler并返回对应的ModelAndView;
  • getLastModified():获取当前请求的最后更改时间,主要用于供给浏览器判断当前请求是否修改过,从而判断是否可以直接使用之前缓存的结果。

RequestMappingHandlerAdapter是HandlerAdapter使用最广泛的实现,它提供了对MethodHandler类型的Handler的支持。

RequestMappingHandlerAdapter的工作流程与RequestMappingHandlerMapping基本一致:

  • 通过实现了InitializingBean接口,调用afterPropertiesSet进入初始化流程;
  • DispatcherServlet会遍历所有HandlerAdapter,通过其supports()获取对应的HandlerAdapter,进入使用流程。
引入方法
  • 当我们在xml中通过启用注解扫描时,AnnotationDrivenBeanDefinitionParser会自动为我们注入一个默认的RequestMappingHandlerMapping;
  • 使用mvc命名空间时MvcNamespaceHandler会创建AnnotationDrivenBeanDefinitionParser也会为我们注入;
  • 使用@EnableWebMvc也会通过@Bean的方式注入。

6、init-method

执行xml中自定义init的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值