引言
前文我们介绍了关于如何学习Spring的源码以及解析了spring中加载配置文件注册Beandefinition的过程。今天我们继续学习DI的过程。
创建实例和DI过程
IOC和DI都是对spring容器特性的描述。IOC指的是将实例的生命周期交给第三方管理(spring)。而DI的侧重点在于某一个类依赖了其他的实例,将实例注入到依赖它的实例的过程。所以可以很明显的看出来DI是发生在类实例已经实例化完成之后的。
创建实例
BeanDefinition
BeanDefinition是对bean属性的定义,包含了bean的状态的属性,如bean的Class对象,单例还是原型等。
上图中是BeanDefinition定义的方法,可以看出其中包括创建Bean的工厂类名称和bean的状态单例,懒加载等。
其中大多数方法都很容易理解,有几个属性这里需要解释下。
dependsOn
dependsOn是指当前Beandefinition所表示的Bean依赖了其他那些bean(不包括基本数据类型),这里依赖的bean并不需要在当前Bean中声明,所以不能通过依赖注入完成,而是需要显示的定义。
autowireCandidate
autowireCandidate用来表示当前bean是否可以被注入到其他实例中。
上面的内容都可以通过xml配置或者注解来配置。
xml
注解
public class JavaBean { public void init(){ //init } public void destroy(){ //destroy } @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) @Bean(initMethod = "init", destroyMethod = "destroy") public JavaBean getEntity(){ return new JavaBean(); }}
继承体系
在上图中实际实际被用来实现Beandefinition的类是RootBeanDefinition
,ChildBeanDefinition
,GenericBeanDefinition
。其中GenericBeanDefinition
是在spring2.5以后才出现的,spring2.5以后都建议使用GenericBeanDefinition
。但是由于以前的代码都是使用RootBeanDefinition
和ChildBeanDefinition
,所以我们也还能看到RootBeanDefinition
,ChildBeanDefinition
这些类。
大体流程
同IOC一样在阅读源码前先来看看一DI的大体流程。
refresh()
在阅读IOC相关实现的时候,除开构造函数外refresh()
就是我们最初的入口,当时只是看了其中的部分代码。实际上refresh()
贯穿了spring启动的整个阶段。当refresh()
方法执行完成时基本就代表spring正常启动了。在DI篇我们来继续看refresh()
的其他的一些代码。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //读取配置文件 注册Beandefinition prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); }catch (BeansException ex) { logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex); destroyBeans(); cancelRefresh(ex); throw ex; } } }
BeanFactoryPostProcessor和BeanPostProcessor
在进行bean的实例化之前会先执行BeanFactoryPostProcessor
和注册BeanPostProcessor
。
BeanFactoryPostProcessor
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }BeanFactoryPostProcessor可以对BeanDefinition进行处理。BeanFactoryPostProcessor在容器实际实例化任何其它的bean之前读取bean的元数据,并且可以对其进行修改修改。用于在执行实例化bean之前进行调用。BeanPostProcessor
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
```实现BeanPostProcessor接口可以在Bean初始化的前后做一些自定义的操作,但是不能够直接操作BeanDefinition元数据。
BeanFactoryPostProcessor
和BeanPostProcessor
都是spring留给我们进行扩展的类。通过实现这两个接口我们可以在bean的实例化过程中添加一些自定义的操作。而需要注意的是这两个接口虽然都提供了扩展bean实例化的功能,但两者确实完全不同的:
BeanFactoryPostProcessor
是在所有的bean都未开始实例化前调用,其可以拿到容器中所有的Beandefinition,所以可以在bean实例化前直接修改bean定义的元数据。BeanPostProcessor
里的实例化前后指的是调用init(init-method)方法前后,这时实际上bean已经开始了实例化(详细的可以参考类的实例化全过程),这时取到的仅仅是某一指定类的实例。即使进行修改也只是修改当前这一实例,而无法对bean的元数据修改。
由于postProcessor可能会在bean的实例化之前进行调用,所以在实例化前context肯定需要先拿到postProcessor,这也就可以解释上面的代码中在解析完配置文件后就开始注册BeanFactoryPostProcessor
和BeanPostProcessor
。
listener
//tood
具体的关于postProcessor和Listener相关会在将整体流程理顺后再详细介绍。
finishBeanFactoryInitialization(ConfigurableListableBeanFactory)
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } beanFactory.setTempClassLoader(null); //缓存bean定义 beanFactory.freezeConfiguration(); beanFactory.preInstantiateSingletons();}
方法首先查找是否开启了注册conversionService,conversionService是用于进行两个类转换的,例如之前说过了Environment类就依赖该实例将定义的变量转换为相应的类型。如果要开启注册conversionService,可以在配置文件中配置。//property
接下来的代码是从bean定义中获取LoadTimeWeaverAware类型优先进行实例化。LoadTimeWeaverAware作用是当类被加载进jvm是动态的转换类。之所以优先实例化这些类是因为在实例化其他类时可能会使用到这些类,比如jpa就极度依赖这些功能。### preInstantiateSingletons()
public void preInstantiateSingletons() throws BeansException { ListbeanNames = new ArrayList (this.beanDefinitionNames); for (String beanName : beanNames) { //获取bean定义 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); //抽象类无法实例化 //非单例和懒加载在需要时才实例化 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { //获取factoryBean的实例 final FactoryBean factory = (FactoryBean ) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction () { @Override public Boolean run() { return ((SmartFactoryBean ) factory).isEagerInit(); } }, getAccessControlContext()); }else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean ) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } }else { getBean(beanName); } } } // 实现了SmartInitializingSingleton接口的回调方法 // SmartInitializingSingleton接口同InitializingBean接口类似都是用于在创建bean时进行一些后置的操作 // 不同之处在于InitializingBean是在每一个实例化的过程中进行调用 而SmartInitializingSingleton是在所有的单例bean被实例化后再refresh中进行回调 for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction
```
preInstantiateSingletons通过一个for循环来实例化所有注册到容器中的bean定义所代表的的bean。
在确定好每一个beanName所代表的的bean确实需要实例化后首先检查当前beanName是否实现了接口
而由于```FactoryBean```本身首先是一个bean,所以我们也可以在ioc容器中获取该bean的实例。如果我们通过getBean(beanName)方法获取的实际上是```FactoryBean```产生的实例类型,想要获取```FactoryBean```的实例需要使用```getBean("&" + beanName)```。#### getBean(String)getBean是一个重载方法,主要还是调用doGetBean()方法实现功能。
protectedT doGetBean( final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { //取该beanName在容器中保存的name //比如上面介绍的factoryBean会加一个& 以及给bean配置的别名等 final String beanName = transformedBeanName(name); Object bean; //尝试从保存bean的容器中取,如果已经存在则不用再次实例化 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); }else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }else { //对于非单例bean 如果该bean正在被创建而又尝试再次创建则会直接抛出异常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { //!containsBeanDefinition(beanName)表示从当前容器中没有找到匹配的BeanDefinition 尝试从父容器中查找 String nameToLookup = originalBeanName(name); if (args != null) { return (T) parentBeanFactory.getBean(nameToLookup, args); }else { return parentBeanFactory.getBean(nameToLookup, requiredType); } } if (!typeCheckOnly) { //标记当前beanName所表示的bean正在被创建或已经被创建 markBeanAsCreated(beanName); } try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); //这一步根据其实现貌似主要是检查当前BeanDefinition表示的bean是否是一个抽象类,但是前面已经检查过了 这里再次检查貌似意义不大 checkMergedBeanDefinition(mbd, beanName, args); //检查是否配置了bean的依赖 如果存在则需要先实例化被依赖的bean String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dependsOnBean : dependsOn) { if (isDependent(beanName, dependsOnBean)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'"); } registerDependentBean(dependsOnBean, beanName); getBean(dependsOnBean); } } if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory
方法中的try-catch块用于创建bean实例,代码很多,不过只是根据bean的作用范围来进行创建如Singleton,prototype或者session等。创建bean的过程大同小异,区别仅在与实例保存的地方。单例bean被保存在一个map中,整个程序运行期间有效。原型bean保存在另外的容器中,每一次使用时需要重新创建。以单例bean创建过程为例,主要实现过程都在```getSingleton(...)```方法中了。```getSingleton(...)```的主要功能就是检查bean是否已经创建,如果没创建就进行创建然后保存到容器中。创建bean的过程由一个匿名内部类实现。#### createBean(String beanName, RootBeanDefinition mbd, Object[] args)
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException { resolveBeanClass(mbd, beanName); try { mbd.prepareMethodOverrides(); }catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { //首先尝试执行BeanPostProcessor,如果存在后置处理器 那么首先实例化bean执行处理器 Object bean = resolveBeforeInstantiation(beanName, mbd); if (bean != null) { return bean; } }catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); } //不存在后置处理器或者存在的执行处理器过程创建实例失败或没有创建实例的动作则执行下面的方法 Object beanInstance = doCreateBean(beanName, mbd, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance;}
上面方法中有这样一句```mbd.prepareMethodOverrides()```。```methodOverrides```实际上市BeanDefinition中的一个属性。其主要用于记录在配置文件中lookup-method和replaced-method参数设置的值。详情可以看这里:[methodOverrides](https://blog.csdn.net/G0_hw/article/details/82149000)#### doCreateBean(...)
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { //如果已经实例化需要重新实例化则从缓存中删除 重新设置 instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } //more code}
方法开头显示创建了一个BeanWrapper的对象,BeanWrapper相当于一个代理器,Spring委托BeanWrapper来完成bean内部属性的初始化。上述方法代码很多,在创建阶段只需要关注前几行。如果该bean的实例未被创建则直接创建一个。创建的方法有createBeanInstance完成。#### createBeanInstance(...)
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { Class beanClass = resolveBeanClass(mbd, beanName); //判断当前bean类是否被定义为public 非public的类无法在其他类中实例化 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()); } if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } 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); } } Constructor [] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } return instantiateBean(beanName, mbd);}
该方法先是尝试查看是否配置了工厂方法,如果存在工厂方法则由工厂方法进行创建。接下来的几行代码是用来提升性能的。spring在创建实例后会将创建该实例的constructor方法缓存,这样下一次需要创建该bean时直接取出构造方法创建即可不需要再重新解析一次。如果没有工厂方法并且构造方法也没有缓存,同时没有找到有参的构造函数,那么会通过放射调用类的默认无参构造函数。#### instantiateBean(String, RootBeanDefinition)该实例化方法没有太多解析的必要,基本就是通过反射的原理获取无参构造函数,通过构造函数来实例化类。### DI到这里为止创建一个实例的过程就完成了,接下来就是检查该实例是否需要被注入其他的属性了。#### 回到doCreateBean(...)前面在创建bean实例时调用到了doCreateBean(...)方法,在创建好实例后的后续功能也依赖于该方法。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { // other-code Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { exposedObject = initializeBean(beanName, exposedObject, mbd); } } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; }else { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } // other-code return exposedObject;}
在DI阶段我们需要关注的就上上面的代码,首先是通过populateBean方法对在配置文件中配置的property属性进行设置值。populateBean顾名思义就是对bean中的属性添加数据。populateBean中其实是通过后置处理器来进行属性的设置,主要的代码如下:
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } }spring中默认注册了以下几种beanPostProcessor,如下:![beanPostProcessor](https://user-gold-cdn.xitu.io/2019/6/22/16b7cfcd1669ee2a?w=695&h=426&f=png&s=32220)每一个beanPostProcessor都会在实例化前后相应的地方进行调用。在这里我们需要关注的是```AutowiredAnnotationBeanPostProcessor```,```RequiredAnnotationBeanPostProcessor```,```CommonAnnotationBeanPostProcessor```这几个注解。顾名思义这几个beanPostProcessor都是用来处理注解的,对应用来处理```@Autowired```,```@Required```,```@Common```几个注解。这里以```@Autowored```的处理为例。#### AutowiredAnnotationBeanPostProcessor
public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass()); try { metadata.inject(bean, beanName, pvs); }catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } return pvs;}private InjectionMetadata buildAutowiringMetadata(Class clazz) { LinkedListelements = new LinkedList (); Class targetClass = clazz; do { LinkedList currElements = new LinkedList (); for (Field field : targetClass.getDeclaredFields()) { AnnotationAttributes annotation = findAutowiredAnnotation(field); if (annotation != null) { if (Modifier.isStatic(field.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static fields: " + field); } continue; } boolean required = determineRequiredStatus(annotation); currElements.add(new AutowiredFieldElement(field, required)); } } for (Method method : targetClass.getDeclaredMethods()) { Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { continue; } AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod); if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { if (Modifier.isStatic(method.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static methods: " + method); } continue; } if (method.getParameterTypes().length == 0) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation should be used on methods with actual parameters: " + method); } } 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); return new InjectionMetadata(clazz, elements);}
该方法主要就是通过解析当前bean有哪些属性被```@Autowired```注解修饰,将其封装为一个```InjectionMetadata```对象。解析的过程通过```findAutowiringMetadata(String beanName, Class clazz)```完成,但实际上主要还是通过上面的```buildAutowiringMetadata(Class clazz)```完成。方法比较简单,首先就是遍历bean的所有字段(Field),通过反射的方法查找字段上的注解,如果存在匹配的注解(```AutowiredAnnotationBeanPostProcessor```匹配的就是```@Autowired```)。如果存在该注解就将这个字段记录表示需要进行注入。当将字段遍历完成后就取出所有的方法,查找方法上是否有该注解,如果存在的话同理记录下该方法。对于被记录下的字段或者方法会被封装成一个```InjectedElement```对象。通过该对象的inject方法完成注入工作。
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Field field = (Field) this.member; try { Object value; if (this.cached) { value = resolvedCachedArgument(beanName, this.cachedFieldValue); } else { DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set autowiredBeanNames = new LinkedHashSet(1); TypeConverter typeConverter = beanFactory.getTypeConverter(); value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); synchronized (this) { if (!this.cached) { if (value != null || this.required) { this.cachedFieldValue = desc; registerDependentBeans(beanName, autowiredBeanNames); if (autowiredBeanNames.size() == 1) { String autowiredBeanName = autowiredBeanNames.iterator().next(); if (beanFactory.containsBean(autowiredBeanName)) { if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName); } } } } else { this.cachedFieldValue = null; } this.cached = true; } } } if (value != null) { ReflectionUtils.makeAccessible(field); field.set(bean, value); } } catch (Throwable ex) { throw new BeanCreationException("Could not autowire field: " + field, ex); } } }刚方法总体来说比较简单,首先是查询当前bean的依赖是否已经被缓存,如果缓存了则从缓存中取即可。如果是第一次解析则从beanfactory中获取相应的依赖属性。synchronized代码块主要就是将解析后的依赖的值缓存起来,建立当前bean和其依赖的属性之间的关系。当下一次创建该类型的bean时可以直接使用不需重新解析。而真正的属性注入是依赖着几行代码:
if (value != null) {
ReflectionUtils.makeAccessible(field); field.set(bean, value); } ```上面的代码没有任何的难度,就是对JDK中反射的api的使用。
基本上后面就是重复这个过程对bean的属性进行注入,在这一过程中最重要的就是beanPostProcessor,注入都已依赖这一组完成的。