手撸Spring系列2:IOC/DI 思想(源码篇-IOC)
说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正。若在阅读时有任何的问题,也可通过评论提出,本人将根据自身能力对问题进行一定的解答。
手撸Spring系列是笔者本人首次尝试的、较为规范的系列博客,将会围绕Spring框架分为
IOC/DI 思想
、Spring MVC
、AOP 思想
、Spring JDBC
四个模块,并且每个模块都会分为理论篇
、源码篇
、实战篇
三个篇章进行讲解(大约12篇文章左右的篇幅)。从原理出发,深入浅出,一步步接触Spring源码并手把手带领大家一起写一个 迷你版的Spring框架,促进大家进一步了解Spring的本质!由于源码篇涉及到源码的阅读,可能有小伙伴没有成功构建好Spring源码的阅读环境,笔者强烈建议:想要真正了解Spring,一定要构建好源码的阅读环境再进行研究,具体构建过程可查看笔者此前的博客:《如何构建Spring5源码阅读环境》
文章目录
- 前言
- 一、IOC架构
- 1.BeanFactory
- 2.BeanDefinition
- 3.BeanDefinitionReader
- 二、从IOC的入口开始
- 1.实例化ApplicationContext
- 2.查看AnnotationConfigApplicationContext的构造方法
- 2.1调用空构造方法
- 2.1.1 AnnotatedBeanDefinitionReader
- 1. ConfigurationClassPostProcessor
- 2. AutowiredAnnotationBeanPostProcessor
- 3. RequiredAnnotationBeanPostProcessor
- 4. CommonAnnotationBeanPostProcessor
- 5. PersistenceAnnotationBeanPostProcessor
- 6. EventListenerMethodProcessor
- 7. DefaultEventListenerFactory
- 2.1.2 ClassPathBeanDefinitionScanner
- 2.2 注册bean配置类
- 2.3 刷新上下文
- 1. prepareRefresh
- 2. obtainFreshBeanFactory
- 实现一
- 实现二
- 3. prepareBeanFactory
- 4. postProcessBeanFactory
- 5. invokeBeanFactoryPostProcessors
- 6. registerBeanPostProcessors
- 7. initMessageSource
- 8. initApplicationEventMulticaster
- 9. onRefresh
- 10. registerListeners
- 11. finishBeanFactoryInitialization
- 12. finishRefresh
- 13. destroyBeans
- 14. cancelRefresh
- 15. resetCommonCaches
- 总结
前言
今天的博客将带领大家一起来目睹一番Spring5的源码,透过源码去发掘Spring是如何具体去实现IOC思想的。由于Spring IOC DI 两个源码讲解写一起篇幅会比较长,因此笔者将IOC和DI分成了两篇博客进行讲解。
在开篇: 手撸Spring系列0:系统架构介绍(开篇)中我们有介绍到,模块 spring-beans
、spring-core
主要实现Spring IOC 和 DI功能,那么接下来我们将从这两个模块开始去解读Spring的源码。
一、IOC架构
1.BeanFactory
在Spring中,提供了许多IOC容器实现的方式由用户自己自由选择(下图是Spring IOC 架构图)
BeanFactory是Spring中的顶层接口,定义了IOC容器的基本功能规范,而在BeanFactory之下存在三个重要的子类,分别是:ListableBeanFactory
、HierarchicalBeanFactory
、AutowireCapableBeanFactory
,并且这三个子类接口最终都由默认实现类 DefaultListableBeanFactory
实现。
可能会有读者伙伴们开始疑惑了,为什么一个用于生产Bean的工厂底下还有有这么多个子类?虽然他们继承自一个”父亲“,但他们的老”父亲“为了能更好的完成家族工作,扩大业务宽度,需要他们各自负责一块领域,并通过不同的职责给他们起了对应的名字。
ListableBeanFactory:正如这个工厂接口的名字所示(能列在表单上的bean工厂),这个工厂接口最大的特点就是可以列出工厂可以生产的所有实例。
HierarchicalBeanFactory:分层级的bean工厂,该接口与他的大哥
ListableBeanFactory
不同的是:大哥将所有的bean实例统一的列在一张表中,但这样做的问题在于,工作出现问题后的追责问题会使得管理员十分头痛。而此时二弟HierarchicalBeanFactory
职责的优势就显现出来了,他会将每个bean所属的”公司“、”部门“等都进行一个归类,此时,工作出现问题后,管理员能够快速的找到出现问题的”部门“,并进行追责。AutowireCapableBeanFactory:定义bean自动装配规则
顶层接口BeanFactory源码:
package org.springframework.beans.factory;import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;public interface BeanFactory {/*** <p>* 这里是对FactoryBean的转义定义,因为如果使用bean的名字检索* FactoryBean得到的对象是工厂生成的对象* 如果需要得到工厂本身,需要转义* </p>*/String FACTORY_BEAN_PREFIX = "&";/*** <p>* 这里根据bean的名字,在IOC容器中得到bean实例,* 这个IOC容器就是一个大的抽象工厂。* </p>*/Object getBean(String name) throws BeansException;/*** <p>* 这里根据bean的名字和Class类型来得到bean实例,* 和上面的方法不同在于它会抛出异常:* 如果根据名字取得的bean实例的Class类型和需要的不同的话。* </p>*/<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;Object getBean(String name, Object... args) throws BeansException;<T> T getBean(Class<T> requiredType) throws BeansException;<T> T getBean(Class<T> requiredType, Object... argsa) throws BeansException;/*** <p>这里提供对bean的检索,看看是否在IOC容器有这个名字的bean</p>*/boolean containsBean(String name);/*** <p>这里根据bean名字得到bean实例,并同时判断这个bean是不是单例</p>*/boolean isSingleton(String name) throws NoSuchBeanDefinitionException;/*** <p>这里根据bean名字得到bean实例,并同时判断这个bean是不是原型</p>*/boolean isPrototype(String name) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;/*** <p>这里对得到bean实例的Class类型</p>*/@NullableClass<?> getType(String name) throws NoSuchBeanDefinitionException;/*** <p>这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来</p>*/String[] getAliases(String name);}
从源码中,我们不难看出,BeanFactory只是对IOC容器进行了基本行为的定义,并不关心一个bean是如何产生定义的。这就如同我们在手机实体店中挑选手机,只关心手机最后呈现出来的性能、外观等因素,而我们不用去关注手机厂商具体是如何生产这部手机的。
2.BeanDefinition
什么是BeanDefinition: 如果将一个bean比喻成一个婴儿,那么BeanDefinition则是这个婴儿体内的DNA。DNA中存储着这个婴儿各种生命基因,双眼皮、单眼皮、黄皮肤、黑皮肤等等都由基因决定,甚至获取到该婴儿的DNA后还可以克隆到一模一样的个体。而BeanDefinition就相当于是bean的DNA,其中定义了与bean实例化相关的各种信息,并通过BeanDefinition中的信息就可以实例化出一个bean对象。(如下是BeanDefinition的类结构图)
3.BeanDefinitionReader
在系列博客的开篇:手撸Spring系列0:系统架构介绍(开篇)中,笔者曾和各位读者伙伴们讲述过,ApplicationContext
作为BeanFactory
的子类,他们之间的区别是:前者扫描bean后会对bean进行实例化,而后者则是等到bean被调用时才进行实例化。
但一个bean的解析过程是十分复杂的,功能会被划分的非常详细,因为需要保证其扩展性、延申性和灵活性,以应对项目的各种变化。而bean的解析过程则是通过BeanDefinitionReader
来完成的。(如下是BeanDefinitionReader的类结构图)
二、从IOC的入口开始
大概的了解Spring IOC 的基本架构后,我们就要正式的开始来阅读源码了,但源码这么多,上千个类,我们应从何读起?了解了基本架构后,就如同观察了一个建筑的大致外貌,要更深入的研究就必须进去建筑内部查看,这时我们就需要找到建筑的入口,但入口又是在哪呢?
不妨先来回想一下,当我们启动一个以spring为框架的程序时,程序首先会去找到Java入口方法main
方法,对spring的IOC容器ApplicationContext
进行实例化,然后进行spring内部的一系列操作后才开始处理和执行业务需求……等等,我们似乎已经找到突破口了,spring需要在IOC容器ApplicationContext
进行实例化后才开始开始真正的工作,也就是说,ApplicationContext
其实是spring框架的入口,那么我们可以尝试从ApplicationContext
开始,去一步步探索spring源码,以揭开它神秘的面纱!
1.实例化ApplicationContext
因为ApplicationContext本身是一个接口,因此我们需要实例化其子类AnnotationConfigApplicationContext
(这里我们使用注解配置的子类AnnotationConfigApplicationContext,除此之外还有以xml文件为配置的ClassPathXmlApplicationContext)
public static void main(String[] args) {ApplicationContext applicationContext =new AnnotationConfigApplicationContext(AppConfig.class);}
2.查看AnnotationConfigApplicationContext的构造方法
进入AnnotationConfigApplicationContext的非空构造方法(如下)
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {// 初始化注解解析器reader,扫描器scannerthis();// 注册配置类annotatedClassesregister(annotatedClasses);// 扫描bean的具体操作refresh();}
进入构造方法后,我们可以看到,里面执行了三个方法this
、register
、refresh
,他们对应的作用分别是:
- this: 调用AnnotationConfigApplicationContext的空构造方法
- register: 注册bean配置类
- refresh: 刷新上下文
2.1调用空构造方法
在阅读这个空构造方法的源码之前,笔者需要向各位读者朋友们温故一个Java的基础知识点:Java中要求在子类的构造方法中调用其父类的构造方法。如果父类无构造方法(其实是一个默认无参的构造方法),那么子类的构造方法中会自动进行调用;如果 父类有自己的构造方法(这时父类不会有默认无参的构造方法),那么在子类的构造方法中,必须要调用父类的某个构造方法,而且必须是在构造方法的第一个语句中进行调用。
因此,在真正执行this();
方法之前,Java会先执行父类中的构造方法,即AnnotationConfigApplicationContext
的父类 GenericApplicationContext
中的构造方法。(GenericApplicationContext的空构造方法源码如下)
public GenericApplicationContext() {this.beanFactory = new DefaultListableBeanFactory();}
在这里我们发现,GenericApplicationContext
在初始化时居然实例化了一个 DefaultListableBeanFactory
,也就是我们的bean工厂。作为BeanFactory
的实现类,我们不妨点进去查看查看他的源码。其中,值得注意的是,在众多的成员变量中存在一个名为 beanDefinitionMap 的map(如下)
/*** <p>bean定义对象的map,按bean名称为键值</p>*/
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
在前面的段落中,笔者使用了婴儿和基因的关系类比bean和BeanDefinition的关系,那么beanDefinitionMap
对应的又是什么呢?他就好比是存储基因的基因库
,存储着各色各样的基因,以用作bean的实例化。
此时相信很多的读者朋友们思路已经很开朗了。父类GenericApplicationContext
的构造方法作用是用于实例化出一个bean工厂,也因此我们就拥有了基因库beanDefinitionMap
,那么子类AnnotationConfigApplicationContext
接下来的任务无疑就是往基因库中添加基因BeanDefinition
。那么Spring官方又是怎么实现的呢?我们把目光重新回到AnnotationConfigApplicationContext
的空构造方法中(如下)
public AnnotationConfigApplicationContext() {// 在IOC容器中初始化一个 注解bean读取器this.reader = new AnnotatedBeanDefinitionReader(this);// 在IOC容器中初始化一个 按类路径扫描注解bean的 扫描器this.scanner = new ClassPathBeanDefinitionScanner(this);}
2.1.1 AnnotatedBeanDefinitionReader
首先我们先来查看AnnotatedBeanDefinitionReader
的构造方法源码:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {this(registry, getOrCreateEnvironment(registry));}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);}
构造方法中除了成员变量的赋值外,在最后一行调用了工具类AnnotationConfigUtils
中的registerAnnotationConfigProcessors方法,通过该方法的名称我们就可以大概知道该方法的用途(寄存器注释配置处理器
),接下来我们就继续查看egisterAnnotationConfigProcessors的源码,探究一下构造AnnotatedBeanDefinitionReader
时发生了什么:
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {registerAnnotationConfigProcessors(registry, null);}public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {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());}}Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(4);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));}if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, REQUIRED_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;}
可以看到,在该方法中主要任务是完成spring内部7个默认bean的注册:
- ConfigurationClassPostProcessor
- AutowiredAnnotationBeanPostProcessor
- RequiredAnnotationBeanPostProcessor
- CommonAnnotationBeanPostProcessor
- PersistenceAnnotationBeanPostProcessor
- EventListenerMethodProcessor
- DefaultEventListenerFactory
1. ConfigurationClassPostProcessor
工厂后置处理器,类上的注解基本都在此解析,spring的包扫描也在里面完成。由于我们目标是为了自己实现一个迷你版的spring,对于该该处理器更细致的阅读,笔者将会在以后的博客中在详细解读。我们暂且知道各个处理器负责功能即可!
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));}
2. AutowiredAnnotationBeanPostProcessor
用于处理 @Autowired 的后置处理器,如mybatis中的mapper属性注入就是通过该处理器进行处理注入的!
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));}
3. RequiredAnnotationBeanPostProcessor
用于处理 @Required 注解的后置处理器
if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}
4. CommonAnnotationBeanPostProcessor
处理公共注解的后置处理器,如:@PostConstruct、@PreDestroy、@Resource等。
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));}
5. PersistenceAnnotationBeanPostProcessor
提供的用于处理注解@PersistenceUnit和@PersistenceContext的处理器。用于注入相应的JPA资源:EntityManagerFactory和EntityManager (或者它们的子类变量)。
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));}
6. EventListenerMethodProcessor
对注解 @EventListener 的处理器,实现spring的事件监听
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));}
7. DefaultEventListenerFactory
EventListenerMethodProcessor
中会调用DefaultEventListenerFactory
的方法,注册的具体实现是由DefaultEventListenerFactory
处理
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));}
看到这里,相信各位读者已经知道了实例化AnnotatedBeanDefinitionReader
的主要作用其实是注册spring内部的7
个处理器。
2.1.2 ClassPathBeanDefinitionScanner
在搞懂了AnnotatedBeanDefinitionReader
的大致作用后,我们回到AnnotationConfigApplicationContext
的构造方法来,继续进入另一条实例化语句的类中ClassPathBeanDefinitionScanner
:
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {this(registry, true);}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {this(registry, useDefaultFilters, getOrCreateEnvironment(registry));}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,Environment environment) {this(registry, useDefaultFilters, environment,(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,Environment environment, @Nullable ResourceLoader resourceLoader) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");this.registry = registry;if (useDefaultFilters) {registerDefaultFilters();}setEnvironment(environment);setResourceLoader(resourceLoader);}
在这其中值得关注的是registerDefaultFilters方法,点击进入该方法:
protected void registerDefaultFilters() {this.includeFilters.add(new AnnotationTypeFilter(Component.class));ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.}try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}}
看到这个方法的第一行,这一行代码任务的其实是扫描特殊的类,比如注解类 @Component (包括我们熟知的 @Controll,@Service,@Repository 等)
至此,this()方法的任务完成的有:
- 初始化bean工厂
- 注册处理器
- 扫描特殊的类(如注解类)
小结:相信有spring基础的读者朋友们可以很快的理解官方这么设计的原因,但刚接触的读者伙伴们可能还是有点懵。不妨我们比喻一下:BeanFactroy就是一家工厂
,而this中调用父类方法实例化BeanFactory其实就是在建立工厂的建筑,接下来实例化AnnotatedBeanDefinitionReader中几个默认处理器,这些处理器我们可以看做成是一台台需要处理工作的机器
,日后会帮助我们完成工厂的具体生产工作;而实例化ClassPathBeanDefinitionScanner则是制定给我们的工厂入口原料制定了指标
,不是所有的原料都可以进入到工厂中制作成为产品的,如:劣质的原料等,只有“达标”的原理才可以进入生产线。(希望这样的比喻可以让大家更好的理解)
2.2 注册bean配置类
回到AnnotationConfigApplicationContext
的构造方法中:
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {// 初始化注解解析器reader,扫描器scannerthis();// 注册配置类annotatedClassesregister(annotatedClasses);// 扫描bean的具体操作refresh();}
在上面的段落中,this
方法已经完成了他自己的”使命“,接下来我们继续研究接下来的方法register(annotatedClasses)
:
public void register(Class<?>... annotatedClasses) {Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");this.reader.register(annotatedClasses);}
进入到register
方法的源码,发现其调用了在this
方法中赋值的reader
即AnnotatedBeanDefinitionReader
对象中的register
方法,我们继续进入,查看其源码:
public void register(Class<?>... annotatedClasses) {for (Class<?> annotatedClass : annotatedClasses) {registerBean(annotatedClass);}}public void registerBean(Class<?> annotatedClass) {doRegisterBean(annotatedClass, null, null, null);}<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {return;}abd.setInstanceSupplier(instanceSupplier);ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);abd.setScope(scopeMetadata.getScopeName());String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);if (qualifiers != null) {for (Class<? extends Annotation> qualifier : qualifiers) {if (Primary.class == qualifier) {abd.setPrimary(true);}else if (Lazy.class == qualifier) {abd.setLazyInit(true);}else {abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}for (BeanDefinitionCustomizer customizer : definitionCustomizers) {customizer.customize(abd);}BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}
此方法主要是按照用户需求将特定的规则配置好,如:是否需要懒加载
小结:在this方法中,我们的工厂虽然已经拥有了多台机器
(处理器),但每个机器都是一些比较多功能的,并不是一台只能完成一个工作的机器,他们有着许多模式,可以联合生产出许多不同的产品。这时,如果我们需要机器们生产出一个符合用户要求的产品,我们就需要按照用户的需求
对每台机器进行一定的设置
,最终生产出符合用户需求的产品。而这就是register方法所完成的任务
2.3 刷新上下文
通过上两个方法的小结,相信读者朋友们都可以猜到最后一个方法需要完成的任务了。是的,经过前两个方法任务的完成后,我们拥有了工厂建筑
、原理指标
、以及调试好的产品生产机器
,接下来就是运送原料
进入工厂,并制造产品的具体过程啦!。进入refresh()
方法中查看源码:
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 1.设置容器的启动日期和活动标志以及执行属性源的任何初始化prepareRefresh();// 2.获取新的beanFactory,销毁原有beanFactory、为每个bean生成BeanDefinition等ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 3.设置beanFactory的属性prepareBeanFactory(beanFactory);try {// 4.允许在上下文子类中对bean工厂进行后处理postProcessBeanFactory(beanFactory);// 5.调用在上下文中注册为bean的工厂处理程序invokeBeanFactoryPostProcessors(beanFactory);// 6.注册拦截bean创建的bean处理器registerBeanPostProcessors(beanFactory);// 7.初始化此上下文的消息源initMessageSource();// 8.初始化此上下文的事件多播程序initApplicationEventMulticaster();// 9.初始化特定上下文子类中的其他特殊beanonRefresh();// 10.检查侦听器bean并注册它们registerListeners();// 11.实例化所有剩余的(非惰性init)单例对象finishBeanFactoryInitialization(beanFactory);// 12.最后一步:发布相应的事件finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// 13.销毁已经创建的单例destroyBeans();// 14.重置同步标识cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// 15.重设公共缓存resetCommonCaches();}}}
源码中可以看出,refresh
方法主要调用了15
个方法(分别对应15
步操作)。
1. prepareRefresh
设置容器的启动日期和活动标志以及执行属性源的任何初始化
protected void prepareRefresh() {// 设置容器启动时间this.startupDate = System.currentTimeMillis();// 设置closed、active状态值this.closed.set(false);this.active.set(true);if (logger.isInfoEnabled()) {logger.info("Refreshing " + this);}// 初始化上下文环境中的任何占位符属性源initPropertySources();// 验证所有标记为required的属性都是可解析的getEnvironment().validateRequiredProperties();// Allow for the collection of early ApplicationEvents,// to be published once the multicaster is available...this.earlyApplicationEvents = new LinkedHashSet<>();}
小结:由于这家工厂的上一任负责人管理不当,工厂倒闭了,你决定接管这个工厂,于是你需要去相关部门办理相关证件,并且证件中记录了你的办理时间(也就是源码中的startupDate
),关闭的工厂得以重新开启(closed=false; active=true
)
2. obtainFreshBeanFactory
obtainFreshBeanFactory
这里主要的作用其实是运送原料
进入工厂,beanDefinition
的注册是在这里完成的。其实现方式有两种,第一种是需要判断是否存在bean工厂,若存在则销毁并创建新的工厂,并为新工厂加上锁;第二种则是只给工厂加上锁。
实现一
org.springframework.context.support.AbstractRefreshableApplicationContext.class
protected final void refreshBeanFactory() throws BeansException {// 若存在工厂,则将其销毁if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {// 创建新的工厂DefaultListableBeanFactory beanFactory = createBeanFactory();beanFactory.setSerializationId(getId());customizeBeanFactory(beanFactory);// 加载beanDefinitionloadBeanDefinitions(beanFactory);// 加上锁synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}}
实现二
org.springframework.context.support.GenericApplicationContext.class
protected final void refreshBeanFactory() throws IllegalStateException {if (!this.refreshed.compareAndSet(false, true)) {throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");}// 加锁this.beanFactory.setSerializationId(getId());}
小结:证件搞下来了,你进入工厂查看情况,发现工厂中有着许多上一任负责人留下的机器
、原料
等物品。如果你打算工厂按照旧生产线生产原来的产品,你大可留下这些物品接着制造产品。但如果你准备生产别的产品,那么旧机器对你来说就没有什么用处了,你可将其销毁掉,重新购买一些新的机器
和原料
。
3. prepareBeanFactory
配置标准的beanFactory,设置ClassLoader,设置SpEL表达式解析器,添加忽略注入的接口,添加bean,添加bean后置处理器等。其实通过命名我们可以知道,该方法需要完成的任务是在bean工厂创建完成后到工厂真正运作前的准备工作(比如:将制作产品的机器
-处理器摆放到正确的位置,以便机器准备启动进入工作状态
等)
4. postProcessBeanFactory
模板方法,此时,所有的beanDefinition已经加载,但是还没有实例化。
允许在子类中对beanFactory进行扩展处理。比如添加ware相关接口自动装配设置,添加后置处理器等,是子类扩展prepareBeanFactory(beanFactory)的方法。除了基础的机器设施外,工厂可能还会为用户定制一些特殊的产品,而这时就需要其他的机器设备的介入帮忙。方法prepareBeanFactory就是帮助我们完成购买这些机器的任务!
5. invokeBeanFactoryPostProcessors
IOC容器的初始化过程有着三个重要的步骤:
- 资源定位
- beanDefinition的载入
- 将beanDefinition以键值对应的方式存入map中
以上三个步骤都在该方法下完成 !!!
invokeBeanFactoryPostProcessors
源码:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}}
顺着invokeBeanFactoryPostProcessors
,我们继续进入第一行中invokeBeanFactoryPostProcessors
的源码:(该方法下将会获取所有的BeanDefinitionRegistryPostProcessor
实现类,首先过滤出实现 PriorityOrdered(优先级)接口的BeanDefinitionRegistryPostProcessor
,对其进行排序后调用方法;接着过滤实现Ordered(顺序)接口的BeanDefinitionRegistryPostProcessor
,进行排序后调用方法,调用所有 其他BeanFactoryPostProcessors
)
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// Invoke BeanDefinitionRegistryPostProcessors first, if any.Set<String> processedBeans = new HashSet<>();if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryProcessor.postProcessBeanDefinitionRegistry(registry);registryProcessors.add(registryProcessor);}else {regularPostProcessors.add(postProcessor);}}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.boolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}// Now, invoke the postProcessBeanFactory callback of all processors handled so far.invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {// skip - already processed in first phase above}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...beanFactory.clearMetadataCache();}
在这其中,我们发现有多处代码都在调用方法invokeBeanFactoryPostProcessors
,此方法具体实现十分复杂,如果读者朋友们不嫌麻烦的话可以尝试使用idea打个断点,一直debug到org.springframework.context.annotation.ComponentScanAnnotationParser
的方法 parse 时,查看属性basePackages
:
获取到了我们在配置类的注解中 @ComponentScan(“com.bosen.www”) 的包名,此时完成了第一步操作 定位资源
,那我们不妨进入parse
方法中调用的doscan
方法:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();for (String basePackage : basePackages) {Set<BeanDefinition> candidates = findCandidateComponents(basePackage);// 开始扫描bean,并解析为beanDefinitionfor (BeanDefinition candidate : candidates) {ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);// 将beanDefinition存入beanDefinitionMap中registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}
至此,IOC容器初始化过程中的三大步骤已经全部完成!!
6. registerBeanPostProcessors
进入registerBeanPostProcessors
方法如下:
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);}
接着进入PostProcessorRegistrationDelegate.registerBeanPostProcessors
:
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);// Register BeanPostProcessorChecker that logs an info message when// a bean is created during BeanPostProcessor instantiation, i.e. when// a bean is not eligible for getting processed by all BeanPostProcessors.int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));// Separate between BeanPostProcessors that implement PriorityOrdered,// Ordered, and the rest.List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);priorityOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, register the BeanPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);// Next, register the BeanPostProcessors that implement Ordered.List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();for (String ppName : orderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);orderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}sortPostProcessors(orderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, orderedPostProcessors);// Now, register all regular BeanPostProcessors.List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();for (String ppName : nonOrderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);nonOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);// Finally, re-register all internal BeanPostProcessors.sortPostProcessors(internalPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, internalPostProcessors);// Re-register post-processor for detecting inner beans as ApplicationListeners,// moving it to the end of the processor chain (for picking up proxies etc).beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));}
小结:其实这一步操作也很好理解,与上一步类似,在完成原本工作的过程中,可能会出现另外一些情况。比如:原本的产品都是生产完成后直接放在商场等实体商店中直接销售的。但是有的用户会在网上下单,这时我们就需要对产品进行快递打包,在产品原本的包装上,还需要加上避免快递运输碰撞的保护包装,而这一步的工作就是交给registerBeanPostProcessors
去完成的。
7. initMessageSource
做国际化功能;消息绑定,消息解析;针对于国际化问题的MessageSource
8. initApplicationEventMulticaster
初始化事件派发器(广播器)
9. onRefresh
spring5中并未对该方法进行实现,是一个空的方法。因此,在子类中可以对其执行自定义的逻辑操作。
10. registerListeners
注册监听器
11. finishBeanFactoryInitialization
实例化所有剩余的(非惰性init)单例对象
12. finishRefresh
最后一步:发布相应的事件
protected void finishRefresh() {// 清除上下文级资源缓存(例如扫描ASM元数据)。clearResourceCaches();// 1. 初始化此上下文的生命周期处理器。initLifecycleProcessor();// 2. 首先将刷新传播到生命周期处理器。getLifecycleProcessor().onRefresh();// 3.推送上下文刷新完毕事件到相应的监听器publishEvent(new ContextRefreshedEvent(this));// Participate in LiveBeansView MBean, if active.LiveBeansView.registerApplicationContext(this);}
到此,IOC容器已经可以宣告初始化成功了!!!
13. destroyBeans
销毁已经创建的单例(工厂出现异常,内部的对象全部销毁)
protected void destroyBeans() {getBeanFactory().destroySingletons();}
14. cancelRefresh
重置同步标识(工厂出现异常,关闭工厂,并将活跃状态改为false
)
protected void cancelRefresh(BeansException ex) {this.active.set(false);}
15. resetCommonCaches
重设公共缓存
protected void resetCommonCaches() {ReflectionUtils.clearCache();ResolvableType.clearCache();CachedIntrospectionResults.clearClassLoader(getClassLoader());}
总结
从工厂
的创建,到开始生产产品的过程中,我们发现,该工厂的负责人
有是一位非常有“远见”的人,思考问题也非常的细致。一个Bean工厂,本能的任务其实就只是生产出bean就可以了,但是负责人
为客户
想的非常周全,在完成基本任务的前提下,还为客户
提供了以后可能会出现的各种需求的解决方案(如:AOP
、DI
等),真就应了那句“顾客就是上帝”啊!
手撸Spring系列2:IOC/DI 思想(源码篇-IOC)相关推荐
- 手撸Spring系列12:MyBatis(源码篇)
说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...
- 手撸Spring系列13:MyBatis(实战篇)
说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...
- 手撸Spring系列4:IOC/DI 思想(实战篇)
说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...
- 手撸Spring系列10:Spring AOP(实战篇)
说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...
- 手撸Spring系列8:Spring AOP(理论篇)
说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正. ...
- spring系列-注解驱动原理及源码-自动装配
目录 一.spring规范的bean自动注入 1.使用@Autowired自动注入 2.使用@Qualifier指定需要装配的组件 3.使用@Autowired装配null对象 4.使用@Primar ...
- spring系列-注解驱动原理及源码-AOP使用及源码解析
目录 一.用注解方式开启AOP 1.实例 2.AOP简单小结 二.AOP原理 1.@EnableAspectJAutoProxy溯源 2.AnnotationAwareAspectJAutoProxy ...
- spring系列-注解驱动原理及源码-声明式事务使用及原理解析
目录 一.环境准备 1.JdbcTemplate使用实例 2.事务添加 二.声明式事务源码分析 1.原理(与AOP非常相似) 一.环境准备 1.JdbcTemplate使用实例 (1)pom文件添加依 ...
- spring系列-注解驱动原理及源码-bean生命周期
目录 一.Bean的初始化和销毁 1.@Bean指定初始化和销毁方法 2.通过实现InitializingBean和Disposabean来初始化和销毁bean 3.使用JSR250定义的@PostC ...
最新文章
- 威斯康辛大学《机器学习导论》2020秋季课程完结,课件、视频资源已开放(附下载)...
- bash: ifconfig: command not found
- Windows下使用idea git 插件
- go标准库的学习-fmt
- 模拟spring - 简单实现spring IOC
- SQLAlchemy 几种查询方式总结
- mysql tinyint和char(1)性能对比
- mysql中的count函数和sum函数如果条件不符合返回什么
- QT的QOpenGLTextureBlitter类的使用
- 教小学妹学算法:十大经典排序算法深度解析
- AWS EC2实例Ubuntu系统设置root用户密码并使用root/ubuntu用户登录
- java.lang.ClassNotFoundException: org.apache.jsp.WEB_002dINF.classes.views.index_jsp
- 苹果6s最大屏幕尺寸_iPhone 6s:经典的小屏旗舰,百元价位也能做苹果党
- Android PdfViewer
- 【★★★★★】提高PHP代码质量的36个技巧
- SCCM2012系列之六,SCCM2012部署前的WDS准备
- nginx + lua 构建网站防护waf(一)
- 【转载】COMSOL Multiphysics 5.3a 安装教程
- 冒险教主-超详细绘制教程
- 基于XTerm模拟发包实现