从源码学Spring+debug模式

Posted 早上真起不来!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从源码学Spring+debug模式相关的知识,希望对你有一定的参考价值。

BeanDefinition对象

spring是一个容器,里面放了一个个bean对象,spring帮我们管理这些对象,那spring是怎么知道我们需要管理那些对象呢?

  • xml 和 注解(@Component) 而这些又被称为bean的定义信息,当我们写好这些配置之后要交给我们的容器,这些配置转成一个叫BeanDefinition对象(BD对象),然后通过BD对象进行创建对象操作

  • 但是xml是怎样解析的呢? 通过io流读文件,读取到一堆字符串,然后通过一些工具(比如sax,dom4j)转成我们的document对象

再将我们document中的数据给到BD对象中

  • 那注解又是怎样获取的呢?通过获取某个上面的注解信息,再获取对应的class,就可以把class中的属性等方法BD对象中

当我们定义好一系列配置文件的时候 可以把这些具体的属性值(value)放到BD对象中,这个时候spring就知道要创建哪些基本的对象了

那又是怎么创建对象的呢?

反射还是new?

几乎所有的框架都是反射,但是反射效率性能低为什么还用反射呢?

反射它是足够灵活的,当创建10w个对象的时候反射才可能出现性能问题

但是我们BD对象通过反射就直接创建对象了,那spring就变的太简单了

spring有一套完整的生态,最根本最核心是因为 扩展性,spring给我们留了很多的口子

BeanFactory

那BeanFactory怎么理解呢?

官方翻译:访问 Spring bean 容器的根接口,也就是相当于入口

但是我们使用的时候好像和这个BeanFactory没什么关系,我们一般这么用:context.getBean(Peoson.class)

但是面试的时候一般会问到:BeanFactory和ApplicationContext是什么关系?

查看父类

ApplicationContext继承了BeanFactory,提供了一系列更加完善的功能

而且BeanFactory只提供了一些getxx方法

虽然我们用的是ApplicationContetx但是继承的还是BeanFactory

所以BeanFactory可以理解为入口或者容器对象

我们可以把BeanFactory的实现子类当做容器

那我们的BeanFactory可以获取到我们的BD对象吗?

BeanFactory接口中没有get他的方法,但是BeanFactory是一个顶级接口 我们可以去他的实现类中找

这就是spring源码很乱的原因之一,它存在了一堆的接口或者一堆的抽象类

那我们可以通过Beanfactory来获取我们的BD

下面这种情况在加载到BD中的时候是否把value替换了?并没有而是在PostProcessor中实现的

PostProcessor

先来看看

PostProcessor 被称为后置处理器或者增强器(更具体),就是用来扩展一些功能的,先看看他常见的实现

  • BeanFactoryPostProcessor

  • BeanPostProcessor

BeanFactoryPostProcessor

解析 bean 定义属性值中的占位符的属性资源配置器的抽象基类,这是什么意思呢?

也就是我们的

在我们当前的BeanFactoryPostProcessor对象里面可以完成对BD中的值完成替换

BD对象(保留原始值) 通过 BeanFactoryPostProcessor 得到最终的BD对象

最终的BD对象

debug分析:

DefaultListableBeanFactory 我们所有的bean对象都在这里存放,相当于一个大容器

debug的时候 有一个重点方法,refresh里面有13个方法

public void refresh() throws BeansException, IllegalStateException 
		synchronized (this.startupShutdownMonitor) 
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			/**
			 * 前戏 做容器刷新前的准备工作
			 * 1、设置容器的启动时间
			 * 2、设置活跃状态为true
			 * 3、设置关闭状态为false
			 * 4、获取Environment对象,并加载当前系统对象的属性到Environment对象中
			 * 5、准备监听器和事件的集合对象,默认为空的集合
			 */
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			/**
			 * 创建容器对象:DefaultListableBeanFactory
			 * 加载xml配置文件的属性值到当期工厂中,最重要的是BeanDefinition 也就是BD对象
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			/**
			 * BeanFactory的各种准备工作,对各种属性进行填充
			 */
			prepareBeanFactory(beanFactory);

			try 
				// Allows post-processing of the bean factory in context subclasses.
				// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				// 调用各种beanFactory处理器,这个就是替换占位符的方法
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 注册bean的处理器,这里只是注册功能,真正调用再getBean
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// Initialize message source for this context.
				// 为上下文初始化源,及不同语言的消息体,国化处理,再springmvc的时候会有国际化。
				initMessageSource();

				// Initialize event multicaster for this context.
				// 初始化事件监听多路广播起
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 留给子类来初始化其他的bean
				onRefresh();

				// Check for listener beans and register them.
				// 在所有注册的bean中查找listener bean,注册到广播器中
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				// 初始化剩下的单实例(非懒加载的)
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent
				finishRefresh();
			

			catch (BeansException ex) 
				if (logger.isWarnEnabled()) 
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			

			finally 
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
				contextRefresh.end();
			
		
	
  • obtainFreshBeanFactory中的refreshBeanFactory方法

@Override
protected final void refreshBeanFactory() throws BeansException 
    // 如果存在beanFactory,则摧毁beanFactory
    if (hasBeanFactory()) 
        destroyBeans();
        closeBeanFactory();
    
    try 
        // 创建DefaultListableBeanFactory对象
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        // 为了序列化指定id,设置从id反序列化到beanFactory对象
        beanFactory.setSerializationId(getId());
        // 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖
        customizeBeanFactory(beanFactory);
        // 初始化documentReader,并进行XML文件读取及解析,默认命名空间的解析,自定义标签的解析
        loadBeanDefinitions(beanFactory);
        this.beanFactory = beanFactory;
    
    catch (IOException ex) 
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    

  • 进到createBeanFacotury,新建一个DefaultListableBeanFactory 对象

  • 初始化的beanFactory

  • 加载后的beanFactory

  • 发现我们的占位符还是没有替换

当我们继续debug走到reflash的invokeBeanFactoryPostProcessors方法的时候就是替换的时候,invoke(调用)增强处理器

那如果我们自己去替换一个bean,也就是处理BD可以吗?

  • 只要去实现beanFactoryProcessor接口即可,拿到我们的BD,就可以set值了

  • 但是spring能识别到我们自己写的吗?不能!我们需要注册到容器中可以用bean 或者@Component
  • 当然beanFactoryProcessor可以定义多个,来处理BD

创建Bean对象

当我们通过BeanFactoryPostProcessor拿到我们的完整的BD后就要开始创建对象

那创建对象又是怎样一个环节呢?

属性赋值

spring除了我们自己写的配置对象,他还跟我们提供了许多自己的东西,比如BeanFactory、ApplicationContext

我们把对象交给容器,当然属性的set操作(就是属性赋值)也交给容器,

那么什么时候调?该调用什么方法?

所以定义统一的规范接口,然后实现功能

Aware

那如果我们自己set BeanFactory、ApplicationContext,该怎么做呢?

那么属性赋值到底是赋什么值?

准确来说,属性赋值分为:

  • 用户自定义属性赋值
  • 容器对象属性赋值 BeanFactory、ApplicationContext

注意,@Autowired可以代替Aware,所以基本不用aware,但是如果是xml写的就得用aware,所以说spring生态完善就在这里,他尽可能的把所有情况给到,

所以Aware为什么为空,就是起到一个标识作用

那我们赋值完后是否获取一个完整的bean对象?

当我们完成属性赋值完后,正常情况下是直接调用使用即可,但是spring在赋值完后 完成一系列增强实现,都属于bean的扩展实现

bean的扩展实现

BeanPostProcessor

就是我们的BeanPostProcessor

说明其中还有一个初始化过程,这个初始化和之前的不相同

说到这个BeanPostProcessor其中还有一个特别重要的东西AOP,

AOP

当我们的有了一个bean对象之后我们想生成他的代理对象,把当前bean对象的引用传递给BeanPostProcessor,在xxafter做逻辑处理,让他来生成我们具体的代理商

走到我们的wrapIFNecessary方法

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) 
    // 如果已经处理直接返回
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) 
        return bean;
    
    // 这里advisedBeans缓存了已经进行了代理的bean,如果换存中存在则直接返回
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) 
        return bean;
    
    // 这里isInfrastructureClass 用于判断当前的bean是否是spring自带的bean
    // 自带的bean是不需要进行代理的,shouldSkip则判断当前bean是否应该被略过
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) 
        // 对当前bean进行缓存
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    

    // Create proxy if we have advice.
    // 获取当前bean的Advices和Advisors
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    // 对当前bean的代理状态进行缓存
    if (specificInterceptors != DO_NOT_PROXY) 
        // 对当前bean的代理状态进行缓存
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 根据获取的Advices和Advisors为当前bean生成代理对象
        Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        // 缓存生成的代理bean的类型,并且返回生成的代理bean
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;

再往下走

所以再来看看这句话 AOP也是IOC核心创建流程中的个扩展点

再接着往下就到了初始化步骤,其实叫初始化不严谨,应该叫执行初始化调用方法

执行初始化调用方法

那什么叫执行初始化调用方法?

他会判断是否实现了InitializingBean接口,是 则调用afterPropertiesSet,否则调用里面有一个invokeInitMethod(最基本的初始化方法)方法,

那为什么会有这个呢?

因为spring帮我们做了一切事情,spring给我们留了一个口子,让我们也可以自己干预

拿到完整bean对象

而销毁对象怎么销毁呢?

销毁对象是在关闭容器的时候,而我们没有关闭过容器,所以不用我们自己做

bean的生命周期

再看看整个bean的生命周期

这里的createBeanInstance和populateBean后面说

@Autowaired

而这里面有一个很重的注解 @PostContruct,主要就是执行初始化方法的

那我们加上这个注解之后,被使用的那个对象是否要经历完整的bean生命周期?

肯定要!

@PostContruct是怎么实现的呢?

先来看看常用的

@Autowaired

@Value

那是怎么调用的呢?

先思考一个问题,spring是先有的xml还是注解,这个当然是xml,那么当spring发明初期只有xml的时候,spring已经有了一套完整生态体系,也就是有了一个完整的bean生命周期流程

当开发了注解,就要完成注解的功能,那么是推翻xml重来 还是扩展实现?

一定是扩展实现,但是在bean的生命周期里面哪里给我们留了扩展的点?

BeanProcessor

那么就可以知道

@PostContruct

小结

IOC的核心实现原理

spring的扩展实现

  • BeanFactoryPostProcessor:针对BD
  • BeanPostProcessor:针对Bean对象

bean的整个生命周期

spring aware接口的意义

起到一个标识作用,定义统一的规范接口,然后实现功能,属性赋值

BeanFactory和FactoryBean的关系

共同点:都是用来创建对象(BD)的

不同的是FactoryBean中包含 了三个方法

  • isSingleton:判断是否是单例对象
  • getObjectType:获取对象类型
  • getObject:用户可以按照自己任意的方式来创建对象(可以使用new、动态代理、反射)

BeanFactory是一个标准化流程,流水线

FactoryBean是私人订制

怎么实现呢?

public class Student implements FactoryBean<Student> 
    public Student getObject() throws Exception 
        // new方式创建对象
        Student student = new Student();
        // 代理方式创建对象
        Object o = Proxy.newProxyInstance(Student.class.getClassLoader(), Student.class.getInterfaces(),
                new InvocationHandler() 
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
                // 一些处理逻辑
                return null;
            
        );
        return (Student) o;
        //return student;
    

    public Class<?> getObjectType() 
        return Student.class;
    

    public boolean isSingleton() 
        return true;
    

当我们在生成每一个具体对象的时候,他有一个标准的bean对象的一个配置流程

那怎么识别是FactoryBean的呢?什么时候识别的呢?

前面说了有一个大容器DefaultListableBeanFactory

在上面refresh方法中的finishBeanFactoryInitialization(初始化剩下的单实例(非懒加载的)),中的preInstantiateSingletons可以找出识别FactoryBean的位置

public void preInstantiateSingletons() throws BeansException 
		if (logger.isTraceEnabled()) 
			logger.trace("Pre-instantiating singletons in " + this);
		
		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		// 将所有的BeanDefinition的名字创建一个集合
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
		// Trigger initialization of all non-lazy singleton beans...
		// 触发所有非延迟加载单例bean的初始化,遍历集合的对象
		for (String beanName : beanNames) 
			// 获取BD对象 合并父类BeanDefinition
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 条件判断,抽象、单例、非懒加载
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) 
				// 获取到BD 第一个判断的就是是否是FactoryBean,是就会走处理逻辑,里面会调用getObject方法,把对象创建出来
				if (isFactoryBean(beanName)) 
					// 根据&+beanName来获取具体的对象
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					// 进行类型转换
					if (bean instanceof FactoryBean) 
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						// 判断这个beanFactory是否希望立即初始化
						boolean isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
						if (isEagerInit) 
                            // 如果beanName不是FactoryBean,只是普通的bean,则通过beanName获取bean实例
							getBean(beanName);
						
					
				
				else 
					getBean(beanName);
				
			
		

// .....
	

以上是关于从源码学Spring+debug模式的主要内容,如果未能解决你的问题,请参考以下文章

怎么使用DeBug深入源码

Unity HTFramework框架(四十)Debug的性能监控

如何进行 Java 代码阅读分析?

Eclipse开发环境debug模式调试断点从jar跳到源码

从系统源码学设计模式-装饰模式

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段