欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring源码笔记

程序员文章站 2022-03-26 20:26:22
Spring容器启动简单理解spring框架,首先就是一个框架,直白点讲就是提高效率的工具,好比工厂干活,以前是人机械式的工作,现在用上了机器,人只用去操作机器就行了。那么spring工具提供了一个大容器,每次工作前把需要的东西全放进去,用的时候去容器拿,不用像之前用的时候还要跑回去拿。框架终究只是一个工具,如果如何使用手都不熟练,什么工具都不好上手,所以最重要的是基础。大多数的框架都是一种套路,利用资源加载和反射,在不断的加载配置文件,无论是yml , factories , properties...

Spring容器启动

简单理解spring框架,首先就是一个框架,直白点讲就是提高效率的工具,好比工厂干活,以前是人机械式的工作,现在用上了机器,人只用去操作机器就行了。那么spring工具提供了一个大容器,每次工作前把需要的东西全放进去,用的时候去容器拿,不用像之前用的时候还要跑回去拿。框架终究只是一个工具,如果如何使用手都不熟练,什么工具都不好上手,所以最重要的是基础。

大多数的框架都是一种套路,利用资源加载和反射,在不断的加载配置文件,无论是yml , factories , properties,xml,handlers等等,value值往往就是对应需要类加载的全限定名,再不停地封装缓存信息,加载信息,监听信息等等,最后再去完成类加载之后的对象执行交互或者进一步封装。

首先是构建项目的目录,遵循了web开发的项目结构;使用spring框架,首先导入context核心包,包含了bean,core,expression等IoC功能

<!--core核心包-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.3.10.RELEASE</version>
</dependency>

所有的bean交给spring容器管理,所以"工作前"需要先启动容器,并将配置的bean放入到容器中:

第一种:ClassPathXmlApplicationContext,加载xml文件,然后解析生成Bean,注册Bean,通过getBean获取对象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DI的解析器,试验过程中注释掉也可以注入? -->
	<context:annotation-config />
	<!-- IoC的解析器 -->
	<context:component-scan base-package="cn.mytest.spring" />
</beans>

配置了注解方式去注册Bean,测试一下IoC和DI

--需要注入的bean
@Data
@Component
public class NameBean {
    private String prefix="张";
    private String suffix="三";
}
--IoC
@Component
public class TestBean {
    private String name;
    @Autowired
    NameBean nameBean;
    public String test(){
        this.name=nameBean.getPrefix()+nameBean.getSuffix();
        return name;
    }
}

--或者通过@Configuration+@Bean
@Configuration
public class ValidateBean {
    @Bean
    public ValidateBean get(){
        return new ValidateBean();
    }
}

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        TestBean testBean = (TestBean)context.getBean("testBean");
        System.out.println(testBean.test()); //张三
        Object validateBean = context.getBean("validateBean");        
    }

第二种:AnnotationConfigApplicationContext,初步实践得知,先注册类中贴有@Bean的实例,再直接根据类的简单名去注册bean,跟@Configuration无关

public class ValidateBean {
    @Bean
    public NameBean getName(){
        System.out.println(1111);
        return new NameBean();
    }
}

// 用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
//容器先后注册了NameBean,ValidateBean和TestBean
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ValidateBean.class,TestBean.class);
        Object testBean = applicationContext.getBean("testBean"); 
        System.out.println(testBean);//1111 cn.mytest.spring.bean.TestBean@2d6eabae

第三种方式是在web容器启动时构建容器,可以通过配置监听器去初始化spring容器

   //ContextLoaderListener在创建时会默认查找WEB-INF/下的applicationContext.xml
	<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:application.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

最终都会走到父类AbstractApplicationContext的refresh方法中

Spring容器的构建

构建ApplicationContext

spring源码笔记

spring容器初始化的流程图

spring源码笔记

第三种方式通过启动web容器,加载监听器ContextLoaderListener,用于监听web容器的生命周期,当web容器启动时就会触发,ServletContext就是整个web容器的’全局变量’

--ContextLoaderListener 容器加载监听器
public void contextInitialized(ServletContextEvent event) {
	initWebApplicationContext(event.getServletContext());
}

initWebApplicationContext

而initWebApplicationContext初始化spring容器,和springMVC初始化容器调用的方法一致,所以在后者框架中将初始化容器放在servlet节点加载时去做的,而不是用监听器的方式

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    //判断servletContext容器中是否已经有创建好的app应用容器,有则抛异常
    if (servletContext.getAttribute
        (WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
        throw new IllegalStateException("");
    }
    try {
        if (this.context == null) {
            //构建一个应用容器返回
            this.context = createWebApplicationContext(servletContext);
        }
        if (this.context instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
            //active激活状态标识,使用原子方式保保证唯一线程操作
            //AtomicBoolean active = new AtomicBoolean()
           	//如果环境未激活,也就是未刷新之前设置父上下文、设置上下文id
            if (!cwac.isActive()) {
                if (cwac.getParent() == null) {
                    ApplicationContext parent = loadParentContext(servletContext);
                    cwac.setParent(parent);
                }
                //配置并刷新当前上下文环境
                configureAndRefreshWebApplicationContext(cwac, servletContext);
            }
        }
        //将应用容器添加到servletContext中  	
        servletContext.setAttribute(WebApplicationContext.
             ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
}

构建建WebApplicationContext对象流程

spring源码笔记

自定义容器或是默认的XmlWebApplicationContext是实现ConfigurableWebApplicationContext接口,而后者的父类接口是WebApplicationContext

XmlWebApplicationContext--实现-->ConfigurableWebApplicationContext接口
--继承-->WebApplicationContext接口--继承-->ApplicationContext接口

--ContextLoader
protected WebApplicationContext createWebApplicationContext
(ServletContext sc) {
	//根据配置确定构建自定义容器还是默认的容器XmlWebApplicationContext
    Class<?> contextClass = determineContextClass(sc);
    //isAssignableFrom方法表示调用者是否是参数的父类
    if (!ConfigurableWebApplicationContext.class.
    isAssignableFrom(contextClass)) {
        throw new ApplicationContextException("");
    }
    return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}

determineContextClass

determineContextClass类加载需要构建的容器类,可以在web.xml中自定义容器,默认的容器就是XmlWebApplicationContext容器

protected Class<?> determineContextClass(ServletContext servletContext) {
    //String CONTEXT_CLASS_PARAM = "contextClass";表示在<context-param>标签中是否有配置的自定义的contextClass
    String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
    if (contextClassName != null) {
        return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
    }
    else {
        //defaultStrategies通过静态方法在类加载时已经添加了默认的参数
        //这个默认的就是XmlWebApplicationContext
        contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
        return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
    }
}

--配置自定义的Context
<context-param>
    <param-name>contextClass</param-name>
    <param-value>
    	org.springframework.web.context.support.MyWebApplicationContext
    </param-value>
</context-param>

defaultStrategies默认策略,加载org.springframework.web.context包下的properties文件:

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

spring源码笔记

spring大量运用了加载资源文件的方式properties.load(inputStream)

--ContextLoader
private static final Properties defaultStrategies;

static {
      //String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";        
      ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
      defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
   }
}

configureAndRefreshWebApplicationContext

configureAndRefreshWebApplicationContext配置并刷新当前上下文环境

protected void configureAndRefreshWebApplicationContext(
    ConfigurableWebApplicationContext wac, ServletContext sc) {
    //配置应用程序上下文id
    //id:org.springframework..support.XmlWebApplicationContext@710c986
    //@后面是hash值避免冲突,容器每次构建时都是唯一
    if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
        //首先找web.xml中<context-param>配置:param-name为contextId
        String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
        if (idParam != null) {
            wac.setId(idParam);
        }
        else {
            //默认id:org.springframework.web.context.WebApplicationContext:
            wac.setId(ConfigurableWebApplicationContext
                      .APPLICATION_CONTEXT_ID_PREFIX +
                      ObjectUtils.getDisplayString(sc.getContextPath()));
        }
    }
    wac.setServletContext(sc);
     /**
     * 设置配置文件路径
     * <context-param>
     *      <param-name>contextConfigLocation</param-name>
     *      <param-value>classpath:spring.xml</param-value>
     *  </context-param>
     */
    String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
    if (configLocationParam != null) {
        wac.setConfigLocation(configLocationParam);
    }
	//Environment表示当前应用程序正在运行的环境,子类ConfigurableEnvironment:提供设置激活的 profile 和默认的 profile 的功能以及操作 Properties 的工具
    ConfigurableEnvironment env = wac.getEnvironment();
    //ConfigurableWebEnvironment:提供配置 Servlet 上下文和 Servlet 参数的功能
    if (env instanceof ConfigurableWebEnvironment) {
        //初始化PropertySources容器:存放多个PropertySource的容器
        ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
    }
	//自定义环境初始化
    customizeContext(sc, wac);
    //构建容器完成配置的核心方法
    wac.refresh();
}

ObjectUtils.identityToString方法:

public static String identityToString(Object obj) {
	return obj.getClass().getName() + "@" + getIdentityHexString(obj);
}

initPropertySources初始化PropertySources容器,PropertySource接口类似一个Map,PropertySources的实现类MutablePropertySources用链表实现存放PropertySource

public class MutablePropertySources implements PropertySources {
    private final List<PropertySource<?>> propertySourceList;
    ...

initPropertySources最终由WebApplicationContextUtils.initServletPropertySources实现,servletContext是web容器变量,有web.xml的配置信息(比如context-param);ServletConfig保存着servlet节点对应容器的配置信息(比如 init-param),这个初始化其实是想把servletContext,一个servletConfig这两个对象给存到容器的propertySources容器里去

	public void initPropertySources(ServletContext servletContext, ServletConfig servletConfig) {		WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
	}

customizeContext

再去加载context-param节点中自定义配置的InitializerClasses,一般用不到

protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
     /**
     *
     * globalInitializerClasses 代表所有的web application都会应用
     * contextInitializerClasses 代表只有当前的web application会使用
     * 配置自定义的globalInitializerClasses/contextInitializerClasses:
     *  <context-param>
     *      <param-name>contextInitializerClasses</param-name>
     *      <param-value>com..MyContextInitializerClasses</param-value>
     *  </context-param> 
     */   List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> 
    initializerClasses = determineContextInitializerClasses(sc);
		...
    //自定的ApplicationContextInitializer再调用initialize()方法        
    for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
         initializer.initialize(wac);
     }

ApplicationContextInitializer容器初始化接口在springboot中频繁用到,refresh之前对ConfiurableApplicationContext的做进一步的设置和处理,在springboot中一键启动时加载所有需要初始化的配置类,比如start相关包中META-INF/spring.factories中配置

spring源码笔记

其他的配置方式:

mian函数中添加:application.addInitializers(new MyApplicationContextInitializer());

@SpringBootApplication
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MySpringBootApplication.class);
        application.addInitializers(new MyApplicationContextInitializer());
        application.run(args);
    }
}

配置文件中配置:context.initializer.classes=xxx.MyApplicationContextInitializer

spring源码笔记

refresh

refresh()方法和方法内的具体实现基本都在AbstractApplicationContext类

--AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
	//Synchronization monitor for the "refresh" and "destroy"
    //简单来说就是在进行refresh或者destroy操作时去拿这个对象加上锁
    synchronized (this.startupShutdownMonitor) {
        //预处理,容器初始化的设值
        prepareRefresh();
        //根据不同容器的实现注册bean 
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        //填充BeanFactory功能,比如AspectJ,spring语言处理器等等
        prepareBeanFactory(beanFactory);
        try {        
            // 容器后处理器
            postProcessBeanFactory(beanFactory);
            // 调用BeanFactoryPostProcessor,激活各种处理器
            invokeBeanFactoryPostProcessors(beanFactory);
            // 6、注册BeanPostProcessors
            registerBeanPostProcessors(beanFactory);
            // 7、初始化Message资源
            initMessageSource();
            // 8、初始事件广播器
            initApplicationEventMulticaster();
            // 9、留给子类初始化其他Bean(空的模板方法)
            onRefresh();
            // 10、注册事件监听器
            registerListeners();
            // 11、初始化其他的单例Bean(非延迟加载的)
            finishBeanFactoryInitialization(beanFactory);
            // 12、完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知
            finishRefresh();
        }
        catch (BeansException ex) {
            // 13、销毁已经创建的Bean
            destroyBeans();
            // 重置active设值为false
            cancelRefresh(ex);
            throw ex;
        }
        finally {
            resetCommonCaches();
        }
    }
}

读取XML配置文件,创建beans流程

spring源码笔记

preRefresh

preRefresh预刷新,initPropertySources把servletConfig和servletContext放到spring容器的propertySources容器里面

protected void prepareRefresh() {
	//设置context的启动时间
    this.startupDate = System.currentTimeMillis();
	this.closed.set(false);//关闭标识为false
	this.active.set(true);//激活标识为true
	//configureAndRefreshWebApplicationContext方法中已经做个这个步骤
	initPropertySources();
    //验证在spring启动的时候自定义配置的环境变量必须存在,重写initPropertySources方法:
    //getEnvironment().setRequiredProperties("xx");设值
	getEnvironment().validateRequiredProperties();
	this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
obtainFreshBeanFactory

obtainFreshBeanFactory中refreshBeanFactory()在AbstractRefreshableApplicationContext和GenericApplicationContext都有实现,但是XmlWebApplicationContext继承了AbstractRefreshableApplicationContext,而AnnotationConfigApplicationContext继承了GenericApplicationContext

--AbstractRefreshableApplicationContext
protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    //新建的DefaultListableBeanFactory,实现ConfigurableListableBeanFactory接口
    DefaultListableBeanFactory beanFactory = createBeanFactory();
    //前面有设值过:org.springframework.web.context.WebApplicationContext:
    beanFactory.setSerializationId(getId());
    customizeBeanFactory(beanFactory);
    //加载BeanDefinition,将bean添加到beanDefinitionMap中
    loadBeanDefinitions(beanFactory);
    synchronized (this.beanFactoryMonitor) {
        this.beanFactory = beanFactory;
    }
}

loadBeanDefinitions有多个实现,这里以默认的XmlWebApplicationContext为例

--XmlWebApplicationContext
// root context的默认配置位置
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
// 默认配置位置的前缀
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
// 默认配置位置的后缀
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";

//通过XmlBeanDefinitionReader加载bean
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // Create a new XmlBeanDefinitionReader for the given BeanFactory.
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
   // Configure the bean definition reader with this context's
   // resource loading environment.
   beanDefinitionReader.setEnvironment(getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

   //空实现,留给子类进行自定义初始化
   initBeanDefinitionReader(beanDefinitionReader);
   //使用给定的reader加载bean定义
   loadBeanDefinitions(beanDefinitionReader);
}

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
    //就是context-param配置的contextConfigLocation,没有则返回context的默认配置
	String[] configLocations = getConfigLocations();
	if (configLocations != null) {
		for (String configLocation : configLocations) {
            //遍历xml配置文件进行加载解析DOM,最终注册到beanDefinitionMap
			reader.loadBeanDefinitions(configLocation);
		}
	}
}

loadBeanDefinitions(configLocation)解析xml配置文件加载bean

--AbstractBeanDefinitionReader
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
	//解析bean配置文件加载器
    ResourceLoader resourceLoader = getResourceLoader();
    //XmlWebApplicationContext实现了ResourcePatternResolver接口
    //也就是以xml配置bean进行加载的,非xml配置就不会实现这个接口
    if (resourceLoader instanceof ResourcePatternResolver) {
        try {
        	//将配置文件的内容转化为Resource对象
   			//判断是否是classpath*:开头的通配符
            Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
            //获取Resource对象流进行解析,转化为bean进行封装
            int loadCount = loadBeanDefinitions(resources);
            if (actualResources != null) {
                for (Resource resource : resources) {
                    actualResources.add(resource);
                }
            }
            return loadCount;
        }
    }
	...
}

loadBeanDefinitions(resources)

//EncodedResource对Resource封装了字符集编码
public int loadBeanDefinitions(Resource resource) {
    return loadBeanDefinitions(new EncodedResource(resource));
}

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    //使用ThreadLocal防止资源文件循环加载
    Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
    //确认没有加载过当前的Resource
    if (currentResources == null) {
        currentResources = new HashSet<>(4);
        this.resourcesCurrentlyBeingLoaded.set(currentResources);
    }
    try {
        //获取Resource的流
        InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            //解析成DOM对象,进行Bean注册
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
        }
		...
    }
}

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) {
    //解析为Document对象
    Document doc = doLoadDocument(inputSource, resource);
    //根据Document对象注册Bean
    return registerBeanDefinitions(doc, resource);
    ...
}    

registerBeanDefinitions返回注册的Bean数量,Bean解析和注册的详情在后面目录

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   //构建读取Document的工具类
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   //获取已注册的bean数量,封装在BeanFactory中
   //BeanFactory实现BeanDefinitionRegistry接口
   int countBefore = getRegistry().getBeanDefinitionCount();
   //注册本次需要加载的Bean 
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   //返回本次注册的bean:总注册的bean减去之前注册的bean
    return getRegistry().getBeanDefinitionCount() - countBefore;
}
prepareBeanFactory ---- 本周重点

填充一些特殊的bean和处理器等,暂时不深入分析每个处理器的作用和实现

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 设置beanFactory的classLoader
    beanFactory.setBeanClassLoader(getClassLoader());
    // 设置beanFactory的表达式语言处理器,默认可以使用#{xxx.xxx}的形式来调用相关属性值
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    // 添加默认的PropertyEditors,这些最后都注册到CustomEditorConfigurer中
    //Set<PropertyEditorRegistrar> propertyEditorRegistrars
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    //在所有实现了Aware接口的bean在初始化之后可以通过processor获取初始化之后的内容
    //ApplicationContextAwareProcessor是ApplicationContext负责回调的processor
    //例如实现了aware的bean初始化之后可以通过awareProcessor获取其bean id
    //List<BeanPostProcessor> beanPostProcessors 
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

    // 设置忽略bean 依赖于以下几个接口的实现类,Spring 会通过其他方式来处理这些依赖
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // 设置几个自动装配的特殊Bean
    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));

    //如果存在bean名称为loadTimeWeaver的bean则注册一个BeanPostProcessor
    // 增加对AspectJ的支持
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // 注册默认的系统环境bean,environment,systemProperties,systemEnvironment
    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());
    }
}
PropertyEditors

addPropertyEditorRegistrar添加PropertyEditorRegistrar,PropertyEditors的接口来实现对象和字符串之间的转换,比如在配置文件中添加一个属性值 myValue:xxx.xxx.Student,拿到这个值之后,通过实现PropertyEditorSupport 去进行类型转换

@Data
public class ExoticType { 
    private String myValue;
}

//这个value只是一个字符串,如果变成ExoticType对象?
@Value("${myValue}")
private ExoticType exoticType;

//实现PropertyEditorSupport接口的setAsText方法
public class ExoticTypeEditor extends PropertyEditorSupport { 
    @Override
    public void setAsText(String text) {
        setValue(new ExoticType(text.toUpperCase()));
    }
}

//注册CustomPropertyEditorRegistrar
public class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
    @Override
    public void registerCustomEditors(PropertyEditorRegistry propertyEditorRegistry) {
        propertyEditorRegistry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());
    }
}

//最后将customPropertyEditorRegistrar注册到CustomEditorConfigurer中
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="propertyEditorRegistrars">
        <list>
            <ref bean="customPropertyEditorRegistrar"/>
        </list>
    </property>
</bean>

AwareProcessor

容器addBeanPostProcessor(new ApplicationContextAwareProcessor(this))添加了一个ApplicationContextAwareProcessor的处理器

postProcessBeanFactory ---- 本周重点

有多个实现,也可以自定义实现,以ConfigurableListableBeanFactory容器为例,容器后处理

--AbstractRefreshableWebApplicationContext
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	//aware将ServletContext 传递给实现ServletContextAware接口的bean
    beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
    //忽略实现了以下2个接口的实现类的注册
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
	//注册 WEB 应用特定的域(scope),比如: request session response application等.
    WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    //注册 WEB 应用特定的 Environment bean,比如contextAttributes等
    //registerSingleton servletContext和servletConfig
    WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}

注册 WEB 应用特定的域(scope)和Environment bean

public static void registerWebApplicationScopes
(ConfigurableListableBeanFactory beanFactory, ServletContext sc) {
	//scope.put
    beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
    beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false));
    beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true));
	//注册域的bean
    beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
    beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
    beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
    beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
}
invokeBeanFactoryPostProcessors —本周重点

激活beanFactory的各种处理器,之前已经将所有的Processors添加到BeanFactory中的beanPostProcessors集合中

注册BeanDefinition

BeanDefinition就是Bean的定义信息,封装了每个bean的信息,对于spring框架来说操作bean就是操作BeanDefinition;BeanFactory封装了所有注册的BeanDefinition(beanDefinitionMap)

refresh()–>obtainFreshBeanFactory()–>registerBeanDefinitions(),经过一系列的解析之后,最终将dom解析成BeanDefinition并封装到BeanFactory中

protected void doRegisterBeanDefinitions(Element root) {
    //委托BeanDefinitionParserDelegate作为解析的代理
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);
	//是否匹配:"http://www.springframework.org/schema/beans"
    if (this.delegate.isDefaultNamespace(root)) {
        //profile:根节点属性,是否匹配当前环境,不匹配则不解析当前xml文件
        //<beans xmlns="http://www.springframework.org/schema/beans" profile="test"...>
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
  			...
            return;
        }
    }
	//解析root节点之前的操作,空实现,留给子类实现
    preProcessXml(root);
    parseBeanDefinitions(root, this.delegate);
    //解析root节点之后的操作,空实现
    postProcessXml(root);
    //通过这个方式还原初始化的BeanDefinitionParserDelegate
    this.delegate = parent;
}

所以最终由parseBeanDefinitions方法来处理dom

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   //default namespace就四个标签<import/>、<alias/>、<bean/> 和 <beans/>
   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)) {
               // 解析 default namespace 下面的几个元素
               parseDefaultElement(ele, delegate);
            }
            else {
               // 解析其他 namespace 的元素
               //例如:<context:component-scan/>、<aop:aspectj-autoproxy/>
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
   // 解析其他 namespace 的元素
      delegate.parseCustomElement(root);
   }
}

解析默认namespace

默认的命名空间只包含了import、alias、bean 和 beans四个标签,其中beans又是一个嵌套的dom继续递归调doRegisterBeanDefinitions

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    // import标签:解耦式的导入,将其他xml配置文件引入解析
    //比如<import resource="classpath:app.xml" />
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
    }
    // alias标签:<alias name="test" alias="test1,test2"/>
    //作用就是增加test1,test2作为bean名称指向bean
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
    }
    //解析bean标签,并注册beanDefinition
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    //beans标签:递归方法解析
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        doRegisterBeanDefinitions(ele);
    }
}

processBeanDefinition核心在于解析bean标签并注册beanDefinition

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    //解析之后BeanDefinition,beanName以及aliases封装到BeanDefinitionHolder
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        //装饰BeanDefinition:可以添加自定义的属性
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        //执行注册,将BeanDefinition信息添加到beanFactory中
        BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        //接受在读取BeanDefinition进程中注册组件、别名、import时的回调接口
        //自定义实现ReaderEventListener
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}
构建BeanDefinitionHolder

BeanDefinitionHolder就是将dom标签的属性及子标签解析之后的信息进行封装

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    //解析bean的属性,id,name和<alias>配置的别名都可以作为bean的key值
    String id = ele.getAttribute(ID_ATTRIBUTE);
    // 获取name属性,缓存至别名List
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    List<String> aliases = new ArrayList<>();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }
    // 如果bean的id为空,但是别名不为空的话,那么默认采用第一个别名作为beanName
    // 例如:<bean class="com.xx.Dog" name="myDog1,myDog2"/>
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        //使用myDog1作为beanName,并移除别名集合
        beanName = aliases.remove(0);
    }
    //检查beanName和别名是否被使用
    if (containingBean == null) {
        checkNameUniqueness(beanName, aliases, ele);
    }
    //解析bean标签,将属性及子节点信息封装
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
	....
}

进一步处理parseBeanDefinitionElement

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
    //this.beanDefinitionName = beanName
    this.parseState.push(new BeanEntry(beanName));
    //解析class属性,类全限定名
    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
    //解析parent属性
    String parent = null;
    if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
        parent = ele.getAttribute(PARENT_ATTRIBUTE);
    }
    //创建AbstractBeanDefinition对象,将标签的信息进行封装
    AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    //解析bean标签属性
    parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
    //解析bean标签下的子节点并封装到bd中
    //包括<property/>,<constructor-arg />注入之类标签等等
    bd.set....
}

parseBeanDefinitionAttributes解析bean属性

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,BeanDefinition containingBean,AbstractBeanDefinition bd) {
    // 1.设置bean作用域scope属性,不能设置为单例
    // 未明确指定bean的作用域,且当前被解析bean是内部bean的话,
    // 则默认使用outer bean的的作用域作为当前bean的作用域
    // 例如:下面的配置,解析到inner属性时,inner未指定作用域,则使用outer的作用域,也就是prototype
    /**
        <bean id="outer" class="com.lyc.cn.v2.day01.inner.Outer" scope="prototype">
            <property name="inner">
                <bean id="inner" class="com.lyc.cn.v2.day01.inner.Inner"/>
            </property>
         </bean>
     **/
     bd.setScope(containingBean.getScope());
    //2.设置abstract属性:abstract=true
    // 3.设置lazy-init(延迟加载)属性;
    // 如果该属性为true的话,ApplicationContext容器在初始化时不会加载该bean;
    // 而是在第一次向容器索取该bean时才会被初始化
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
    //4.设置autowire属性,自动注入,有byName和byType方式,默认不开启
    //byName,按照setXxx方法的Xxx名称去注入bean
    //byTupe,按照set方法的入参属性类去注入bean
    bd.setAutowireMode(getAutowireMode(autowire));
    //5.设置depends-on属性,如果BeanA依赖于BeanB,可通过depends-on属性使BeanB在BeanA之前完初始化
    //6.设置autowire-candidate属性,默认为true
    //当设置为false时,不让其他类通过autowire注入当前bean
    // 7、设置primary属性,当byType注入有多个类型时,
    // 可以指定primary="true",提高注入的优先级,避免抛出异常
    // 8、设置init-method,bean初始化完成后回调该方法
    // 9、设置destroy-method属性,bean销毁后回调该方法
    // 10、设置factory-method属性,该属性可指定静态工厂或实例工厂方法实例化bean
    // 11、设置factory-bean属性,一般和factory-method属性一起使用,
    // 指定工厂bean和工厂bean的工厂方法
}
registerBeanDefinition

BeanDefinitionReaderUtils工具类方法去执行注册

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
    // 1、注册BeanDefinition,一般为id
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    // 2、注册aliases(别名),一般配置多个指向Bean的别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

入参BeanDefinitionRegistry接口提供了多个beanfactory实现类,默认的实现是DefaultListableBeanFactory

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
    if (beanDefinition instanceof AbstractBeanDefinition) {
        //验证不能将静态工厂方法与方法重写相结合(factory-method的配置)
        ((AbstractBeanDefinition) beanDefinition).validate();
    }

    //优先从缓存中加载BeanDefinition,覆盖原先的bean
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        //添加到beanfactory的beanDefinitionMap中
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }else {
        // 如果beanDefinition已经被标记为创建(为了解决单例bean的循环依赖问题)
        if (hasBeanCreationStarted()) {
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                //将缓存的beanDefinitionNames和新解析的beanName加入集合
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                // 将updatedDefinitions赋值给beanDefinitionNames
                this.beanDefinitionNames = updatedDefinitions;
                // 如果manualSingletonNames中包含新注册的beanName
                if (this.manualSingletonNames.contains(beanName)) {
                    // 创建set集合并将manualSingletonNames加入到新创建的set集合
                    Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                    // 移除新注册的beanName
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        }
        else {
            // 将beanDefinition信息维护至缓存
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            // manualSingletonNames缓存了手动注册的单例bean,所以需要remove
            // 例如:xmlBeanFactory.registerSingleton("myDog", new Dog());
            // 就可以向manualSingletonNames中注册单例bean
            this.manualSingletonNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }
    // 如果当前注册的bean的定义已经在beanDefinitionMap缓存中存在,
    // 或者实例已经存在于单例bean的缓存中,将该beanName对应的缓存信息、单例对象清除
    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}

上面方法主要是将beanName和BeanDefinition形成映射

解析其他namespace

xmlns 属性可以在文档中定义一个或多个可供选择的命名空间,使用时在子标签内添加他的前缀作为标识:

比如:context,aop等

<beans xmlns="http://www.springframework.org/schema/beans" profile="test"
   xmlns:context="http://www.springframework.org/schema/context"...  
----context:----作为另外的一个命名空间标识
  <context:component-scan base-package="cn.mytest.spring" />

构建NamespaceHandler

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    // node.getNamespaceURI拿到节点的命名空间,例如常见的:
    // <aop> 节点对应命名空间: http://www.springframework.org/schema/aop
    String namespaceUri = getNamespaceURI(ele);
    // 命名空间对应的的handler, 例如:contex 对应 ContextNameSpaceHandler
    //namespaceHandlerResolver解析namespaceUri, 拿到NamespaceHandler
    NamespaceHandler handler = this.readerContext
        .getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        return null;
    }
    // handler解析节点(ParserContext用于存放解析需要的一些上下文信息)
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

readerContext.getNamespaceHandlerResolver()获取了默认的命名空间处理器DefaultNamespaceHandlerResolver,其封装了所有包下的handler

spring源码笔记

每个包下MATA-INF/spring.handlers文件记录对应的hanlder,因此使用指定的 classLoader 从所有类路径资源(META-INF/spring.handlers)加载所有属性,并使用 Properties 来存放 spring.handlers 文件中的内容(命名空间和 handler 的键值对)

--MATA-INF/spring.handler
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler"

//使用给定的类加载器从指定的类路径资源加载所有属性
Properties mappings = PropertiesLoaderUtils
.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
//将Properties转换成Map, mappings -> handlerMappings
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);

每个命名空间处理都会封装不同标签的bean解析器,例如ContextNamespaceHandler中封装了诸如property-placeholder,annotation-config等标签解析器

	<!-- 加载db.properties文件,属性占位 -->
	<context:property-placeholder location="classpath:db.properties"
		system-properties-mode="NEVER" />

	<!-- DI的解析器 -->
	<context:annotation-config />
	<!-- IoC的解析器 -->
	<context:component-scan base-package="cn.wolfcode.wms" />

public class ContextNamespaceHandler extends NamespaceHandlerSupport {
   @Override
   public void init() {
      registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
      registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
      registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
      registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
      registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
      registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
      registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
      registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
   }
}

先获取每个标签对应的BeanDefinitionParser解析器,再根据不同的解析器去实现parse方法,对于各个标签的解析功能暂不深入,主要是太多了,也可以进行自定义namespace

private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
    //拿到节点的localName,例如:<context:annotation-config />
    String localName = parserContext.getDelegate().getLocalName(element);
    //从parsers缓存中,拿到localName对应的解析器, 例如: component-scan -> ComponentScanBeanDefinitionParser
    BeanDefinitionParser parser = this.parsers.get(localName);
    return parser;
}

--parser.parse(element, parserContext);

初始化Bean

refresh执行到finishBeanFactoryInitialization时才开始初始化非延迟加载的bean,符合框架的通用性原则,不断的加载配置文件和资源文件,不断的封装缓存和需要处理的内容,最后进行类加载处理,进行封装和处理

本文地址:https://blog.csdn.net/weixin_42829824/article/details/107455200