Spring Ioc之初始化

引言

spring加载xml的对象信息解析实例化成各个bean的过程我在这里就不细讲了,毕竟从头开始看很容易绕晕大家,反而让大家觉得这并不需要写。我们姑且认为spring已经加载好了各类对象信息封装成BeanDefinition,并已经实例化存储在了某个地方。不管是懒汉还是饿汉,都要经历反射出对象实例,然后初始化,我们先从spring中比较好理解的地方来入手IOC,那就是IOC中的bean在实例化之后的初始化操作。主要涉及到BeanPostProcessor,InitializingBean这两个的应用。

IOC的bean初始化

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        invokeInitMethods(beanName, wrappedBean, mbd);

        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }

为了方便阅读,我删除了部分不相干的代码。
AbstractAutowireCapableBeanFactory#initializeBean就是初始化IOC容器中的Bean的主要方法,从这个方法入手,来看看IOC加载Bean到底做了什么?
将实例化好的bean传入该方法:

--> 调用BeanPostProcessor的postProcessBeforeInitialization方法
--> 调用bean实例的初始化方法
--> 调用BeanPostProcessor的postProcessAfterInitialization方法

以下三段代码就是这三个过程:

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

        Object result = existingBean;
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            result = beanProcessor.postProcessBeforeInitialization(result, beanName);
            if (result == null) {
                return result;
            }
        }
        return result;
    }

循环所有实现了BeanPostProcessor类的bean,并执行相应的对象初始化之前的方法postProcessBeforeInitialization

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
            throws Throwable {

        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isDebugEnabled()) {
                logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                        @Override
                        public Object run() throws Exception {
                            ((InitializingBean) bean).afterPropertiesSet();
                            return null;
                        }
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }

        if (mbd != null) {
            String initMethodName = mbd.getInitMethodName();
            if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

该段代码给一些实现了InitializingBean的bean进行初始化操作。

注意:

1:spring为bean提供了两种初始化的方式,需要实现InitializingBean接口,重写afterPropertiesSet方法,或者在配置文件中同过init-method指定,两种方式可以同时使用,但是会先执行afterPropertiesSet再执行init-method。下文还有demo证明。

2:实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率相对来说要高点。但是init-method方式消除了对spring的依赖

3:如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。

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

        Object result = existingBean;
        for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
            result = beanProcessor.postProcessAfterInitialization(result, beanName);
            if (result == null) {
                return result;
            }
        }
        return result;
    }

再次循环所有实现了BeanPostProcessor类的bean,并执行相应的对象初始化之前的方法postProcessAfterInitialization。顺便提一下,以后要写的Spring AOP的底层处理也是通过实现BeanPostProcessor来执行代理包装逻辑的。

IOC的bean注入

我们的ioc对象初始化好了,接下来就要看看最关键的依赖注入了。先思考一个问题,spring在什么时候把对象注入进去的?这里先不解释,我们看这段源码:

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        if (pvs instanceof MutablePropertyValues) {
            ...
        }
        else {
            original = Arrays.asList(pvs.getPropertyValues());
        }

        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

        // Create a deep copy, resolving any references for values.
        List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
        boolean resolveNecessary = false;
        for (PropertyValue pv : original) {
            if (pv.isConverted()) {
                deepCopy.add(pv);
            }
            else {
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
                //在这里解析并塞入了注入的对象
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                Object convertedValue = resolvedValue;
                boolean convertible = bw.isWritableProperty(propertyName) &&
                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
                if (convertible) {
                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
                }
                // Possibly store converted value in merged bean definition,
                // in order to avoid re-conversion for every created bean instance.
                if (resolvedValue == originalValue) {
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
                }
                else if (convertible && originalValue instanceof TypedStringValue &&
                        !((TypedStringValue) originalValue).isDynamic() &&
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
                }
                else {
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
    }

我还是删了很多其他逻辑,这里主要的一句话就是Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
在这里分析并塞入了注入对象的关联。具体怎么操作还得看自己去翻阅。接下来我用最简化的代码方式来展示我的寻找过程:

AbstractBeanFactory类
@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

我们肯定找到拿到每个bean的如果,如果不存在就会创建。

AbstractBeanFactory类
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
        final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
        throws BeansException {
    // Create bean instance.
    if (mbd.isSingleton()) {
        sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
            @Override
            public Object getObject() throws BeansException {
                try {
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    // Explicitly remove instance from singleton cache: It might have been put there
                    // eagerly by the creation process, to allow for circular reference resolution.
                    // Also remove any beans that received a temporary reference to the bean.
                    destroySingleton(beanName);
                    throw ex;
                }
            }
        });
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
}

然后再进入createBean(),它的实现是在 AbstractAutowireCapableBeanFactory 当中:

AbstractAutowireCapableBeanFactory类
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    return beanInstance;
}
AbstractAutowireCapableBeanFactory类
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        populateBean(beanName, mbd, instanceWrapper);
        if (exposedObject != null) {
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
    }           
}

重点关注 createBeanInstance() 和 populateBean() 这两个方法。其中,createBeanInstance方法生成了Bean所包含的Java对象:

AbstractAutowireCapableBeanFactory类
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
    if (resolved) {
        if (autowireNecessary) {
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            return instantiateBean(beanName, mbd);
        }
    }
}
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
    BeanWrapper bw = new BeanWrapperImpl(beanInstance);
    initBeanWrapper(bw);
    return bw;
}

重点关注 getInstantiationStrategy()这个方法,可以看到instantiateBean方法的功能实现是通过调用getInstantiationStrategy().instantiate方法实现的。 getInstantiationStrategy方法的作用是获得实例化的策略对象,也就是指通过哪种方案进行实例化的过程。继续跟踪下去我们可以发现,Spring当中提供了两种实例化方案: BeanUtils和Cglib方式。BeanUtils实现机制是通过Java的反射机制,Cglib是一个第三方类库采用的是一种字节码加强方式机制。Spring中采用的默认实例化策略是Cglib。

接下来就是重头戏建立bean的依赖关系了。我们回到doCreateBean方法中的populateBean(beanName, mbd, instanceWrapper);

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
    applyPropertyValues(beanName, mbd, bw, pvs);
}

有没有发现,我们已经来到我开始讲的applyPropertyValues方法了?
下面我们就不看源码了,我们用反射来把value注入进去,这样更容易理解。

try {
    Method declaredMethod = bean.getClass().getDeclaredMethod(
            "set" + propertyValue.getName().substring(0, 1).toUpperCase()
                    + propertyValue.getName().substring(1), value.getClass());
    declaredMethod.setAccessible(true);
    declaredMethod.invoke(bean, value);
} catch (NoSuchMethodException e) {
    Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
    declaredField.setAccessible(true);
    declaredField.set(bean, value);
}

拿到set参数的方法,如果出现异常,表示并没有写set方法,则就粗暴的方法塞入field。(此处并不是源码,是我根据源码理解写的比较通俗易懂的方式)

这是我觉得在繁多的spring源码中找出一段目标代码先看到,更容易让人能够跟着思路走下去。

题外话:

synchronized (this.dependenciesForBeanMap) {
            Set<String> dependenciesForBean =
                this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
            dependenciesForBean.add(canonicalName);
        }

在看IOC源码的时候看到Map的computeIfAbsent让我恍然大悟,我来用以前怎么写这段代码的来解释这段代码什么意思如下:

Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
if (dependenciesForBean != null){
    dependenciesForBean = new LinkedHashSet<>(8);
}
dependenciesForBean.add(dependentBeanName);
dependenciesForBean.add(canonicalName);

这是jdk1.8才支持的lambda写法,是不是代码更简洁?

再来分享一种简洁的方法,计算每个学生的总分记录到map中:

List<Student> students = new ArrayList<>();
students.add(new Student("张三", "语文", 18));
students.add(new Student("张三", "数学", 20));
Map<String, Integer> resultMap = new HashMap<>();
for (Student student : students) {
    resultMap.merge(student.getName(), student.getScore(), (a, b) -> b + a);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值