Spring技术内幕——IoC

Spring技术内幕

IoC

控制反转,对象依赖关系的管理被反转了,由IoC容器负责,由其进行管理并完成对象的注入。

BeanFactory

基本接口:简单容器,体现了Spring为提供给用户使用的IoC容器所设定的最基本的功能规范。
通过BeanDefinition来管理Spring中各种对象以及他们的依赖关系。BeanDefinition抽象了我们对Bean的定义,是让容器起作用的主要数据类型。

以XmlBeanFactory为例(DefaultListableBeanFactory作为基类):
首先需要指定BeanDefinition信息来源,这个肯定是个xml作为resource,利用DefaultListableBeanFactory初始化一个XmlBeanDefinitionReader,有了这个reader对象,就可以进行相应的读取reader.loadBeanDefinitions(res)。读取完通过一个回调给BeanFactory。

ApplicationContext

高级形态的IoC容器。

  1. 支持应用事件,继承接口ApplicationEventPublisher,和Bean的生命周期结合起来形成事件,配合后置处理器进行处理
  2. 支持不同的信息源、访问资源:可以从不同地方得到Bean定义资源

IoC容器的初始化过程

IoC容器的初始化由refresh()方法启动,容器的刷新。

  1. Resource定位过程:BeanDefinition的资源定位
  2. BeanDefinition的载入和解析:将用户定义好的Bean表示成容器内部的数据结构,也就是BeanDefinition。
    在refresh()方法的中的obtainFreshBeanFactory()调用loadBeanDefinitions():首先根据资源定位,调用BeanDefinitionReader读取并载入。BeanDefinition的载入分为两部分:首先调用xml解析器得到docunment对象,然后根据Spring的Bean规则对这个document解析得到BeanDefinition。
    经过这些IoC容器大致完成了管理Bean对象的数据准备工作,但是重要的依赖注入还没有发生。这些BeanDefinition在IoC容器中还只是静态的配置信息。要想发挥作用,还需要完成数据向容器注册。
  3. 向IoC容器注册这些BeanDefinition,通过BeanDefinitionRegistry接口实现完成,将BeanDefinition注入到一个HashMap中。容器通过这个Map持有BeanDefinition数据的。完成了注册也就完成了容器的初始化工作。

建立好了这些Bean的配置信息,也就是BeanDefinition可以被容器使用了,都在BeanDefinitionMap中可以被检索使用。这些信息是容器建立依赖反转的基础。

IoC容器的依赖注入

在容器接口BeanFactory中getBean接口是触发依赖注入发生的地方。
getBean()作为起点,后面调用了createBean(),不但生成了Bean,还对Bean的初始化进行了处理,比如属性定义,后置处理器等。
与依赖注入密切相关的方法有createBeanInstance和populateBean:

  • createBeanInstance:生成bean所包含的java对象,可以通过工厂方法,也可以容器的autowire特性生成,CGLIB对Bean实例化,反射。
  • 生成这些对象后,怎么样把依赖关系设置好,完成整个依赖注入过程,涉及到对各种Bean属性的处理过程,也就是populateBean()。

依赖递归完成依赖注入,都是以getBean()为入口。

IoC容器其他特性的设计

ApplicationContext和Bean的初始化及销毁

对于BeanFactory,特别是ApplicationContext,容器自身也有一个初始化和销毁的过程,即refresh()方法中的prepareBeanFactory(),这个方法包括为容器配置ClassLoader,PropertyEditor和BeanPostProcessor等。
容器通过管理Bean的生命周期来实现定制化Bean的初始化以及销毁过程:
Bean实例的生命周期:

  1. Bean实例的创建 createBeanInstance()
  2. 为Bean实例设置属性 populateBean()(包括下面的initializeBean)
  3. 调用Bean的初始化方法 initializeBean() 在invokeInitMethods()方法前,会调用一系列aware接口的实现,把相关的BeanName、BeanClassLoader、BeanFactory这些aware接口通过set方法注入到Bean中
  4. 应用可以通过容器使用Bean
  5. 容器关闭时,调用Bean的销毁方法
lazy—init属性和预初始化

向容器索要bean是getBean()方法的调用,此时才会发生依赖注入;除此之外,还可以通过设置lazy-init,这会在容器初始化的过程中完成Bean的依赖注入,对应refresh()方法中的finishBeanFactoryInitialization(beanFactory)。这样容器在第一次取得bean时就很高效。
spring中的bean默认是不会lazy-init的,所以在启动过程就会调用getBean方法。如果不希望该Bean在启动过程就调用,那么将lazy-init设置为true,它就会在程序第一次使用的时候进行初始化。

FactoryBean的实现

返回的是工厂FactoryBean生产的产品,而不是FactoryBean本事,为我们提供了一个很好的封装机制,比如封装proxy对象

BeanPostProcessor

Bean的后置处理器其实就是一个监听器,监听触发的事件。将他向容器中注册后,容器中管理的Bean具备了接收IoC容器事件回调的能力。
在initializeBean()方法中invokeInitMethods()之前调用postProcessorBeforeInitialization()
在initializeBean()方法中除了上述的aware、invokeinitmethods的调用,最后还要applyBeanPostProcessorsAfterInitialization()

autowiring(自动装配)的实现

在populateBean(),使用反射自动查找属性的类型或者名字

Bean对IoC容器的感知

通过aware接口实现对容器的感知:
BeanFactoryAware、BeanNameAware、ApplicationContextAware
在调用初始化回调方法之前,会调用aware接口的setter方法
在postProcessBeforeInitialization()方法中同样调用好多aware接口的set方法

其他

PostConstruct

postconstruct
在这里插入图片描述
在这里插入图片描述
可以看到容器启动后,被@PostConstruct标注的方法被执行了。至于为什么就需要了解一个Bean的创建过程了。(其方法在实例初始化之前被执行)

回顾spring中一个Bean的创建过程

我们采用xml或者注解配置Bean,这些配置会被解析处理变成BeanDefinition,,可以理解为Bean的元数据。最后通过getBean来创建Bean。

@PostConstruct方法将在最后生成Bean的时候被调用。getBean方法是一个Bean生成的入口,为此,我们找到BeanFactory的getBean方法。BeanFactory是一个抽象接口,它抽象了一个Bean工厂或者Bean容器。BeanDefinition和Bean实例都存放在BeanFactory中。
在这里插入图片描述
BeanFactory实现类调用getBean方法,
在这里插入图片描述
跟进doGetBean,以创建单例Bean为例,createBean方法创建Bean实例,所以creatBean包含了核心逻辑

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

createBean委托给doCreateBean处理

 Object beanInstance = doCreateBean(beanName, mbdToUse, args);

doCreateBean方法

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {
    BeanWrapper instanceWrapper = null;


    // 创建Bean的实例对象
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    
    // 

    // 初始化一个Bean
    Object exposedObject = bean;
    try {
        // 处理Bean的注入
        populateBean(beanName, mbd, instanceWrapper);
        // 处理Bean的初始化操作
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    } catch (Throwable ex) {
        // ...
    }

    // ...

    return exposedObject;
}

三个核心逻辑:

1)创建一个Bean的实例对象,createBeanInstance方法执行

2)处理Bean之间的依赖注入,比如@Autowired注解注入的Bean。所以,populateBean方法将会先去处理注入的Bean,因此对于相互注入的Bean来说不用担心Bean的生成先后顺序问题。

3)Bean实例生成,相互注入以后。还需要对Bean进行一些初始化操作。比如我们@PostConstruct注解注释的方法,将再初始化的时候被解析并调用。当然还有一些Aware接口,@Schedule注解啥的也会做相应的处理。

因此我们关注的postConstruct注解的解析调用就是在第三步,进入initializeBean方法

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    // ...

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 初始化前置处理
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // 调用初始化方法
        invokeInitMethods(beanName, wrappedBean, mbd);
    } catch (Throwable ex) {
        // ...
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // 初始化后置处理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

这里主要包含了初始化的前置、后置处理,以后初始化方法的调用。@PostConstruct注解将在applyBeanPostProcessorsBeforeInitialization这个前置处理。
我们跟进applyBeanPostProcessorsBeforeInitialization前置方法

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    // 遍历所有的后置处理器
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        // 调用初始化前置方法
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

我们注意到,这里遍历了在spring启动过程中被注册的BeanPostProcessor接口,并调用其前置方法。

BeanPostProcessor接口被称作Bean的后置处理器接口,也就是说当一个Bean生成以后,会针对生成的Bean做一些处理。比如我们注解了@PostConstruct注解的Bean将会被其中一个BeanPostProcessor处理。或者一些@Schedule之类注解的Bean也会被处理,等一些所谓的后置处理操作。

到这里呢,我们意识到,原来@PostConstruct注解是会被一个专门的BeanPostProcessor接口的具体实现类来处理的。

我们找到该实现类:InitDestroyAnnotationBeanPostProcessor,根据名字我们就大体可以知道这个后置处理器是用于处理Bean的初始化方法注解和Bean的销毁方法注解的。这里,我们只关注@PostConstruct初始化注解相关的

我们跟进InitDestroyAnnotationBeanPostProcessor的postProcessBeanInitialization方法

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // 元数据解析
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
    try {
        // 触发初始化方法
        metadata.invokeInitMethods(bean, beanName);
    }
    catch (InvocationTargetException ex) {
        throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
    }
    return bean;
}

findLifecycleMetadata方法将会解析元数据,所以@PostConstruct注解的初始化方法也会在这里被找到。

invokeInitMethods方法将会触发上一步被找到的方法。

其实,到这里我们大体都可以猜测这两个方法的逻辑了。就是通过反射将Method给找出来,然后再通过反射去调用这些method方法。

跟进findLifecycleMetadata方法看看初始化方法的查找过程吧

private LifecycleMetadata findLifecycleMetadata(Class<?> 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;
  
}

我们更关心的是buildLifecycleMetadata这个构建方法

private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
    List<LifecycleElement> initMethods = new ArrayList<>();
    Class<?> targetClass = clazz;

    do {
        final List<LifecycleElement> currInitMethods = new ArrayList<>();// 变量类中的方法Method对象
        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
            // 判断是否被@PostConstruct注解注释
            if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
                LifecycleElement element = new LifecycleElement(method);
                currInitMethods.add(element);
            }
            // ...
        });

        // 添加到集合中,后续调用
        initMethods.addAll(0, currInitMethods);
        // ...
        targetClass = targetClass.getSuperclass();
    } while (targetClass != null && targetClass != Object.class);

    return new LifecycleMetadata(clazz, initMethods, destroyMethods);
}

可以看出这个方法会解析this.initAnnotationType,这是什么呢?

public CommonAnnotationBeanPostProcessor() {
    setOrder(Ordered.LOWEST_PRECEDENCE - 3);
    setInitAnnotationType(PostConstruct.class);
    setDestroyAnnotationType(PreDestroy.class);
    ignoreResourceType("javax.xml.ws.WebServiceContext");
}


可以看出,这就是PostConstruct注解。

分析完注解包括@PostConstruct元数据的解析,我们回到InitDestroyAnnotationBeanPostProcessor的postProcessBeforeInitialization方法

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // 元数据解析
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
    try {
        // 触发初始化方法
        metadata.invokeInitMethods(bean, beanName);
    }
    catch (InvocationTargetException ex) {
        throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
    }
    return bean;
}

这次我们关注invokeInitMethods方法,相应的执行方法

public void invokeInitMethods(Object target, String beanName) throws Throwable {
    Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
    Collection<LifecycleElement> initMethodsToIterate = (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
    if (!initMethodsToIterate.isEmpty()) {
        for (LifecycleElement element : initMethodsToIterate) {
            if (logger.isTraceEnabled()) {
                logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
            }
            // 调用
            element.invoke(target);
        }
    }
}

跟进invoke,单纯地invoke了method,是我们很熟悉的反射调用

public void invoke(Object target) throws Throwable {
    ReflectionUtils.makeAccessible(this.method);
    this.method.invoke(target, (Object[]) null);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值