Spring 总结

mac2025-12-31  0

文章目录

简介BeanFactorySpring源码-初始化BeanDefinitionSpring源码-对象初始化&依赖注入Spring源码-AOPSpring事务Spring应用SpringMVC的初始化与Servlet 3.0SpringMVC应用

简介

Spring是Java程序员日常开发中最长应的应用框架之一,它是如此的流行甚至对Java语言本身的发展都起到了推动作用,目前Spring可以说是Java后端开发的事实标准。Spring的优点可以总结如下:

Spring的两个最核心功能是IoC和Aop,为模块解耦合提供了基础支持;基于Aop实现的声明式缓存和声明式事务大大简化了代码逻辑;基于Spring的SpringMVC为快速接入JavaEE提供支持;Spring的test模块解决了应用程序的单元测试问题;Spring可以与很多优秀的框架集成,可以说跟谁都行有一腿;基于Spring构建的SpringBoot、SpringCloud使得Spring在微服务领域迎来了第二个春天;

BeanFactory

在刚开始接触Spring的时候,有人说Spring就是一个生产bean对象的工厂,底层实际上就是一个Map,直到现在对此也非常认同,Spring是一个Map,但绝不仅仅是一个Map,下面先看看Spring的BeanFactory结构 从图中的类名称可以看出,Spring从BeanFactory扩展出了具有不同能力的BeanFactory,当然这还不包含ApplicationContext,所以我个人对Spring的理解是它在HashMap的基础上扩展处理成百上千个特性,这些特性让Spring成为了一个优秀的框架产品。

如果把Spring当成是一个生产Bean的工厂,那么这个Bean工厂上产Bean的原材料就是BeanDefinition,从名字上就可以看出来,BeanDefinition是定义Bean的Bean,也就是说BeanDefinition封装了每一个能够被Spring管理的Bean的元数据,例如类型、依赖、属性、初始化方法等 从Spring中获取一个bean对象的主流程包括两步

加载配置文件,从中解析出BeanDefinition调用getBean(beanName)触发Bean的初始(从BeanDefinition到Bean)

Spring源码-初始化BeanDefinition

这里主要说说xml的解析,主要原因是相比注解的方式更加简单,以ClasspathXmlApplication为例,下面进入源码部分。 整个Spring初始的入口是ClasspathXmlApplication的构造方法

ClasspathXmlApplication public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { //入口在这里 refresh(); } } @Override protected Resource[] getConfigResources() { return this.configResources; } AbstractApplicationContext.java @Override public void refresh() throws BeansException, IllegalStateException { ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); } protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); } AbstractRefreshableApplicationContext.java @Override protected final void refreshBeanFactory() throws BeansException { /** 这里创建了BeanFactory的实例 - DefaultListableBeanFactory 所以说,我们开发中用到的ApplicationContext是BeanFactory的封装, 在BeanFactory的基础上提供了很多额外的功能,例如 事件发布与监听、组件扫描、国际化等 **/ DefaultListableBeanFactory beanFactory = createBeanFactory(); //从这里开始加载配置文件,注册BeanDefinition到BeanFactory loadBeanDefinitions(beanFactory); } AbstractXmlApplicationContext.java implements ResourceLoader */ @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { //创建一个专门从Xml中读取BeanDefinition的XmlBeanDefinitionReader XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setResourceLoader(this); loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { /** 当前类中的getConfigResources方法被ClasspathXmlApplicationContext重写了, 所以这里调用的是ClasspathXmlApplicationContext中的方法 */ Resource[] configResources = getConfigResources(); reader.loadBeanDefinitions(configResources); } protected Resource[] getConfigResources() { return null; } AbstractBeanDefinitionReader.java public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { loadBeanDefinitions(resource); } XmlBeanDefinitionReader.java public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } /** 这里是解析的核心逻辑 */ public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { //将配置文件转换成了InputStream流对象 InputStream inputStream = encodedResource.getResource().getInputStream(); return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) }{ //从流对象得到Document对象 Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //创建一个从Document中获取BeanDefinition的Reader BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); } DefaultBeanDefinitionDocuemntReader.java public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) { parseBeanDefinitions(root, this.delegate); }

这里就开始解析Elemnent对象了

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { //如果是spring默认的标签,就有spring内核自己来解析,例如beans、bean、<property>等等 parseDefaultElement(ele, delegate); } else { //如果是其他模块的标签或自定义的标签,例如 <aop:xxx> <tx:xxx> //就通过对应的xml名称空间,从spring.handlers中找到对应的NamespaceHandler //再由NamespaceHandler设置的parser进行解析 //这也是其他框架与spring进行集成的一个方式,例如dubbo的DubboNamespaceHandler就是用来解析<dubbo:xxx>的 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); } 最后实际上就是将解析出来的BeanDefinition通过BeanDefinitionRegistry提供的接口能力注册到DefaultListableBeanFactory中 实际上DefaultListableBeanFactory实现了BeanDefinitionRegistry接口,而最终BeanDefinition对象就会被添加到DefaultListableBeanFactory的 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256); 这个Map中。

下面我们看看BeanDefinition 可以说一目了然,我们所有的配置信息最终都会被解析到BeanDefinition中,Spring在创建Bean实例时,就会根据这些信息来执行不同的逻辑。

从这段逻辑中其实还能学点很多关于代码设计的知识点,比如在解析xml的时候通过BeanDefinitionReader/XmlBeanDefinitionDocumentReader等层层委托,遵循了面向对象设计原则的单一职责原则,再比如大量使用模板模式实现子类的灵活扩展。

Spring源码-对象初始化&依赖注入

前面讲了注册BeanDefinition的过程,有了创建Bean的原材料,接下来就是创建Bean对象了。

在Spring中创建Bean对象的入口有两个,一个是调用getBean()方法从容器中获取Bean对象,另外一个就是在Spring容器初始化的时候,会默认对单例对象进行初始化

AbstractApplicationContext.java @Override public void refresh() throws BeansException, IllegalStateException { // 这里会对非懒加载的bean进行实例化,实际上也是调用getBean,所以 // 触发bean实例化的入口就是getBean, // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); }

下面来看一下getBean方法的逻辑

AbstractApplicationContext.java @Override public <T> T getBean(String name, Class<T> requiredType) throws BeansException { assertBeanFactoryActive(); /** 这里调用的是DefaultListableBeanFactory的getBean方法 前面说过,ApplicationContext实际上是对BeanFactory 的再次封装,此处还是基于BeanFactory来实现IoC容器 所以这里也就很容易理解了 */ return getBeanFactory().getBean(name, requiredType); }

AbstractBeanFactory中的doGetBean是Bean对象初始化的核心方法,化繁为简,以单例对象的创建过程为例来说明

protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { /** Here **/ return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } } }); } } AbstractAwiredCapableBeanFactory.java @Override protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { //通过beanName从BeanDefinition中得到对应的class对象 Class<?> resolvedClass = resolveBeanClass(mbd, beanName); //这里调用的BeanPostProcessor的两个生命周期方法, 与Aop相关,后面再说 // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. Object bean = resolveBeforeInstantiation(beanName, mbdToUse); //看到doXxx就说明是真正干活的方法了,在Spring中doXxx都是苦力 Object beanInstance = doCreateBean(beanName, mbdToUse, args); } protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException { /** 这里是解决循环依赖的核心逻辑,循环依赖主要包含三种常见: 1. 构造方法之间的依赖 2. 构造方法和setter方法之间的依赖 3. setter方法之间的依赖 由于java本身不允许一个对象被创建一半,所以第一种循环依赖的场景没办法解决 第二种场景,解决方案是选初始化构造方法依赖的对象,然后将这个对象应用在构造函数上, 最后通过setter方法再将当前对象注入到被依赖对象中 第三种场景的解决方案与第二种基本一致 spring中使用了三级缓存来解决问题,这是个老生常谈的问题了,就不在详细说了 */ boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } /** 这里是进行属性赋值 主要分为@Autowired注释的属性,@Value注释的属性 如果是引用类型,则调用getBean先对其进行初始化,在通过反射设置到当前对象中 如果是@Value属性,通过PropertyPlaceHolderConfigurer进行设置 */ populateBean(beanName, mbd, instanceWrapper); /** 这里是对Bean进行初始化,这个方法比较重要,主要涉及到了bean 的生命周期管理,Aop代理对象的创建也是发生在这一步 */ exposedObject = initializeBean(beanName, exposedObject, mbd); } protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { /** 调用所有XxxAware的回调方法,例如BeanNameAware、BeanFactoryAware、ApplicationContextAware等 注入相关的属性值 */ invokeAwareMethods(beanName, bean); /** 这里调用BeanPostProcessor的前置方法postProcessBeforeInitialization */ wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); /** 这里调用初始化方法 首先会调用InitializingBean接口的afterPropertiesSet方法 然后再调用<bean init-method=“”>指定的方法 这里涉及到优先级问题,使用的时候需要注意以下 */ invokeInitMethods(beanName, wrappedBean, mbd); /** 这里调用BeanPostProcessor的后置方法postProcessAfterInitialization Aop代理对象就是在这里创建的,是整个Aop的入口,涉及到我们常说的 Cglib动态代理和Jdk 动态代理, 后面再详细分析 */ ·wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } // 这个方法会从IoC容器中获取所有的BeanPostProcessor,并调用后置方法 @Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { result = beanProcessor.postProcessAfterInitialization(result, beanName); if (result == null) { return result; } } return result; }

到这儿其实创建Bean的过程就执行完了,Bean对象实例化主要分为三个步骤

通过反射创建Bean对象对对象中的属性进行复制,这里如果是引用类型,会递归触发getBean的调用最后就是调用Bean对象的生命周期钩子方法,管理Bean对象的生命周期

实际上Bean的创建过程还涉及到了Aop的整个初始化流程,相对比较复杂,放到后面分析Aop的时候再详细看,不过,可以先有一个印象,就是Spring Aop是通过BeanPostProcesser实现的。

Spring源码-AOP

SpringAop是核心功能模块之一,提供了面向切面编程的支持,在Aop领域涉及到一些晦涩难懂的概念:

目标对象:只被代理的对象,一般是业务对象;连接点:插入切面的地方,在Spring Aop中指的是方法;切点:指连接点的集合;切面:切面逻辑,例如日志记录、事务;织入:简单理解就是生成代理对象的过程;通知:定义了在连接点如何织入切面(前置通知、后置通知、环绕通知、异常通知、返回通知);

下面分别来简单看一下Aop的xml和注解两种应用实例

xml方式 业务类 public class UserService { public void queryUser() { System.out.println("Query User"); } } 切面类 public class LogAspectj { //前置通知方法 public void beforeLog() { System.out.println("before log"); } //环绕通知方法 public Object aroundLog(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("around before"); System.out.println("" + joinPoint.getSignature().getName() + ", args:" + Arrays.asList(joinPoint.getArgs())); Object re = joinPoint.proceed(); System.out.println("around after"); return re; } //后置通知方法 public void afterLog() { System.out.println("after log"); } //返回通知方法 public void returningLog() { System.out.println("returning log"); } //异常通知方法 public void exceptionLog(Exception ex) { System.out.println("exception log"); } } 配置文件 <context:component-scan base-package="spring"/> <bean id="userService" class="spring.service.UserService"/> <!-- 切面 --> <bean id="logAdvice" class="spring.log.LogAspectj"/> <aop:config> <!-- 切点 --> <aop:pointcut id="servicePointCut" expression="execution(* spring.service.UserService.*(..))"/> <aop:aspect ref="logAdvice"> <aop:before method="beforeLog" pointcut-ref="servicePointCut"/> <aop:around method="aroundLog" pointcut-ref="servicePointCut"/> <aop:after method="afterLog" pointcut-ref="servicePointCut"/> <aop:after-returning method="returningLog" pointcut-ref="servicePointCut"/> <aop:after-throwing method="exceptionLog" pointcut-ref="servicePointCut" throwing="ex"/> </aop:aspect> </aop:config> 注解方式 @Aspect @Component public class LogAspectj { @Pointcut("execution(* spring.service.*.*(..))") public void pointCut() { } @Before("pointCut()") public void beforeLog() { System.out.println("before log"); } @Around("pointCut()") public Object aroundLog(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("around before"); System.out.println("" + joinPoint.getSignature().getName() + ", args:" + Arrays.asList(joinPoint.getArgs())); Object re = joinPoint.proceed(); System.out.println("around after"); return re; } @After("pointCut()") public void afterLog() { System.out.println("after log"); } @AfterReturning("pointCut()") public void returningLog() { System.out.println("returning log"); } @AfterThrowing(value = "pointCut()", throwing = "ex") public void exceptionLog(Exception ex) { System.out.println("exception log"); } } @ComponentScan("spring.service") @Configuration //开启注解切面支持 @EnableAspectJAutoProxy public class SpringConfig { }

以上就是Spring Aop的简单实用示例,下面进入源码,Spring Aop的逻辑相对复杂些,为了简化逻辑,以注解Aop为基础来看Aop的原理。

面试时,常问的一道题就是Spring Aop的实现原理,我们经常会回答Jdk 动态代理和Cglib动态代理,然后就大眼瞪小眼,一首《凉凉》送给你。那么,再往下说的话,说点什么呢,其实可以聊聊是在什么时候创建的代理对象,以及具体的调用过程,对于五种类型的通知是怎支持的,再比如Spring是如何解析我们的配置的等等。

对于配置解析这块,由于不是核心逻辑,就大致说一下,也没必要深究,简单来说,我们配置的各种通知,最后会被Spring解析成不同Advisor实例,注册到IoC容器中。下面我们着重来看代理对象的创建和调用流程。

前面在说Bean的初始化的时候,说到在对bean对象进行初始化时,会调用Bean生命周期的钩子方法,比如我们常见的BeanNameAware、BeanFactoryAware、ApplicationContextAware、BeanPostProcessor、InitializingBean等,而Spring Aop正是依赖于BeanPostProcessor来创建待对象的

AbstractAutowireCapableBeanFactory.java

// 这是Bean实例化的一个核心方法 @Override protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { /** 从注释看,是说这里是一个创建代理对象的前置方法,内部逻辑就是调用BeanPostProcessor 的before和after方法,但是从调制结果来看,一般情况下这里都是返回null, 所以可以先暂时忽略,往后看 */ // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. Object bean = resolveBeforeInstantiation(beanName, mbdToUse); Object beanInstance = doCreateBean(beanName, mbdToUse, args); } /** 这方法前面已经说过了,是创建Bean的核心方法 包括bean对象的创建 属性赋值、依赖注入 生命周期管理 */ protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException { instanceWrapper = createBeanInstance(beanName, mbd, args); populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); } protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { //调用XxxAware钩子方法 invokeAwareMethods(beanName, bean); //调用BeanPostProcessor的before方法 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); //调用初始化方法 invokeInitMethods(beanName, wrappedBean, mbd); //调用BeanPostProcessor的after方法,Aop代理对的创建就发生在这里 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }

上面简单回顾了一些Bean实例化的过程,说到Aop是基于BeanPostProcessor实现的,那是怎么回事呢?我们看一期用于开启Aop支持的注解实现

@EnableAspectJAutoProxy @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { } class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { /** 启动容器时,会调用这个方法,这个方法的作用是向SpringIoC中注册 一个指定的BeanDefinition对象 */ @Override public void registerBeanDefinitions( AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); } } AopConfigUtils public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) { return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null); } public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { /** 重点来了,这个被注册到IoC容器的对象就是AnnotationAwareAspectJAutoProxyCreator */ return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); }

来看看AnnotationAwareAspectJAutoProxyCreator的继承关系 图中有两个接口重点关注一下,分别是BeanPostProcessor和Ordered接口。既然它是一个BeanPostProcessor,那么在Bean初始化触发生命周期时,对应的方法就一定会被调用,看下下面的方法

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; /** 这个方法时bean生命周期的一个回调入口,处理BeanPostProcessor的after方法 看一看到,这里是获取了所有的BeanPostProcessor,然后回调其postProcessAfterInitialization 方法,那么,我们就看看AnnotationAwareAspectJAutoProxyCreator这个类的 postProcessAfterInitialization做了什么事情 */ for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { result = beanProcessor.postProcessAfterInitialization(result, beanName); if (result == null) { return result; } } return result; } /** AbstractAutoProxyCreator是AnnotationAwareAspectJAutoProxyCreator的父类,并且实现了 postProcessAfterInitialization方法 **/ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { /** 这里也是核心逻辑,简单来说,就是获取与当前Bean相匹配的所有Advisor对象 前面我们说过,对应的切面配置会被Spring解析成多个Advisor实例并注册到Ioc容器中 */ Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); /** 重点来了,这里就是你对面试官说的Jdk动态代理||Cglib动态代理 */ 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; } //getAdvicesAndAdvisorsForBean的实现类,方法 protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { //这里是获取所有的Advisor List<Advisor> candidateAdvisors = findCandidateAdvisors(); //根据当前bean对象对Advisor做进一步过滤 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { /** 这里是一个重点,是对匹配到的Advisor列表进行排序,排序后的顺序为: 1. AfterThrowAdvisor 异常通知 2. AfterReturningAdvisor 返回通知 3. AfterAdvisor 后置通知 4. AroundAdvisor 环绕通知 5. BeforeAdvisor 前置通知 这个顺序大家需要记一下,后面说aop调用的时候还会涉及到 */ eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; } 下面看看创建代理对象的过程 protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { //Spring提供了两种代理工厂,CglibProxyFactory和JDKDynamicProxyFactory //这里以JDKDynamicProxyFactory为例 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); return proxyFactory.getProxy(getProxyClassLoader()); } @Override public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); //这里吧JdkDynamicAopProxy实现了InvocationHandler,所以用this作为参数 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }

到此,代理对象的床架过程就分析完了,总结起来,其实很简单

bean初始化的生命周期触发对BeanPostProcessor的after方法的调用AspectJAwareAdvisorAutoProxyCreator 刚好是一个BeanPostProcessor执行AspectJAwareAdvisorAutoProxyCreator的after方法首先获取容器中所有的Advisor根据Bean低下过滤可以引用的Advisor对象对Advisor实例进行排序将Advisor列表复制给ProxyFactoryProxyFactoy通过动态代理创建目标对象的代理对象,代理对象内部封装了所有Advisor实例

下面我们来看看代理对象的调用过程,调用的起点在Proxy对象的invoke方法,也就是JdkDynamicAopProxy

@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //这里我删除了一些边角逻辑,留下了主逻辑 //这里拿到了一个由所有Advisor构成的调用链 // Get the interception chain for this method. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); //将调用链封装成了一个Invocation对象 // We need to create a method invocation... invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. //调用Invocation的procced方法,也就是说,调用核心逻辑在ReflectiveMethodInvocation中 retVal = invocation.proceed(); } /** 这个方法就是最后干活的苦力,可惜没叫doProcced(). interceptorsAndDynamicMethodMatchers 这个变量厉害了,还记得前面说过Advisor会被排序么 这里存储着所有排好序的advisor,前面我们说的排序顺序是 1. AfterThrowAdvisor 异常通知 2. AfterReturningAdvisor 返回通知 3. AfterAdvisor 后置通知 4. AroundAdvisor 环绕通知 5. BeforeAdvisor 前置通知 */ @Override public Object proceed() throws Throwable { /** 删除了一些边角逻辑,留下最重要的一句,你可能会差异这里怎么变成了MethodInterceptor 实际上是在获取List<Object> chain对象时,把Advisor转换成了MethodInterceptor, 向看的话可以自己翻一下 那么这里的调用逻辑是什么,只看代码并不直观,请看下图 **/ // been evaluated statically before this object was constructed. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); }

这个图应该只有我自己能看到, 哈哈哈。 简单来说就是按照排好序的Advisor的顺序,一次顺序调用,在原路返回。

调用流程可以简单总结一下:

对目标对象的调用首先会到Proxy的invoke方法中在invoke中,根据排好序的Advisor创建调用链,创建过程中奖所有Advisor转成MethodInterceptor然后逐层调用代表了不同类型的通知的MethodInterceptor最后返回

Spring事务

Spring的事务是就与Aop实现的,下面我们先来看一下基于注解的Spring事务的配置

@ComponentScan("spring.dao") @ComponentScan("spring.service") @ComponentScan("spring.log") @Configuration @EnableAspectJAutoProxy //开启事务支持 @EnableTransactionManagement public class SpringConfig { //注册数据源 @Lazy @Bean public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUsername("root"); dataSource.setPassword("zd1991.."); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/test"); return dataSource; } //注册事务管理器 @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dataSource()); } //注册JdbcTemplete @Bean public JdbcTemplate jdbcTemplate() { return new JdbcTemplate(dataSource()); } } @Service public class UserService implements InitializingBean { @Autowired private UserDao userDao; //开始事务 @Transactional public void queryUser() { int i = 10 / 0; //ex System.out.println("Query User"); } }

在开启事务支持的@EnableTransactionManagement注解中,其实也注册了一个BeanPostProcessor

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { @Override protected String[] selectImports(AdviceMode adviceMode) { //这里注册了两个Bean对象到IoC容器 //AutoProxyRegistrar注册了一个用于实现事务代理的BeanPostProcessor //ProxyTransactionManagementConfiguration 注册了与事务相关的Advisor,包含了事务相关的Aop核心逻辑 return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; } } public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { /** 这里实际上注册了一个InfrastructureAdvisorAutoProxyCreator,它也是一个PostProcessor */ AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); } } /** 可以看到,继承了AbstractAdvisorAutoProxyCreator,这里定义了Aop的核心逻辑 */ public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { private ConfigurableListableBeanFactory beanFactory; @Override protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.initBeanFactory(beanFactory); this.beanFactory = beanFactory; } @Override protected boolean isEligibleAdvisorBean(String beanName) { return (this.beanFactory.containsBeanDefinition(beanName) && this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE); } }

下面在看一下ProxyTransactionManagementConfiguration,这个类特别重要

@Configuration public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { /** 这里注册了一个Advisor,由于Spring Aop执行过程中,会加载Spring中的所有Advisor,所以 这个Bean对象也会被加载到,这个Advisor还调用了transactionInterceptor(), 这个方法返回的TransactionInterceptor实际上就是Aop中生成调用链用的MethodInterceptor 其实解释Aop将Advisor转换成MethodInterceptor的时候,BeanFactoryTransactionAttributeSourceAdvisor被转成 MethodInterceptor的时候,返回了TransactionInterceptor,所以,事务的核心逻辑就在TransactionInterceptor中 */ @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() { BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); advisor.setTransactionAttributeSource(transactionAttributeSource()); advisor.setAdvice(transactionInterceptor()); advisor.setOrder(this.enableTx.<Integer>getNumber("order")); return advisor; } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { return new AnnotationTransactionAttributeSource(); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionInterceptor transactionInterceptor() { TransactionInterceptor interceptor = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource()); if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; } } public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable { @Override public Object invoke(final MethodInvocation invocation) throws Throwable { Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() { @Override public Object proceedWithInvocation() throws Throwable { return invocation.proceed(); } }); } } /** 这个方法就是最终代理事务的地方: 出现异时常回滚 正常执行则提交事务 */ protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); //获取事务管理器 final PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. //调用目标方法 retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception //异常回滚 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { //清理状态 cleanupTransactionInfo(txInfo); } //提交事务 commitTransactionAfterReturning(txInfo); return retVal; } else { final ThrowableHolder throwableHolder = new ThrowableHolder(); // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. try { Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, new TransactionCallback<Object>() { @Override public Object doInTransaction(TransactionStatus status) { TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); try { return invocation.proceedWithInvocation(); } catch (Throwable ex) { if (txAttr.rollbackOn(ex)) { // A RuntimeException: will lead to a rollback. if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } else { throw new ThrowableHolderException(ex); } } else { // A normal return value: will lead to a commit. throwableHolder.throwable = ex; return null; } } finally { cleanupTransactionInfo(txInfo); } } }); // Check result state: It might indicate a Throwable to rethrow. if (throwableHolder.throwable != null) { throw throwableHolder.throwable; } return result; } catch (ThrowableHolderException ex) { throw ex.getCause(); } catch (TransactionSystemException ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); ex2.initApplicationException(throwableHolder.throwable); } throw ex2; } catch (Throwable ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); } throw ex2; } } }

Spring应用

SpringMVC的初始化与Servlet 3.0

在Servlet3.0中,引入了一些很方便的特性,例如异步支持、各种组件的注解支持以及初始化器自动加载机制等,这里我们主要说一说自动初始化器加载即使。

在Servlet3.0中规定,如果在META-INF/services下指定了一个基于SPI规则的ServletContainerInitializer的话,Servlet容器就会自动加载(对于Java SPI不了解的老铁自己百度一下,这里不做扩展),就像下面这样: 上面就是SpringMVC提供的ServletContainerInitializer的实现,实际上,也是SpringMVC在Servlet 3.0中注解化配置和启动的一个入口,下面我们来看看这个SpringServletContainerInitializer做了些什么。

/** @HandlersTypes 这个注解是一个入口,被这个注解修饰的类,当启动Servlet时,就会被自动加载 实际上这里加载的WebApplicationInitializer也就是我们自己定义的 继承了 AbstractAnnotationConfigDispatcherServletInitializer 这个类的配置类 */ @HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { /** 被实例化的WebApplicationInitializer对象,会通过这个Set<Class>集合注入到这个onStartup注入进来 这就给了SpringMVC一个启动自己的hook接口 */ @Override public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>(); if (webAppInitializerClasses != null) { for (Class<?> waiClass : webAppInitializerClasses) { /** 这里很简单了,判断所有被加载的Class对象,如果是抽象类就跳过 如果不是,就放到list中,其实最终就是我们的自定义配置类 */ if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) { try { initializers.add((WebApplicationInitializer) waiClass.newInstance()); } catch (Throwable ex) { throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex); } } } } servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); AnnotationAwareOrderComparator.sort(initializers); /** 这里就执行了SpringMVC的hook方法了 遍历所有的WebApplicationInitializer,并调用onStartup方法 */ for (WebApplicationInitializer initializer : initializers) { initializer.onStartup(servletContext); } } }

入口找到了,下面我们继续往下看 从名字就可以看出来,这些类主要功能就是初始化DispatcherServlet,也就是SpringMVC环境。图中的WebInitializer是我自定义的一个配置类,就像下面这样。

/** 实际上,这个类就相当于我们用xml和web.xml配置spring mvc时的 ContextLoadListener 和 DispatcherServlet 的集合 */ public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { //这里用来指定Root IoC容器的配置 @Override protected Class<?>[] getRootConfigClasses() { return new Class[0]; } //这里用来指定 Web IoC容器的配置 @Override protected Class<?>[] getServletConfigClasses() { return new Class[0]; } //这里用来设置DispatcherServlet的服务路径 @Override protected String[] getServletMappings() { return new String[0]; } }

为了不懵逼,先把spring mvc整个环节的初始流程梳理一下,然后再对照源码来看:

创建Root ApplicationContext,用这个ApplicationContext创建ContextLoadListener,并注册到ServletContext创建Sevlet ApplicationContext,用这个ApplicationContext创建DispatcherServlet,并注册到ServletContextServlet容器继续启动流程,触发ContextLoadListener的contextInitialized()和Dispatcher的init()方法在contextInitialized()中触发Root ApplicationContext的refresh,开始Root IoC容器初始化流程在init()方法中,把初始化好的Root IoC与Servlet IoC进行关联,然后触发Servlet IoC的refresh方法,开始初始化Servlet IoC容器初始化Spring MVC的核心组件Spring MVC初始化完成

从流程可以看出,实际上,就是把xml的配置方式转换成了Java 配置,没有什么特别的地方,下面来看看源码

AbstractDispatcherServletInitializer.java public void onStartup(ServletContext servletContext) throws ServletException { super.onStartup(servletContext); //这里创建Root IoC,注意,是创建!! this.registerDispatcherServlet(servletContext); 这里创建DispatcherServlet ,注意,是创建!! } 一点点里看 AbstractContextLoaderInitializer.java public void onStartup(ServletContext servletContext) throws ServletException { registerContextLoaderListener(servletContext); } /** 这个方法就非常清楚了 创建一个Root IoC容器,然后用这个IoC容器构造ContextLoadListener 最终,把这个Listener注册到ServletContext中,交给Serlvet容器管理 */ protected void registerContextLoaderListener(ServletContext servletContext) { WebApplicationContext rootAppContext = createRootApplicationContext(); ContextLoaderListener listener = new ContextLoaderListener(rootAppContext); listener.setContextInitializers(getRootApplicationContextInitializers()); servletContext.addListener(listener); } 然后在看看这个Root IoC容器是怎么创建出来的 AbstractAnnotationConfigDispatcherServletInitializer.java protected WebApplicationContext createRootApplicationContext() { //这里获取根容器相关的配置类 Class<?>[] configClasses = this.getRootConfigClasses(); if (!ObjectUtils.isEmpty(configClasses)) { AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext(); //将这个配置类注册到容器中 rootAppContext.register(configClasses); return rootAppContext; } else { return null; } } //这个方法熟悉吧!,就是我们自定义配置类的时候其中一个方法 protected abstract Class<?>[] getRootConfigClasses();

到这儿,根容器就创建完了,但是此时还没有对其进行初始化,那么是在哪初始化呢?前面不是说把这个创建出来的ApplicationContext交给了ContextLoadListener吗,对其进行初始化就是在Listener的contextInitialized()方法中触发的,也就是说,Servlet容器初始化完成后,就会着手初始Spring环境

ContextLoaderListener.java @Override public void contextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); } public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { //触发容器初始化流程 configureAndRefreshWebApplicationContext(cwac, servletContext); 将根容器注册到ServletContext中 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); } protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { //到这里就是IoC容器初始流程了 wac.refresh(); }

根容器创建完了,也初始化完了,下面在看看Servlet IoC容器的创建和初始。

AbstractDispatcherServletInitializer.java this.registerDispatcherServlet(servletContext); 这里创建DispatcherServlet ,注意,是创建!!

上接这个方法。

protected void registerDispatcherServlet(ServletContext servletContext) { //创建web IoC容器 WebApplicationContext servletAppContext = this.createServletApplicationContext(); //创建DispatcherServlet FrameworkServlet dispatcherServlet = this.createDispatcherServlet(servletAppContext); //向Servlet容器注册DispatcherServlet Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); registration.setLoadOnStartup(1); //这个了getServletMapping 调用的就是我们自己实现的方法,用来设置DispatcherServlet的入口url registration.addMapping(this.getServletMappings()); registration.setAsyncSupported(this.isAsyncSupported()); }

着重看一下第一步和第二步

AbstractAnnotationConfigDispatcherServletInitializer.java protected WebApplicationContext createServletApplicationContext() { //创建了一个热乎乎的ApplicationContext AnnotationConfigWebApplicationContext servletAppContext = new AnnotationConfigWebApplicationContext(); //调用获取配置类信息的hook方法 Class<?>[] configClasses = this.getServletConfigClasses(); if (!ObjectUtils.isEmpty(configClasses)) { servletAppContext.register(configClasses); } return servletAppContext; } //这个方法就是我们自己实现的返回Web IoC容器配置类的方法 protected abstract Class<?>[] getServletConfigClasses(); //这个方法就很简单里,直接new 了一个对象,简单粗暴 俺喜欢 O(∩_∩)O protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) { return new DispatcherServlet(servletAppContext); }

到此,Web IoC容器就创建完了,但是还没初始化,它的初始化时由DispatcherServlet的init()方法触发的,这个方法时Servlet规范中定义的方法,由Servlet容器调用,下面来看看

HttpServletBean.java public final void init() throws ServletException { this.initServletBean(); } FrameServlet.java protected final void initServletBean() throws ServletException { //想要的都在这里 this.webApplicationContext = this.initWebApplicationContext(); this.initFrameworkServlet(); } protected WebApplicationContext initWebApplicationContext() { /** 这里是一个重点: 从ServletContext中获取前面初始化完成的Root IoC容器 */ WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.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) { /** 这里将两个IoC容器进行关联 */ cwac.setParent(rootContext); } //这里调用了WebApplicationContext的refresh()方法对容器进行初始,就不贴代码了,没什么好看的 this.configureAndRefreshWebApplicationContext(cwac); } } } if (!this.refreshEventReceived) { //这个方法也比较厉害,主要是初始Spring MVC中的核心组件 //例如HandlerMapping,HandlerAdapter HandlerExceptionResolver ViewResulver MultipartResolver等 this.onRefresh(wac); } return wac; }

到此,所有的初始工作都完成了,就等着请求过来了。

Spring MVC内部把IoC容器拆分成了Root 和Web两个,在日常开发的时候,用利用这个特性把Service和Dao层的Bean放到Root IoC容器中,把Web相关的Bean放到Web IoC容器中,这样可以在Bean 容器层进行解耦,但是,在有些项目中,配置@ComponentScan的时候,并没有进行合理的规划,瞎扫,项目中的Bean对象哪里都有,笔者在使用SpringMVC的很长时间里都没有注意到这一点,经常出现properties配置文件中属性无法加载的问题,造成这个问题的原因在于:

把属性配置文件加载到了Root IoC容器中你却在Web IoC容器中拿

Spring 把这个权利交给了程序员,那么在使用的时候就要好好利用。

SpringMVC应用

最新回复(0)