Интерпретация Spring построчно (4)

Java

Создание не простое, пожалуйста, указывайте автора в начале перепечатки: Nuggets@小西子 + ссылка на источник~

Если вы хотите узнать больше об исходном коде Spring,Нажмите, чтобы перейти к остальной части построчного анализа серии Spring

Введение

Думал об этом в эти дниbeanКак должен быть написан жизненный цикл, потому что процесс этой части действительно долгий и включает в себя многоbeanPostProcessorСкрытые точки, многие из наших общих функций выполняются через эти спрятанные точки.

В итоге я решил начать с поста в блоге,beanОб основном процессе жизненного цикла говорить довольно грубо (относительно). После этого, через серию сообщений в блоге, некоторые подробности основного процесса и то, как передаются некоторые общие функции.springСдержанныйbeanPostProcessorПохоронен для достижения. Заинтересованные студенты могут выбрать просмотр самостоятельно.

(Из-за ограничения Nuggets на количество слов в статье, этот пост в блоге был вынужден разделить на две части:Нажмите, чтобы перейти к следующей статье)

два,SpringЗапуск контейнера

Я обнаружил, что до сих пор эта серия моихspringСообщение в блоге, я не говорил об этом хорошо.springПроцесс запуска контейнера (тоже прямо приведен в первой статье)refreshметод). Так же, как класс запуска с чистыми аннотациями, упомянутый в предыдущей статье.AnnotationConfigApplicationContext, здесь мы снова рассматриваем:

@Test
public void test() {
    // 我们平常使用AnnotationConfigApplicationContext的时候,只需要这样直接new出来就好了
    applicationContext = new AnnotationConfigApplicationContext("com.xiaoxizi.spring");
    // 然后就可以从容器中拿到bean对象了,说明其实new创建对象的时候,我们容器就做好启动初始化工作了~
    MyAnnoClass myAnnoClass = applicationContext.getBean(MyAnnoClass.class);
    System.out.println(myAnnoClass);
}

// AnnotationConfigApplicationContext的构造器
public AnnotationConfigApplicationContext(String... basePackages) {
    this();
    // 扫描目标包,收集并注册beanDefinition,上一篇具体讲过,这里就不赘述了
    scan(basePackages);
    // 这里就调用到我们大名鼎鼎的refresh方法啦
    refresh();
}

Давайте посмотрим на основной метод запуска этого контейнера.refresh, логика этого метода вAbstractApplicationContextВ классе это тоже типичный шаблонный метод:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 一些准备工作,主要是一下状态的设置事件容器的初始化
        prepareRefresh();

        // 获取一个beanFactory,这个方法里面调用了一个抽象的refreshBeanFactory方法
        // 我们的xml就是在这个入口里解析的,具体的流程有在之前的博文分析过
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 把拿到的beanFactory做一些准备,这里其实没啥逻辑,同学们感兴趣的可以看下
        // 但是这个方法也是一个protected的方法,
        // 也就是说我们如果实现自己的spring启动类/或者spring团队需要写一个新的spring启动类的时候
        // 是可以在beanFactory获取之后做一些事情的,算是一个钩子
        prepareBeanFactory(beanFactory);
		
        try {
            // 这也是一个钩子,在处理beanFactory前允许子类做一些事情
            postProcessBeanFactory(beanFactory);

            // 实例化并且调用factoryPostProcessor的方法,
            // 我们@Compoment等注解的收集处理主要就是在这里做的
            // 有一个ConfigurationClassPostProcessor专门用来做这些注解支撑的工作
          	// 这里的逻辑之前也讲过了
            // 那么其实我们可以说,到这里为止,我们的beanDefinition的收集(注解/xml/其他来源...)
            // 、注册(注册到beanFactory的beanDefinitionMap、beanDefinitionNames)容器
            // 工作基本就全部完成了
            invokeBeanFactoryPostProcessors(beanFactory);
			
            // 从这里开始,我们就要专注bean的实例化了
            // 所以我们需要先实例化并注册所有的beanPostProcessor
            // 因为beanPostProcessor主要就是在bean实例化过程中,做一些附加操作的(埋点)
            // 这里的流程也不再讲了,感兴趣的同学可以自己看一下,
            // 这个流程基本跟FactoryPostProcessor的初始化是一样的,
            // 排序,创建实例,然后放入一个list --> AbstractBeanFactory#beanPostProcessors
            registerBeanPostProcessors(beanFactory);

            // 初始化一些国际化相关的组件,这一块我没有去详细了解过(主要是暂时用不到...)
            // 之后如果有时间也可以单独拉个博文来讲吧
            initMessageSource();

            // 初始化事件多播器,本篇不讲
            initApplicationEventMulticaster();

            // 也是个钩子方法,给子类创建一下特殊的bean
            onRefresh();

            // 注册事件监听器,本篇不讲
            registerListeners();

            // !!!实例化所有的、非懒加载的单例bean
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // 初始化结束,清理资源,发送事件
            finishRefresh();
        }
        catch (BeansException ex) {
            // 销毁已经注册的单例bean
            destroyBeans();
            // 修改容器状态
            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();
        }
    }
}

Грубо говоря, мыspringЗапуск контейнера в основном предназначен для размещения этих нелениво загруженных синглетонов.beanСоздавайте экземпляры и управляйте ими.

три,beanсоздавать экземпляр

1. КакойbeanНужно создавать экземпляр при запуске?

простоrefreshметод, мы виделиfinishBeanFactoryInitializationметод используется для создания экземпляраbean, и английский язык в исходном коде также объясняет, что он должен быть инстанцирован, поэтому оставшиеся нелениво загруженные синглтоныbean, это действительно так? Давайте посмотрим на исходный код:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// skip .. 我把前面的非主流程的跳过了
    // Instantiate all remaining (non-lazy-init) singletons.
    beanFactory.preInstantiateSingletons();
}

// DefaultListableBeanFactory#preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException {
    // 我们之前注册beanDefinition的时候,有把所有的beanName收集到这个beanDefinitionNames容器
    // 这里我们就用到了
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // 循环所有的已注册的beanName
    for (String beanName : beanNames) {
        // 获取合并后的beanDefinition,简单来讲,我们的beanDefinition是可以存在继承关系的
        // 比如xml配置从的parent属性,这种时候,我们需要结合父子beanDefinition的属性,生成一个新的
        // 合并的beanDefinition,子beanDefinition中的属性会覆盖父beanDefinition的属性,
        // 并且这是一个递归的过程(父还可以有父),不过这个功能用的实在不多,就不展开了,
        // 同学们有兴趣可以自行看一下,这里可以就理解为拿到对应的beanDefinition就好了
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        // 非抽象(xml有一个abstract属性,而不是说这个类不是一个抽象类)、单例的、非懒加载的才需要实例化
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                // 这里是处理factoryBean的,暂时不讲,之后再专门写博文
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    final FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                                                    ((SmartFactoryBean<?>) factory)::isEagerInit,
                                                                    getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                       ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            }
            else {
                // !!!我们正常普通的bean会走到这个流程,这里就把这个bean实例化并且管理起来的
                // 这里是获取一个bean,如果获取不到,则创建一个
                getBean(beanName);
            }
        }
    }

    // 所以的bean实例化之后,还会有一些处理
    for (String beanName : beanNames) {
        // 获取到这个bean实例
        Object singletonInstance = getSingleton(beanName);
        // 如果bean实现了SmartInitializingSingleton接口
        if (singletonInstance instanceof SmartInitializingSingleton) {
            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            // 会调用它的afterSingletonsInstantiated方法
            // 这是最外层的一个钩子了,平常其实用的不多
            // 不过@Listener的发现是在这里做的
            smartSingleton.afterSingletonsInstantiated();
        }
    }
}

Как видите, это былонеабстрактный(xmlсуществует одинabstractсвойства, а не говорить, что класс не является абстрактным классом),синглтон,не ленивая загрузкаизbeanбуду тамspringСоздается при запуске контейнера,springЧувак, твой комментарий неверен.Интересно подбирать слова) ~

2. ИспользуйтеgetBeanотbeanFactoryПолучатьbean

Просто сказал, звони.getBeanКогда метод пора, я попробую его первым.springполучить это в контейнереbean, если вы не можете его получить, вы создадите его Теперь давайте разберемся с процессом:

public Object getBean(String name) throws BeansException {
    // 调用了doGetBean
    // 说一下这种方式吧,其实我们能在很多框架代码里看到这种方式
    // 就是会有一个参数最全的,可以最灵活使用的方法,用来处理我们的业务
    // 然后会对不同的使用方,提供一些便于使用的类似于门面的方法,这些方法会简化一些参数,使用默认值填充
    // 或者实际业务可以很灵活,但是不打算完全开放给使用方的时候,也可以使用类似的模式
    return doGetBean(name, null, null, false);
}

getBean->doGetBeanЭто мыbeanFactoryДоступ извнеbeanИнтерфейс просто говорит, что мы инициализируемspringКогда контейнер используется, он будет использоваться для всех синглетонов.beanDefinitionперечислитьgetBeanметоды создают экземпляры тех, которые они определяютbeanВот и все, так что его логика не только дляspringКонтейнерное начальное определение, нам также нужно сделать это мышление, чтобы посмотреть на этот метод:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                          @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
	// 转换一下beanName,暂时不看,之后统一讲
    final String beanName = transformedBeanName(name);
    Object bean;

    // 看一下这个bean是否已经实例化了,如果实例化了这里能直接拿到
    // 这个方法涉及到spring bean的3级缓存,之后会开一篇博客细讲
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        // 通过这个bean实例获取用户真正需要的bean实例
        // 有点绕,其实这里主要是处理当前bean实现了FactoryBean接口的情况的
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    else {
        // 当前线程下的,循环依赖检测,如果当前bean已经在创建中,这里又进来创建了,说明是循环依赖了
        // 会直接报错,代码逻辑也很简单,这里主要是一个TheadLocal持有了一个set,
        // 可以认为是一个快速失败检测,和后面的全局循环依赖检测不是一个容器
        // 容器是 prototypesCurrentlyInCreation
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }


        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // 如果父容器不为空且当前容器没有这个beanName对应的beanDefinition
            // 则尝试从父容器获取(因为当期容器已经确定没有了)
            // 下面就是调用父容器的getBean了
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                    nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }
		// 如果不是只检测类型是否匹配的话,这里要标记bean已创建(因为马上就要开始创建了)
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);
			// 拿到这个bean的所有依赖的bean
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                // 如果依赖不为空,需要先循环实例化依赖
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(...);
                    }
                    registerDependentBean(dep, beanName);
                    try {
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(...);
                    }
                }
            }

            // 这里开始真正创建bean实例的流程了
            if (mbd.isSingleton()) {
                // 如果是单例的bean(当然我们启动的时候会实例化的也就是单例bean了),这里会进行创建
                // 注意这里也是一个getSingleton方法,跟之前那个getSingleton方法差不多,不过这里是
                // 如果获取不到就会使用这个lamdba的逻辑创建一个,
                // 也就是说我的的createBean方法是真正创建bean实例的方法,这里我们之后会重点看
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                // 通过这个bean实例获取用户真正需要的bean实例
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            else if (mbd.isPrototype()) {
                // 如果是多例的bean
                // 那么每次获取都是创建一个新的bean实例
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    // 可以看到这里直接去调用createBean了
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                // 这里逻辑还是一样的
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }
            else {
                // spring是允许我们自定义scope的,这里是自定义scope的逻辑
                // 需要注意的是,spring mvc 的 session、request那些scope也是走这里的逻辑的
                // 这里感兴趣的同学可以自行看下,暂时不讲
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException(...);
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(...);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }
	
    // 这里是类型转换的逻辑,getBean是有可以传类型的重载方法的
    // 不过我们初始化的时候不会走到这个逻辑来,感兴趣的同学可以自行看
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(...);
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            throw new BeanNotOfRequiredTypeException(...);
        }
    }
    // 返回获取到的bean
    return (T) bean;
}

Перейдем к синглтонуbeanЛогика создания , а именно:

if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            // ...
            destroySingleton(beanName);
            throw ex;
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

давайте посмотрим на этоgetSingletonметод, следует отметить, что этот метод находится вDefaultSingletonBeanRegistryВ классе:

/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) {
        // 可以看到,我们先从singletonObjects通过beanName获取实例
		// 这是不是说明singletonObjects就是spring用来存放所以单例bean的容器呢?可以说是的。
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
			// 跳过了一个spring单例bean容器状态判断,
            // 如果spring单例bean容器正在销毁时不允许继续创建单例bean的
            
            // 创建容器之前的钩子,这里默认会把bean那么加入到一个正在创建的beanNameSet,
            // 如果加入失败就代表是循环依赖了。
            // 检测容器是  singletonsCurrentlyInCreation
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                // 这里就是调用传进来的lamdba了
                // 也就是调用了createBean创建了bean实例
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            }
            catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            }
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                // 从正在创建的beanNameSet移除
                afterSingletonCreation(beanName);
            }
            // 如果成功创建了bean实例,需要加入singletonObjects容器
            // 这样下次再获取就能直接中容器中拿了
            if (newSingleton) {
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

Как видите, этоgetSingletonПуть заключается в том, чтобы начать сsingletonObjectsПолучатьbeanНапример, создайте его, если вы не можете его получить, и добавьте к нему некоторую циклическую логику обнаружения зависимостей.

3. createBean,действительноbeanлогика инициализации

мы говоримcreateBeanметод реальныйbeanЛогика инициализации, но эта инициализация не только о создании экземпляра, но также включает в себя некоторую проверку, а также логику, такую ​​как инъекция зависимости в классе, вызовы метода инициализации и т. Д. Давайте кратко посмотрим:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {
	
    RootBeanDefinition mbdToUse = mbd;
    // 获取bean的类型
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }
	
    // Prepare method overrides.
    try {
        // 这里对beanDefinition中的MethodOverrides做一些准备
        // 主要是梳理一下所有重写方法(xml<replaced-method><lockup-method>标签对应的属性)
        // 看下这些方法是否是真的有重载方法,没有重载的话会设置overloaded=false,
        // 毕竟有些人配置的时候即使没有重载方法也会使用<replaced-method>标签
        // (这功能我确实也没用过。。
        mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanDefinitionStoreException(...);
    }

    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        // 给BeanPostProcessors一个机会,在我们的bean实例化之前返回一个代理对象,即完全不走spring的实例化逻辑
        // 也是个BeanPostProcessors的钩子,就是循环beanPostProcessors然后调用的逻辑
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(...);
    }

    try {
        // 这里是spring真正bean实例化的地方了
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        // 获取到了直接返回
        return beanInstance;
    }
    // 跳过异常处理
}

3.0. doCreateBeanкак создать экземплярbeanиз?

только сказал,doCreateBeanЭто мыspringреальное воплощениеbeanЛогика, тогда давайте посмотрим:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 创建bean实例
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                // 调用一个BeanPostProcessor的钩子方法,这里调用的是
                // MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
                // 这个钩子方法是在bean实例创建之后,依赖注入之前调用的,需要注意的是
                // @Autowired和@Value注解的信息收集-AutowiredAnnotationBeanPostProcessor
                // @PostConstruct、@PreDestroy注解信息收集-CommonAnnotationBeanPostProcessor
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(...);
            }
            mbd.postProcessed = true;
        }
    }

   	// 这一部分是使用3级缓存来解决循环依赖问题的,之后再看
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                      isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        // 加入三级缓存
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    
    Object exposedObject = bean;
    try {
        // 依赖注入
        populateBean(beanName, mbd, instanceWrapper);
        // bean初始化-主要是调用一下初始化方法
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
            throw (BeanCreationException) ex;
        }
        else {
            throw new BeanCreationException(...);
        }
    }
	// 这里也算是循环依赖检测的,暂时不讲
    if (earlySingletonExposure) {
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                for (String dependentBean : dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                if (!actualDependentBeans.isEmpty()) {
                    throw new BeanCurrentlyInCreationException(...);
                }
            }
        }
    }
    try {
        // 如果是单例bean,还会注册销毁事件
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(...);
    }

    return exposedObject;
}

Как видите, нашdoCreateBeanПримерно сделал 5 вещей:

  1. Создайтеbeanпример
  2. перечислитьbeanPostProcessorметод захоронения
  3. В зависимости от класса тока впрыскаbean
  4. Тока вызоваbeanметод инициализации
  5. зарегистрировать текущийbeanлогика разрушения

Далее мы подробно рассмотрим эти процессы.

3.1. createBeanInstanceСоздайтеbeanпример

Как вы обычно создаете экземпляр класса? это использовать конструктор напрямуюnewвыйти с одним? Или использовать фабричный метод, чтобы получить его?

очевидно,springОн также поддерживает эти два метода.Если учащиеся помнят синтаксический анализ тегов бобов, они также должны помнитьspringВ дополнение к созданию экземпляра с помощью конструктораbeanизconstructor-argOff-label, он также обеспечиваетfactory-beanиfactory-methodсвойства для настройки с использованием фабричных методов для создания экземпляровbean.

и сказал раньшеConfigurationClassPostProcessorкогда мы говорим о@beanПри маркировке я также увидел, что для@beanОбработка ярлыка, это новыйbeanDefinitionи поставьте текущий класс конфигурации и@BeanМодифицированные методы запихиваются в этоbeanDefinitionизfactoryBeanNameиfactoryMethodNameАтрибуты (могут быть в воздухеConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod).

Далее давайте посмотримcreateBeanInstanceКод:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
	// 校验
    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }
	// 如果beanDefinition里有instanceSupplier,直接通过instanceSupplier拿就行了
    // 这种情况我们就不重点讲了,其实跟工厂方法的方式也差不多
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }
    
	// 如果工厂方法不为空,就使用工厂方法实例化
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // 这里是对非单例bean做的优化,如果创建过一次了,
    // spring会把相应的构造器或者工厂方法存到resolvedConstructorOrFactoryMethod字段
    // 这样再次创建这个类的实例的时候就可以直接使用resolvedConstructorOrFactoryMethod创建了
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            return instantiateBean(beanName, mbd);
        }
    }

    // 如果beanDefinition没有构造器信息,则通过beanPostProcessor选择一个
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    // 1.如果通过beanPostProcessor找到了合适的构造器
    // 2.或者autowireMode==AUTOWIRE_CONSTRUCTOR(这个xml配置的时候也可以指定的)
    // 3.或者有配置构造器的参数(xml配置constructor-arg标签)
    // 4.获取实例化bean是直接传进来了参数
    // 只要符合上面四种情况之一,我们就会通过autowireConstructor方法来实例化这个bean
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
        mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        // 需要构造器方式注入的bean的实例化
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // 这里主要逻辑是兼容kotlin的,我们暂时不看
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        // 需要构造器方式注入的bean的实例化
        return autowireConstructor(beanName, mbd, ctors, null);
    }

    // 不需要特殊处理的话,就直接使用无参构造器了
    return instantiateBean(beanName, mbd);
}

конкретныйinstantiateUsingFactoryMethod,autowireConstructoЯ не буду показывать вам метод здесь, потому что логика внедрения некоторых параметров более сложная, и я открою отдельный блог позже.

Фактически, после получения конкретных параметров, будь то создание конструктора или фабричный метод, это очень ясно, просто отразите вызов напрямую.

instantiateBeanЭто логика получения конструктора без параметров, а затем его отражения и создания экземпляра.Логика относительно проста, и я не буду следовать ей здесь.

3.1.1. ПрохождениеdetermineConstructorsFromBeanPostProcessorsКонструктор методов

Это в основном, чтобы привести всех.determineConstructorsFromBeanPostProcessorsЭтот метод, потому что большинство из нас теперь используют аннотации для объявленияbeanДа, и если вы также используете конструктор для внедрения при использовании аннотаций, то этот метод используется для получения соответствующего конструктора.

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
    throws BeansException {
    if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
                if (ctors != null) {
                    // 一旦拿到构造器就返回了
                    return ctors;
                }
            }
        }
    }
    return null;
}

можно увидеть, черезbeanPostProcessorПогребенная точка, чтобы сделать это, вот вызовSmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors, тут продавать не буду, мы реально поддерживаем метод аннотации, и логика выбора конструктора вAutowiredAnnotationBeanPostProcessorВ середине, вы чувствуете, что этот класс кажется немного знакомым?

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {
    // ...
    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));
    }
    // ...
}

Также звонитеAnnotationConfigUtils#registerAnnotationConfigProcessorsВ методе есть инъекция ~

Как видно из названия, этоbeanPostProcessorследует использовать для обработки@AutowiredАннотация, хотят сказать некоторые студенты, это не аннотация внедрения свойств, какое отношение она имеет к конструктору? Затем у нас есть bean-компонент, внедренный конструктором в качестве примера:

@Service
public class ConstructorAutowiredBean {
    private Student student;
    @Autowired
    public ConstructorAutowiredBean(Student student) {
        this.student = student;
    }
}

Большинство студентов, возможно, забыли,@AutowiredЕго можно использовать для модификации конструктора,@AutowiredПараметры декорированного конструктора также будутspringПолучается из контейнера (может быть, это будет не совсем точно, все понимают о чем я, то есть смысл внедрения конструктора...).

Однако на самом деле мы обычно не попадаем, даже если используем внедрение конструктора.@AutowiredАннотация тоже хороша, это на самом делеAutowiredAnnotationBeanPostProcessorОтказоустойчивая логика при получении конструктора, посмотрим код вместе:

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
    throws BeanCreationException {
	// 整个方法分为了两个部分
    // 第一部分是收集这个类上被@Lookup修饰的方法
    // 这个注解的功能和我们xml的lookup-method标签是一样的
    // 而收集部分也是一样的封装到了一个MethodOverride并且加入到beanDefinition里面去了
    // 虽然这部分工作(@Lookup注解的收集工作)是应该放在bean创建之前(有MethodOverride的话会直接生成代理实例)
    // 但是放在当前这个determineCandidateConstructors方法里我还是觉得不太合适
    // 毕竟跟方法名的语意不符,不过好像确实没有其它合适的钩子了,可能也只能放这了
    if (!this.lookupMethodsChecked.contains(beanName)) {
        if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
            try {
                Class<?> targetClass = beanClass;
                do {
                    ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                        // 循环处理所有的方法,获取@Lookup注解并封装信息
                        Lookup lookup = method.getAnnotation(Lookup.class);
                        if (lookup != null) {
                            LookupOverride override = new LookupOverride(method, lookup.value());
                            try {
                                RootBeanDefinition mbd = (RootBeanDefinition)
                                    this.beanFactory.getMergedBeanDefinition(beanName);
                                mbd.getMethodOverrides().addOverride(override);
                            }
                            catch (NoSuchBeanDefinitionException ex) {
                                throw new BeanCreationException(...);
                            }
                        }
                    });
                    targetClass = targetClass.getSuperclass();
                }
                while (targetClass != null && targetClass != Object.class);

            }
            catch (IllegalStateException ex) {
                throw new BeanCreationException(...);
            }
        }
        this.lookupMethodsChecked.add(beanName);
    }

    // 这里开始是选择构造器的逻辑了
    // 先从缓存拿...这些也是为非单例bean设计的,这样就不用每次进来都走选择构造器的逻辑了
    Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
    if (candidateConstructors == null) {
        synchronized (this.candidateConstructorsCache) {
            candidateConstructors = this.candidateConstructorsCache.get(beanClass);
            if (candidateConstructors == null) {
                Constructor<?>[] rawCandidates;
                try {
                    // 获取当前类的所有的构造器
                    rawCandidates = beanClass.getDeclaredConstructors();
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(...);
                }
                // 这个列表存符合条件的构造器
                List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                Constructor<?> requiredConstructor = null;
                Constructor<?> defaultConstructor = null;
                // 这个primaryConstructor我们不管,是兼容kotlin的逻辑
                Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
                int nonSyntheticConstructors = 0;
                for (Constructor<?> candidate : rawCandidates) {
                    // 循环每个构造器
                    if (!candidate.isSynthetic()) {
                        // 这个判断是判断不是合成的构造器,同学们想了解这个Synthetic可以自行查一下
                        // 这边就不展开了,这个主意是和内部类有关,Synthetic的构造器是编译器自行生成的
                        nonSyntheticConstructors++;
                    }
                    else if (primaryConstructor != null) {
                        continue;
                    }
                    // 找一下构造器上有没有目标注解,说白了就是找@Autowired注解
                    MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
                    if (ann == null) {
                       	// 如果找不到,这里认为可能是因为当前这个class是spring生成的cglib代理类
            			// 所以这里尝试拿一下用户的class
                        Class<?> userClass = ClassUtils.getUserClass(beanClass);
                        // 如果用户的class和之前的beanClass不一致,说明之前那个class真的是代理类了
                        if (userClass != beanClass) {
                            try {
                                // 这个时候去userClass拿一下对应的构造器
                                Constructor<?> superCtor =
                                    userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                // 再在用户的构造器上找一下注解
                                ann = findAutowiredAnnotation(superCtor);
                            }
                            catch (NoSuchMethodException ex) {
                            }
                        }
                    }
                    if (ann != null) {
                        // 这里是找到注解了
                        if (requiredConstructor != null) {
                            // 这个分支直接报错了,意思是之前已经如果有被@Autowired注解修饰了的构造器
                            // 且注解中的Required属性为true的时候,
                            // 就不允许再出现其他被@Autowired注解修饰的构造器了
                            // 说明@Autowired(required=true)在构造器上的语言是必须使用这个构造器
                            throw new BeanCreationException(...);
                        }
                        // 拿注解上的required属性
                        boolean required = determineRequiredStatus(ann);
                        if (required) {
                            if (!candidates.isEmpty()) {
                                // 这里也是一样的,有required的构造器,就不预约有其他被
                                // @Autowired注解修饰的构造器了
                                throw new BeanCreationException(...);
                            }
                            // requiredConstructor只能有一个
                            requiredConstructor = candidate;
                        }
                        // 符合条件的构造器加入列表-即有@Autowired的构造器
                        candidates.add(candidate);
                    }
                    else if (candidate.getParameterCount() == 0) {
                        // 如果构造器的参数为空,那就是默认构造器了
                        defaultConstructor = candidate;
                    }
                }
                
                if (!candidates.isEmpty()) {
                    // 如果被@Autowired修饰的构造器不为空
                    if (requiredConstructor == null) {
                        // 如果没有requiredConstructor,就把默认构造器加入列表
                        // 如果有requiredConstructor,实际上candidates中就只有一个构造器了
                        if (defaultConstructor != null) {
                            candidates.add(defaultConstructor);
                        }
                        else if (candidates.size() == 1 && logger.isInfoEnabled()) {
                            logger.info(...);
                        }
                    }
                    // 然后把candidates列表赋值给返回值
                    candidateConstructors = candidates.toArray(new Constructor<?>[0]);
                }
                else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
                    // 如果当前类总共也只有一个构造器,并且这个构造器是需要参数的
                    // 那就直接使用这个构造器了
                    // 这就是为什么我们平常构造器注入不打@Autowired注解也可以的原因
                    candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
                }
                // 以下主要是处理primaryConstructor的,我们就不读了
                else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                         defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
                    candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
                }
                else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
                    candidateConstructors = new Constructor<?>[] {primaryConstructor};
                }
                else {
                    // 都不满足,就是空数组了
                    candidateConstructors = new Constructor<?>[0];
                }
                // 处理完之后放入缓存
                this.candidateConstructorsCache.put(beanClass, candidateConstructors);
            }
        } 
    }
    // 之所以上面解析的时候,没找到构造器也是使用空数组而不是null
    // 就是为了从缓存拿的时候,能区分究竟是没处理过(null),还是处理了但是找不到匹配的(空数组)
    // 避免缓存穿透
    return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

Если вы можете найти подходящий конструктор, вы можете создать экземпляр объекта напрямую через отражение~

3.2. ПоbeanPostProcessorПохоронен для сбора информационных заметок

пройти черезcreateBeanInstanceПосле создания экземпляра класса, но до внедрения свойств у нас естьbeanPostProcessorВызов метода скрытой точки:

synchronized (mbd.postProcessingLock) {
    if (!mbd.postProcessed) {
        try {
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(...);
        }
        mbd.postProcessed = true;
    }
}
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof MergedBeanDefinitionPostProcessor) {
            MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
            bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
        }
    }
}

Поскольку часть логики поддержки аннотаций в этом скрытом месте довольно важна, я расскажу о ней отдельно здесь.

3.2.1. CommonAnnotationBeanPostProcessorсобирать@PostConstruct,@PreDestroy,@ResourceИнформация

CommonAnnotationBeanPostProcessorСлишкомAnnotationConfigUtils#registerAnnotationConfigProcessorsМетод вводится, поэтому я не буду брать вас с собой, чтобы прочитать его здесь. так какCommonAnnotationBeanPostProcessorДостигнутоMergedBeanDefinitionPostProcessorинтерфейс, поэтому он тоже будет вызываться в этой скрытой точке.Давайте посмотрим на эту логику:

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
    implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable{
    // 构造器
    public CommonAnnotationBeanPostProcessor() {
		setOrder(Ordered.LOWEST_PRECEDENCE - 3);
        // 给两个关键字段设置了
		setInitAnnotationType(PostConstruct.class);
		setDestroyAnnotationType(PreDestroy.class);
		ignoreResourceType("javax.xml.ws.WebServiceContext");
	}
    
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        // 这里调用了父类的方法,正真的收集`@PostConstruct`、`@PreDestroy`注解的逻辑是在这里做的
        super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
        // 这里就是收集@Resource注解的信息啦
        InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
        // 检查一下
        metadata.checkConfigMembers(beanDefinition);
    }
}
3.2.1.1 Аннотации жизненного цикла@PostConstruct,@PreDestroyсобрать сообщение

Давайте посмотрим на реализацию родительского класса для сбора аннотаций жизненного цикла:

public class InitDestroyAnnotationBeanPostProcessor
    implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable{
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        // 寻找生命周期元数据
        LifecycleMetadata metadata = findLifecycleMetadata(beanType);
        // 对收集到的声明周期方法做一下校验处理
        metadata.checkConfigMembers(beanDefinition);
    }

    private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
        if (this.lifecycleMetadataCache == null) {
            // 没有开启缓存就直接拿构建生命周期元数据了
            return buildLifecycleMetadata(clazz);
        }
        // 有开启缓存的话,就先从缓存找,找不到再构建,然后丢回缓存
        LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
        if (metadata == null) {
            synchronized (this.lifecycleMetadataCache) {
                metadata = this.lifecycleMetadataCache.get(clazz);
                if (metadata == null) {
                    // 构建
                    metadata = buildLifecycleMetadata(clazz);
                    this.lifecycleMetadataCache.put(clazz, metadata);
                }
                return metadata;
            }
        }
        return metadata;
    }
    
    private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
        // 简单判断类上是不是一定没有initAnnotationType和destroyAnnotationType这两个注解修饰的方法
        // 相当于快速失败
        // 需要注意的是,当前场景下,这两个注解实例化的时候已经初始化为PostConstruct和PreDestroy了
        if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
            return this.emptyLifecycleMetadata;
        }
		// 用来储存类上所有初始化/销毁方法的容器
        List<LifecycleElement> initMethods = new ArrayList<>();
        List<LifecycleElement> destroyMethods = new ArrayList<>();
        Class<?> targetClass = clazz;

        do {
            // 中间容器来储存当前类的初始化/销毁方法
            final List<LifecycleElement> currInitMethods = new ArrayList<>();
            final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
			// 循环类上的每一个方法
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
                    // 如果方法被@PostConstruct注解修饰,包装成一个LifecycleElement
                    LifecycleElement element = new LifecycleElement(method);
                    // 加入收集初始化方法的中间容器
                    currInitMethods.add(element);
                }
                if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
                    // 如果方法被@PreDestroy注解修饰,包装成一个LifecycleElement
                    // 加入收集销毁方法的中间容器
                    currDestroyMethods.add(new LifecycleElement(method));
                }
            });
			// 加入所有初始化/销毁方法的容器
            // 需要注意的是,在整个循环过程中,
            // 当前类的初始化方法都是加入初始化方法容器的头部
            // 当前类的销毁方法都是加入销毁方法容器的尾部
            // 所以可以推断,初始化方法调用的时候是从父类->子类调用
            // 而销毁方法从子类->父类调用。
            // 即 bean初始化->调用父类初始化方法->调用子类初始化方法->...->调用子类销毁方法->调用父类销毁方法->销毁bean
            initMethods.addAll(0, currInitMethods);
            destroyMethods.addAll(currDestroyMethods);
            // 获取父类,循环处理所有父类上的初始化/销毁方法
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);
		// 把当前类class对象+初始化方法列表+销毁方法列表封装成一个LifecycleMetadata对象
        return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
                new LifecycleMetadata(clazz, initMethods, destroyMethods));
    }
}

Посмотрите на эти метаданные жизненного циклаLifecycleMetadataСтруктура:

private class LifecycleMetadata {
    // 目标类
    private final Class<?> targetClass;
    // 目标类上收集到的初始化方法
    private final Collection<LifecycleElement> initMethods;
    // 目标类上收集到的销毁方法
    private final Collection<LifecycleElement> destroyMethods;
    // 检查、校验后的初始化方法
    @Nullable
    private volatile Set<LifecycleElement> checkedInitMethods;
    // 检查、校验后的销毁方法
    @Nullable
    private volatile Set<LifecycleElement> checkedDestroyMethods;
    
    public void checkConfigMembers(RootBeanDefinition beanDefinition) {
        // 这是那个检查、校验方法
        Set<LifecycleElement> checkedInitMethods = new LinkedHashSet<>(this.initMethods.size());
        for (LifecycleElement element : this.initMethods) {
            // 循环处理每个初始化方法
            String methodIdentifier = element.getIdentifier();
            // 判断是否是标记为外部处理的初始化方法,
            // 如果是外部处理的方法的话,其实spring是不会管理这些方法的
            if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
                // 这里把当前方法注册到这个externallyManagedDestroyMethods
                // 我猜想是方法签名相同的方法就不调用两次了
                // 比如可能父类的方法打了@PostConstruct,子类重写之后也在方法上打了@PostConstruct
                // 这两个方法都会被收集到initMethods,但是当然不应该调用多次
                beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
                // 加入了检查后的初始化方法列表,实际调用初始化方法时也是会调用这个列表
                checkedInitMethods.add(element);
            }
        }
        // 销毁方法的处理逻辑和初始化方法一样,我直接跳过了
        this.checkedInitMethods = checkedInitMethods;
        this.checkedDestroyMethods = checkedDestroyMethods;
    }
}

Пока что мы на самом делеCommonAnnotationBeanPostProcessorАннотация жизненного цикла процесса сбора завершена, в основном через штамп метода родительского класса, который должен быть@PostConstruct,@PreDestroyИнформация о декорированном методе инкапсулирована вLifecycleMetadata. прочитай этоInitDestroyAnnotationBeanPostProcessorПосле логики возникнет ли у студентов желание реализовать собственный набор аннотаций жизненного цикла? В конце концов, напишите класс для наследования, а затем в своем собственном конструкторе классаsetнемногоinitAnnotationType,destroyAnnotationTypeВот и все!

3.2.1.2 Аннотации внедрения зависимостей@Resourceсобрать сообщение

только что сказал нашfindResourceMetadataметод используется для сбора@ResourceДля информации аннотации давайте посмотрим на логику здесь:

private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
    // 也是一个缓存逻辑
    String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
    InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    if (InjectionMetadata.needsRefresh(metadata, clazz)) {
        synchronized (this.injectionMetadataCache) {
            metadata = this.injectionMetadataCache.get(cacheKey);
            if (InjectionMetadata.needsRefresh(metadata, clazz)) {
                if (metadata != null) {
                    metadata.clear(pvs);
                }
                // 构建逻辑
                metadata = buildResourceMetadata(clazz);
                this.injectionMetadataCache.put(cacheKey, metadata);
            }
        }
    }
    return metadata;
}

private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
    // 这个方法除了收集@Resource注解之外,
    // 其实还会收集@WebServiceRef和@EJB注解(如果你的项目有引入这些)
    // 不过由于@WebServiceRef和@EJB我们现在基本也不用了(反正我没用过)
    // 我这边就把相应的逻辑删除掉了,这样看也清晰点
    // 而且这些收集逻辑也是一致的,最多只是说最后把注解信息封装到不同的子类型而已
    // 快速失败检测
    if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
        return InjectionMetadata.EMPTY;
    }
	// 收集到注入元素
    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        // 这里套路其实跟收集生命周期注解差不多了
        // 也是循环收集父类的
        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
        // 循环处理每个属性
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            if (...) {...} // 其他注解的处理
            else if (field.isAnnotationPresent(Resource.class)) {
                // 静态属性不允许注入,当然其实@Autowired和@Value也是不允许的,
                // 只是那边不会报错,只是忽略当前方法/属性而已
                if (Modifier.isStatic(field.getModifiers())) {
                    throw new IllegalStateException(...);
                }
                if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
                    // 不是忽略的资源就加入容器
                    // ejb那些就是封装成EjbRefElement
                    currElements.add(new ResourceElement(field, field, null));
                }
            }
        });
		// 循环处理每个方法,比如@Resource修饰的set方法啦(当然没规定要叫setXxx)
        // 这里会循环当前类声明的方法和接口的默认(default)方法
        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            // 这里是处理桥接方法的逻辑,桥接方法是编译器自行生成的方法。
            // 主要跟泛型相关,这里也不多拓展了
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                return;
            }
            // 由于这个工具类的循环是会循环到接口的默认方法的
            // 这里这个判断是处理以下场景的:
            // 接口有一个default方法,而当前类重写了这个方法
            // 那如果子类重写的method循环的时候,这个if块能进去
            // 接下来接口的相同签名的默认method进来时,
            // ClassUtils.getMostSpecificMethod(method, clazz)会返回子类中重写的那个方法
            // 这是就和当前方法(接口方法)不一致,就不会再进if块收集一遍了
            if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                if (...) {...} // 其他注解的处理
                else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
                    if (Modifier.isStatic(method.getModifiers())) {
                        throw new IllegalStateException(...);
                    }
                    Class<?>[] paramTypes = method.getParameterTypes();
                    if (paramTypes.length != 1) {
                        // 原来@Resource方法注入只支持一个参数的方法(set方法)
                        // 这个限制估计是规范定的
                        // @Autowired没有这个限制
                        throw new IllegalStateException(...);
                    }
                    if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
                        // 封装了一个属性描述符,这个主要用来加载方法参数的,暂时不展开
                        PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                        // 也封装成一个ResourceElement加入容器
                        currElements.add(new ResourceElement(method, bridgedMethod, pd));
                    }
                }
            }
        });
		// 每次都放到列表的最前面,说明是优先会注入父类的
        elements.addAll(0, currElements);
        targetClass = targetClass.getSuperclass();
    }
    while (targetClass != null && targetClass != Object.class);
	// 把当前类的class和收集到的注入元素封装成一个注入元数据
    return InjectionMetadata.forElements(elements, clazz);
}

Видно, что он на самом деле похож на жизненный цикл, он тоже собирает аннотационную информацию, а затем инкапсулирует ее, но сбор этого элемента инъекции должен собирать атрибуты и (set), мы по-прежнему смотрим на эту структуру данных, как обычно:

public class InjectionMetadata {
    // 目标类--属性需要注入到哪个类
    private final Class<?> targetClass;
	// 注入元素
    private final Collection<InjectedElement> injectedElements;
	// 检查后的注入元素
    @Nullable
    private volatile Set<InjectedElement> checkedElements;
}

public abstract static class InjectedElement {
		// Member是Method和Field的父类
		protected final Member member;
		// 通过这个属性区分是field还是method
		protected final boolean isField;
		// 属性描述符,如果是method会通过这个描述符获取入参
		@Nullable
		protected final PropertyDescriptor pd;
		@Nullable
		protected volatile Boolean skip;
}

получитьInjectionMetadataПослеmetadata.checkConfigMembersЛогика точно такая же, как и у жизненного цикла, так что это не так.

Итак, мы здесьCommonAnnotationBeanPostProcessorАнализируется логика скрытой точки класса после создания экземпляра компонента.

3.2.2. AutowiredAnnotationBeanPostProcessorсобирать@Autowired,@ValueИнформация

AutowiredAnnotationBeanPostProcessorСроки регистрации на этот класс обсуждались много раз, а такжеAnnotationConfigUtils#registerAnnotationConfigProcessorsМетод инжектирован, давайте посмотрим на него прямо здесьpostProcessMergedBeanDefinitionКак метод собирает аннотационную информацию:

public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
    implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
    // 自动注入注解类型
    private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
    
    public AutowiredAnnotationBeanPostProcessor() {
        // autowiredAnnotationTypes中放入@Autowired、@Value
        this.autowiredAnnotationTypes.add(Autowired.class);
        this.autowiredAnnotationTypes.add(Value.class);
        try {
            this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
                                              ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
        }
        catch (ClassNotFoundException ex) {
            // JSR-330 API not available - simply skip.
        }
    }
    
    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        // 这里其实就很熟悉了,和@Resource的处理过程看起来就是一模一样的
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);
    }
	
    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        // 缓存逻辑我这边就不看了,都是一模一样的
        // 这个,其实连收集逻辑都基本是一致的,我们就简单过一下吧
        if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
            return InjectionMetadata.EMPTY;
        }

        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;

        do {
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
			// 处理属性
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                MergedAnnotation<?> ann = findAutowiredAnnotation(field);
                if (ann != null) {
                    // 静态属性不允许注入
                    if (Modifier.isStatic(field.getModifiers())) {
                        return;
                    }
                    // @Autowrired有一个required属性需要收集一下
                    boolean required = determineRequiredStatus(ann);
                    currElements.add(new AutowiredFieldElement(field, required));
                }
            });
			// 处理方法
            ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                    return;
                }
                MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
                if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                    if (Modifier.isStatic(method.getModifiers())) {
						// 静态方法不处理,忽略,相当于不生效,@Resource那边是会报错的。
                        return;
                    }
                    boolean required = determineRequiredStatus(ann);
                    // 封装一个属性描述符描述符
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    currElements.add(new AutowiredMethodElement(method, required, pd));
                }
            });
			// 父类优先
            elements.addAll(0, currElements);
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);
		// 封装到InjectionMetadata
        return InjectionMetadata.forElements(elements, clazz);
    }
}

Ах, скучно, эта логика так же проста, как@ResourceЛечение точно такое же, есть ли у студентов сомнения - такой похожий метод,springЗачем писать дважды?Является ли это нарушениемDRYА как же принцип? Учащиеся думают над этим вопросом.

я не думаю, что это было нарушеноDRYпринцип, но дляjavax.inject.InjectРазделение аннотаций пока нецелесообразно и должно быть разделено наcommon; иcommonОбработка различных типов аннотаций в (@EJB,@Resource,@WebServiceRef)использоватьif-elseЭто также не очень элегантно, и можно использовать небольшой шаблон стратегии.

Однако у всех разные мнения на этот счет. Заинтересованные студенты также могут обсудить это в комментариях~

3.2.3. РезюмеCommonAnnotationBeanPostProcessorиAutowiredAnnotationBeanPostProcessor

В основном эти дваbeanPostProcessorКое-что я сделал, и это тоже тесно связано с нашим обычным развитием.Вот краткое содержание.

3.2.3.1 Разделение функций

эти двоеbeanPostProcessorФункции делятся на:

  1. CommonAnnotationBeanPostProcessorосновная обработкаjdkСоответствующие нормативные примечания,@Resource,@PostConstructи т.д. аннотацииjdkКак определено в спецификации.

    • Связанный с жизненным циклом коллекции@PostConstruct,@PreDestroyИнформация аннотаций заключена вLifecycleMetadata
    • Сбор аннотаций внедрения ресурсов (наша основная задача@Resource) информация инкапсулируется вInjectionMetadata
  2. AutowiredAnnotationBeanPostProcessorосновная обработкаspringОпределенный@Autowiredсвязанные функции

    • Я должен сказать здесь, что я думаю, что этот класс также используется для работы сjavax.inject.Injectнеразумный

    • Собирать аннотации, связанные с автоматической инъекцией@Autowired,@Valueинформация упакована вInjectionMetadata

3.2.3.2 Использование@Resouceвсе еще@Autowired?

Итак, что мы рекомендуем использовать в нашем ежедневном процессе разработки?@Resouceвсе еще@AutowiredШерстяная ткань? Я думаю, что доброжелательный видит благожелательный, а мудрый видит мудрость.Я лишь кратко перечислю вопросы, на которые необходимо обратить внимание при использовании этих двух аннотаций:

  1. @Resouceи@AutowiredНи один из них не может использоваться для внедрения статических свойств (путем использования аннотаций к статическим свойствам и статическим методам).
  2. использовать@ResouceПри внедрении статических свойств он будет выброшенIllegalStateExceptionВызывает сбой текущего процесса инициализации экземпляра
  3. при использовании@AutowiredПри внедрении статического свойства будет игнорироваться только текущее свойство.Если оно не внедрено, это не приведет к сбою процесса инициализации экземпляра.
  4. использовать@ResouceПри изменении метода метод может иметь только один входной параметр, и@Autowiredбезлимитный
  5. @ResouceпринадлежатьjdkМожно считать, что вторжение в проект нулевое;@Autowiredпринадлежатьspringспецификация, использование@Autowiredнельзя заменить другимIOCФреймворк (я его не заменял...)

(Из-за ограничения Nuggets на количество слов в статье, этот пост в блоге был вынужден разделить на две части:Нажмите, чтобы перейти к следующей статье)

Создание не простое, пожалуйста, указывайте автора в начале перепечатки: Nuggets@小西子 + ссылка на источник~

Если вы хотите узнать больше об исходном коде Spring,Нажмите, чтобы перейти к остальной части построчного анализа серии Spring

٩(* ఠO ఠ)=3⁼³₌₃⁼³₌₃⁼³₌₃du ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла ла. . .

Вот блогер-новичок Сяо Сизи, большие парни видели это, пожалуйста, поставьте лайк в левом верхнем углу~~