2023-09-16  阅读(2)
原文作者:王伟王胖胖 原文地址:https://blog.csdn.net/wangwei19871103/article/details/104963990

前言

前面写了一些netty的源码解析,虽然覆盖不了所有的内容,但是大部分核心的内容都讲到了,主要还是要自己去看,去理解,然后写点小demo,领会netty的设计意图,为什么能高性能,从线程的分工明确,多路复用到内存分配的分而治之,让多线程之间减少竞争,让内存使用效率提高,等等一些思想。现在想再分析下Spirng 5.2.1.RELEASE的源码,虽然这个很复杂,但是我们还是可以大致了解一些原理,对以后使用和问题定位都有所帮助,而且还可以学到一些思想,一些处理方法,一些设计模式等等。我们主要是研究注解使用的一些原理。

简单注解例子

首先我们创建一个配置类MyConfig

    @Configuration
    public class MyConfig {
        
    }

然后写一个测试方法,方便我们调试:

     @Test
        public void BeanDefinitionRegistryPostProcessorTest0() {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        }

啥都不干,就分析他对配置类做了什么。

简单思考

先不看源码,我们自己思考下我们把一个配置类放进去,他可能会做点什么。假设我们都用过Spring,哪怕最简单的那种,很明显我们可以猜到,他里面应该是对我们注解@Configuration的类进行了解析,分析他里面有点什么,然后进行相应的处理。确实大致思路就这样,但是具体就比较复杂了,我们还是看源码慢慢分析吧。

AnnotationConfigApplicationContext注解配置上下文

先看下大致创建了什么

202309162311019581.png

首先我们看名字只知道他是注解配置的上下文,也就是一个环境,那环境里面应该有好多东西,可以处理我们传进去的类。我们刚才调用的构造方法就是这个:

    	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    		this();
    		register(componentClasses);
    		refresh();
    	}
    	
    	public AnnotationConfigApplicationContext() {
    		this.reader = new AnnotatedBeanDefinitionReader(this);
    		this.scanner = new ClassPathBeanDefinitionScanner(this);
    	}
    	public GenericApplicationContext() {
    		this.beanFactory = new DefaultListableBeanFactory();
    	}

首先他先创建了一个DefaultListableBeanFactory,这个就是后面一直要用的bean工厂,里面放着所有和bean相关的东西,比如bean定义,bean后置处理器等等,其实spring的思想就是把你给他的类都需要一个bean定义来描述,这样才可以进行处理。然后再创建AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner,一个是注解的bean定义读取器,一个是bean定义的扫描器。这里要注意ClassPathBeanDefinitionScanner其实是提供给用户用的,并不是他内部使用,内部后面他会再创建一个来用。我们先来看下AnnotatedBeanDefinitionReader创建做了什么。

AnnotatedBeanDefinitionReader读取器

看这个构造方法,传入的是一个BeanDefinitionRegistry类型,就是可以注册bean定义的,内部要注册就需要用到。

    	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    		this(registry, getOrCreateEnvironment(registry));
    	}

getOrCreateEnvironment获得或者创建环境

如果BeanDefinitionRegistryEnvironmentCapable的话就可以直接获取,否则就创建一个标准环境,其实就是获取一些系统的变量。比如可以配置dev环境,test环境,online环境等等。

    	private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
    		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    		if (registry instanceof EnvironmentCapable) {
    			return ((EnvironmentCapable) registry).getEnvironment();
    		}
    		return new StandardEnvironment();
    	}

AnnotatedBeanDefinitionReader构造方法

BeanDefinitionRegistry进行了保存和把environment封装进了ConditionEvaluatorConditionEvaluator可以理解成一个条件过滤器,与@Conditional有关,如果有了这个注解,就先判断条件成不成立,不成立的话有些操作就不做了。

    	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    		Assert.notNull(environment, "Environment must not be null");
    		this.registry = registry;
    		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
    		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    	}

重要属性

另外有三个属性后面会用到,比如bean的名字生成器BeanNameGenerator,可以自定义怎么生成,默认是简单类名首字母小写,还有一个是范围注解的解析器ScopeMetadataResolver,解析出范围,是单例,还是原型,另一个就是条件评估器了ConditionEvaluator

    private final BeanDefinitionRegistry registry;
    	//类名生成器
    	private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
    	//socpe注解解析器
    	private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
    	//条件评估器
    	private ConditionEvaluator conditionEvaluator;

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)注册注解配置处理器

这个一看方法就知道要加一些处理器,来处理我们的注解,也就是说,spring有些内部的处理器需要注册进来,这里可以想到spring应该是为了统一处理处理器,所以也是按注册,处理这样的流程来,无论是自己内部的,还是用户自定义的,我们来看看里面是怎么做的。

    	public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    		registerAnnotationConfigProcessors(registry, null);
    	}

主要流程就是获取DefaultListableBeanFactory,然后注册AnnotationAwareOrderComparator顺序比较器,排序用的,ContextAnnotationAutowireCandidateResolver自动装配解析器,解析自动装配相关配置用。然后创建一些后置处理器的bean定义,内部一般用RootBeanDefinition来定义,比如这个类ConfigurationClassPostProcessor,他是前面配置类处理的关键,所以这里先添加bean定义,还有AutowiredAnnotationBeanPostProcessor,处理自动装配的,另外还有EventListenerMethodProcessorDefaultEventListenerFactoryCommonAnnotationBeanPostProcessor暂时不讲,后面用到会说。

    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
    			BeanDefinitionRegistry registry, @Nullable Object source) {
    		//获取beanFactory
    		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    		if (beanFactory != null) {
    			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
    				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);//设置依赖比较器
    			}
    			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
    				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());//设置自动装配解析器
    			}
    		}
    		//创建BeanDefinitionHolder集合
    		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
    		//设置ConfigurationClassPostProcessor后置处理器
    		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    		}
    		//自动装配注解处理器
    		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    		}
    
    		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
    		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    		}
    
    		// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
    		if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    			RootBeanDefinition def = new RootBeanDefinition();
    			try {
    				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
    						AnnotationConfigUtils.class.getClassLoader()));
    			}
    			catch (ClassNotFoundException ex) {
    				throw new IllegalStateException(
    						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
    			}
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    		}
    		//事件监听方法处理器
    		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
    			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    		}
    		//默认事件监听器工厂
    		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
    			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
    			def.setSource(source);
    			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    		}
    
    		return beanDefs;
    	}

AnnotationConfigUtils的registerPostProcessor注册后置处理器

注册后置处理器,其实是注册对应的bean定义,对于一些内部处理器的bean定义,会设置角色属性setRole,然后向registry里注册beanNamebean定义,最后封装成BeanDefinitionHolder返回。

    	private static BeanDefinitionHolder registerPostProcessor(
    			BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
    
    		definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    		registry.registerBeanDefinition(beanName, definition);//注册进registry
    		return new BeanDefinitionHolder(definition, beanName);
    	}

GenericApplicationContext的registerBeanDefinition注册bean定义

可以看到,这里出现了beanFactory,就是我们开始获得的DefaultListableBeanFactory,注册bean定义是交给他的。

    @Override
    	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    			throws BeanDefinitionStoreException {
    
    		this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
    	}

DefaultListableBeanFactory的registerBeanDefinition注册bean定义

其他非核心的暂时略过了,剩下就两行,最终是把他放入ConcurrentHashMap中,名字放入ArrayList中。放在map里是为了后面可以方便映射获取,名字在list中则是为了方便获取遍历。

    ...
    	this.beanDefinitionMap.put(beanName, beanDefinition);//名字和bean定义对应
    				this.beanDefinitionNames.add(beanName);//名字
    ...

BeanDefinitionHolder封装bean定义而已

这个类其实就是对beanNamebean定义和别名做了封装:

202309162311029872.png
最后注解配置处理器注册完成,注册了比较器和解析器,注册了注解处理器bean定义:

202309162311034053.png

202309162311036664.png
可以看到,内部的bean定义全部都是用RootBeanDefinition,关于bean定义的类型后面会说,先了解就行。至此读取器创建完成,其实就是注册了需要处理注解的处理器bean定义,此时还没有创建bean哦。后面ConfigurationClassPostProcessor发挥着很大的作用,用来解析配置类。后面我们要先了解下spring里的bean定义到是定义什么。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文