加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

【spring源码分析】IOC容器初始化(五)——查漏补缺(1)

发布时间:2020-12-16 23:39:32 所属栏目:百科 来源:网络整理
导读:前言:前面已经对IOC容器初始化的大致流程梳理了一遍,但是比较粗略,下面进行查漏补缺。 1.BeanDefinitionParserDelegate 在对bean的xml文件进行解析的过程中BeanDefinitionParserDelegate类非常重要,这里对其进行分析。 ① checkNameUniqueness检查bean的

前言:前面已经对IOC容器初始化的大致流程梳理了一遍,但是比较粗略,下面进行查漏补缺。


1.BeanDefinitionParserDelegate

在对bean的xml文件进行解析的过程中BeanDefinitionParserDelegate类非常重要,这里对其进行分析。

checkNameUniqueness检查bean的名称是否被使用

 1 /**
 2      * Validate that the specified bean name and aliases have not been used already
 3      * within the current level of beans element nesting.
 4      */
 5     protected void checkNameUniqueness(String beanName,List<String> aliases,Element beanElement) {
 6         String foundName = null;
 7 
 8         if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {
 9             foundName = beanName;
10         }
11         if (foundName == null) {
12             foundName = CollectionUtils.findFirstMatch(this.usedNames,aliases);
13         }
14         if (foundName != null) {
15             error("Bean name ‘" + foundName + "‘ is already used in this <beans> element",beanElement);
16         }
17 
18         this.usedNames.add(beanName);
19         this.usedNames.addAll(aliases);
20     }

通过源码,可知这里对bean的name和别名都进行了检测,如果通过则会将beanName和aliases存储在usedNames中。

usedNames为HashSet,保证beanName的唯一性。

②在解析bean元素的过程中,有如下代码,让人很费解:

通过查看ParseState源码注解,终于知道push和pop的作用:

追踪解析bean过程中的逻辑位置,如果调用#toString方法,则打印出解析bean过程中的一些相关信息。

decorateBeanDefinitionIfRequired方法:

 1 public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
 2             Element ele,BeanDefinitionHolder definitionHolder,@Nullable BeanDefinition containingBd) {
 3 
 4         System.out.println("BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired对自定义属性进行解析");
 5         BeanDefinitionHolder finalDefinition = definitionHolder;
 6 
 7         // Decorate based on custom attributes first.
 8         NamedNodeMap attributes = ele.getAttributes();
 9         for (int i = 0; i < attributes.getLength(); i++) {
10             Node node = attributes.item(i);
11             finalDefinition = decorateIfRequired(node,finalDefinition,containingBd);
12         }
13 
14         // Decorate based on custom nested elements.
15         NodeList children = ele.getChildNodes();
16         for (int i = 0; i < children.getLength(); i++) {
17             Node node = children.item(i);
18             if (node.getNodeType() == Node.ELEMENT_NODE) {
19                 finalDefinition = decorateIfRequired(node,containingBd);
20             }
21         }
22         return finalDefinition;
23     }

该函数的主要作用是对bean标签的自定义属性进行解析,将解析的属性封装进BeanDefinitionHolder中(第11行),具体操作代码在decorateIfRequired函数中:

 1 public BeanDefinitionHolder decorateIfRequired(
 2             Node node,BeanDefinitionHolder originalDef,@Nullable BeanDefinition containingBd) {
 3 
 4         String namespaceUri = getNamespaceURI(node);
 5         if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
 6             NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
 7             if (handler != null) {
 8                 BeanDefinitionHolder decorated =
 9                         handler.decorate(node,originalDef,new ParserContext(this.readerContext,this,containingBd));
10                 if (decorated != null) {
11                     return decorated;
12                 }
13             }
14             else if (namespaceUri.startsWith("http://www.springframework.org/")) {
15                 error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]",node);
16             }
17             else {
18                 // A custom namespace,not to be handled by Spring - maybe "xml:...".
19                 if (logger.isDebugEnabled()) {
20                     logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
21                 }
22             }
23         }
24         return originalDef;
25     }

分析:

注意第5行会判断节点的空间类型,只有自定义空间类型才会进入分支,通过空间uri获得空间处理器,对于bean的属性对应的是:http://www.springframework.org/schema/p标签,会取得SimplePropertyNamespaceHandler处理器,第9行:通过decorate方法进行处理:

 1 @Override
 2     public BeanDefinitionHolder decorate(Node node,BeanDefinitionHolder definition,ParserContext parserContext) {
 3         if (node instanceof Attr) {
 4             Attr attr = (Attr) node;
 5             String propertyName = parserContext.getDelegate().getLocalName(attr);
 6             String propertyValue = attr.getValue();
 7             MutablePropertyValues pvs = definition.getBeanDefinition().getPropertyValues();
 8             if (pvs.contains(propertyName)) {
 9                 parserContext.getReaderContext().error("Property ‘" + propertyName + "‘ is already defined using " +
10                         "both <property> and inline syntax. Only one approach may be used per property.",attr);
11             }
12             if (propertyName.endsWith(REF_SUFFIX)) {
13                 propertyName = propertyName.substring(0,propertyName.length() - REF_SUFFIX.length());
14                 pvs.add(Conventions.attributeNameToPropertyName(propertyName),new RuntimeBeanReference(propertyValue));
15             }
16             else {
17                 pvs.add(Conventions.attributeNameToPropertyName(propertyName),propertyValue);
18             }
19         }
20         return definition;
21     }

这里就是将bean的属性以键值对的形式存入MutablePropertyValues中,key=属性名,value=属性值。

通过对bean标签属性的循环遍历,就将属性值封装到BeanDefinitionHolder中了。

总的来说BeanDefinitionParserDelegate类,主要对bean标签的相关属性进行解析。

2.DefaultListableBeanFactory

在实例化bean对象时,用的是DefaultListableBeanFactory的preInstantiateSingletons方法:

 1 public void preInstantiateSingletons() throws BeansException {
 2         if (this.logger.isDebugEnabled()) {
 3             this.logger.debug("Pre-instantiating singletons in " + this);
 4         }
 5 
 6         // Iterate over a copy to allow for init methods which in turn register new bean definitions.
 7         // While this may not be part of the regular factory bootstrap,it does otherwise work fine.
 8         List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
 9 
10         // Trigger initialization of all non-lazy singleton beans...
11         for (String beanName : beanNames) {
12             RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
13             if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
14                 if (isFactoryBean(beanName)) {
15                     Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
16                     if (bean instanceof FactoryBean) {
17                         final FactoryBean<?> factory = (FactoryBean<?>) bean;
18                         boolean isEagerInit;
19                         if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
20                             isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
21                                             ((SmartFactoryBean<?>) factory)::isEagerInit,22                                     getAccessControlContext());
23                         }
24                         else {
25                             isEagerInit = (factory instanceof SmartFactoryBean &&
26                                     ((SmartFactoryBean<?>) factory).isEagerInit());
27                         }
28                         if (isEagerInit) {
29                             getBean(beanName);
30                         }
31                     }
32                 }
33                 else {
34                     System.out.println("在DefaultListableBeanFactory#preInstantiateSingletons中实现bean的初始化,会调用AbstractBeanFactory的getBean方法");
35                     getBean(beanName);
36                 }
37             }
38         }
39 
40         // Trigger post-initialization callback for all applicable beans...
41         for (String beanName : beanNames) {
42             Object singletonInstance = getSingleton(beanName);
43             if (singletonInstance instanceof SmartInitializingSingleton) {
44                 final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
45                 if (System.getSecurityManager() != null) {
46                     AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
47                         smartSingleton.afterSingletonsInstantiated();
48                         return null;
49                     },getAccessControlContext());
50                 }
51                 else {
52                     smartSingleton.afterSingletonsInstantiated();
53                 }
54             }
55         }
56     }

在此方法中,注意第12行RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);该方法的作用是将BeanDefinition进行转换,在bean加载时,实例化出来的是GenericBeanDefinition,而spring在实例化bean时需要的是RootBeanDefinition,因此getMergedLocalBeanDefinition方法的作用就是将非RootBeanDefinition转化为RootBeanDefinition以便后续使用。

3.AbstractBeanFactory

在实例化bean的时候,最终会落入doGetBean方法中:

  1 protected <T> T doGetBean(final String name,@Nullable final Class<T> requiredType,  2             @Nullable final Object[] args,boolean typeCheckOnly) throws BeansException {
  3 
  4         System.out.println("AbstractBeanFactory#doGetBean方法实例化Bean");
  5         final String beanName = transformedBeanName(name);
  6         Object bean;
  7 
  8         // Eagerly check singleton cache for manually registered singletons.
  9         Object sharedInstance = getSingleton(beanName);
 10         if (sharedInstance != null && args == null) {
 11             if (logger.isDebugEnabled()) {
 12                 if (isSingletonCurrentlyInCreation(beanName)) {
 13                     logger.debug("Returning eagerly cached instance of singleton bean ‘" + beanName +
 14                             "‘ that is not fully initialized yet - a consequence of a circular reference");
 15                 }
 16                 else {
 17                     logger.debug("Returning cached instance of singleton bean ‘" + beanName + "‘");
 18                 }
 19             }
 20             bean = getObjectForBeanInstance(sharedInstance,name,beanName,null);
 21         }
 22 
 23         else {
 24             // Fail if we‘re already creating this bean instance:
 25             // We‘re assumably within a circular reference.
 26             if (isPrototypeCurrentlyInCreation(beanName)) {
 27                 throw new BeanCurrentlyInCreationException(beanName);
 28             }
 29 
 30             // Check if bean definition exists in this factory.
 31             BeanFactory parentBeanFactory = getParentBeanFactory();
 32             if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 33                 // Not found -> check parent.
 34                 String nameToLookup = originalBeanName(name);
 35                 if (parentBeanFactory instanceof AbstractBeanFactory) {
 36                     return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
 37                             nameToLookup,requiredType,args,typeCheckOnly);
 38                 }
 39                 else if (args != null) {
 40                     // Delegation to parent with explicit args.
 41                     return (T) parentBeanFactory.getBean(nameToLookup,args);
 42                 }
 43                 else {
 44                     // No args -> delegate to standard getBean method.
 45                     return parentBeanFactory.getBean(nameToLookup,requiredType);
 46                 }
 47             }
 48 
 49             if (!typeCheckOnly) {
 50                 markBeanAsCreated(beanName);
 51             }
 52 
 53             try {
 54                 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 55                 checkMergedBeanDefinition(mbd,args);
 56 
 57                 // Guarantee initialization of beans that the current bean depends on.
 58                 String[] dependsOn = mbd.getDependsOn();
 59                 if (dependsOn != null) {
 60                     for (String dep : dependsOn) {
 61                         if (isDependent(beanName,dep)) {
 62                             throw new BeanCreationException(mbd.getResourceDescription(), 63                                     "Circular depends-on relationship between ‘" + beanName + "‘ and ‘" + dep + "‘");
 64                         }
 65                         registerDependentBean(dep,beanName);
 66                         try {
 67                             getBean(dep);
 68                         }
 69                         catch (NoSuchBeanDefinitionException ex) {
 70                             throw new BeanCreationException(mbd.getResourceDescription(), 71                                     "‘" + beanName + "‘ depends on missing bean ‘" + dep + "‘",ex);
 72                         }
 73                     }
 74                 }
 75 
 76                 // Create bean instance.
 77                 if (mbd.isSingleton()) {
 78                     sharedInstance = getSingleton(beanName,() -> {
 79                         try {
 80                             return createBean(beanName,mbd,args);
 81                         }
 82                         catch (BeansException ex) {
 83                             // Explicitly remove instance from singleton cache: It might have been put there
 84                             // eagerly by the creation process,to allow for circular reference resolution.
 85                             // Also remove any beans that received a temporary reference to the bean.
 86                             destroySingleton(beanName);
 87                             throw ex;
 88                         }
 89                     });
 90                     bean = getObjectForBeanInstance(sharedInstance,mbd);
 91                 }
 92 
 93                 else if (mbd.isPrototype()) {
 94                     // It‘s a prototype -> create a new instance.
 95                     Object prototypeInstance = null;
 96                     try {
 97                         beforePrototypeCreation(beanName);
 98                         prototypeInstance = createBean(beanName,args);
 99                     }
100                     finally {
101                         afterPrototypeCreation(beanName);
102                     }
103                     bean = getObjectForBeanInstance(prototypeInstance,mbd);
104                 }
105 
106                 else {
107                     String scopeName = mbd.getScope();
108                     final Scope scope = this.scopes.get(scopeName);
109                     if (scope == null) {
110                         throw new IllegalStateException("No Scope registered for scope name ‘" + scopeName + "‘");
111                     }
112                     try {
113                         Object scopedInstance = scope.get(beanName,() -> {
114                             beforePrototypeCreation(beanName);
115                             try {
116                                 return createBean(beanName,args);
117                             }
118                             finally {
119                                 afterPrototypeCreation(beanName);
120                             }
121                         });
122                         bean = getObjectForBeanInstance(scopedInstance,mbd);
123                     }
124                     catch (IllegalStateException ex) {
125                         throw new BeanCreationException(beanName,126                                 "Scope ‘" + scopeName + "‘ is not active for the current thread; consider " +
127                                 "defining a scoped proxy for this bean if you intend to refer to it from a singleton",128                                 ex);
129                     }
130                 }
131             }
132             catch (BeansException ex) {
133                 cleanupAfterBeanCreationFailure(beanName);
134                 throw ex;
135             }
136         }
137 
138         // Check if required type matches the type of the actual bean instance.
139         if (requiredType != null && !requiredType.isInstance(bean)) {
140             try {
141                 T convertedBean = getTypeConverter().convertIfNecessary(bean,requiredType);
142                 if (convertedBean == null) {
143                     throw new BeanNotOfRequiredTypeException(name,bean.getClass());
144                 }
145                 return convertedBean;
146             }
147             catch (TypeMismatchException ex) {
148                 if (logger.isDebugEnabled()) {
149                     logger.debug("Failed to convert bean ‘" + name + "‘ to required type ‘" +
150                             ClassUtils.getQualifiedName(requiredType) + "‘",ex);
151                 }
152                 throw new BeanNotOfRequiredTypeException(name,bean.getClass());
153             }
154         }
155         return (T) bean;
156     }

分析:

①9-21行:检查本地单例缓存中是否已经加载过bean,如果没有的话再检查earlySingletonObjects是否已经加载过该bean。

②26-51行:执行一些校验工作,bean是否为prototype(如果为prototype会抛出异常)、是否为抽象、将bean打上created标记。

③58-74行:检查bean的depends-on属性,保证depends-on依赖的bean会优先于当前bean被加载。

④77-91行、93-104行、106-136行:对bean的不同类型进行判断,然后走不同的分支进行bean的创建,我们关注77-91行。

4.AbstractAutowireCapableBeanFactory

这里我们关注创建bean的方法,createBeanInstance:

 1 protected BeanWrapper createBeanInstance(String beanName,RootBeanDefinition mbd,@Nullable Object[] args) {
 2         // Make sure bean class is actually resolved at this point.
 3         Class<?> beanClass = resolveBeanClass(mbd,beanName);
 4 
 5         if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
 6             throw new BeanCreationException(mbd.getResourceDescription(), 7                     "Bean class isn‘t public,and non-public access not allowed: " + beanClass.getName());
 8         }
 9 
10         Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
11         if (instanceSupplier != null) {
12             return obtainFromSupplier(instanceSupplier,beanName);
13         }
14 
15         if (mbd.getFactoryMethodName() != null)  {
16             return instantiateUsingFactoryMethod(beanName,args);
17         }
18 
19         // Shortcut when re-creating the same bean...
20         boolean resolved = false;
21         boolean autowireNecessary = false;
22         if (args == null) {
23             synchronized (mbd.constructorArgumentLock) {
24                 if (mbd.resolvedConstructorOrFactoryMethod != null) {
25                     resolved = true;
26                     autowireNecessary = mbd.constructorArgumentsResolved;
27                 }
28             }
29         }
30         if (resolved) {
31             if (autowireNecessary) {
32                 return autowireConstructor(beanName,null,null);
33             }
34             else {
35                 return instantiateBean(beanName,mbd);
36             }
37         }
38 
39         // Need to determine the constructor...
40         Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass,beanName);
41         if (ctors != null ||
42                 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
43                 mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
44             return autowireConstructor(beanName,ctors,args);
45         }
46 
47         // No special handling: simply use no-arg constructor.
48         return instantiateBean(beanName,mbd);
49     }

分析:

该函数前面都是进行一些判断,是否已经存在,是否由父类方法去创建等,这里我们主要关注40-48行。

这里会判断该bean是否使用构造函数进行属性的注入,如果是执行44行,否则执行48行。这里转到48行方法中去:

 1 protected BeanWrapper instantiateBean(final String beanName,final RootBeanDefinition mbd) {
 2         try {
 3             Object beanInstance;
 4             final BeanFactory parent = this;
 5             if (System.getSecurityManager() != null) {
 6                 beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
 7                         getInstantiationStrategy().instantiate(mbd,parent), 8                         getAccessControlContext());
 9             }
10             else {
11                 beanInstance = getInstantiationStrategy().instantiate(mbd,parent);
12             }
13             BeanWrapper bw = new BeanWrapperImpl(beanInstance);
14             initBeanWrapper(bw);
15             return bw;
16         }
17         catch (Throwable ex) {
18             throw new BeanCreationException(
19                     mbd.getResourceDescription(),"Instantiation of bean failed",ex);
20         }
21     }

代码转到11行:

 1 public Object instantiate(RootBeanDefinition bd,@Nullable String beanName,BeanFactory owner) {
 2         // Don‘t override the class with CGLIB if no overrides.
 3         if (!bd.hasMethodOverrides()) {
 4             Constructor<?> constructorToUse;
 5             synchronized (bd.constructorArgumentLock) {
 6                 constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
 7                 if (constructorToUse == null) {
 8                     final Class<?> clazz = bd.getBeanClass();
 9                     if (clazz.isInterface()) {
10                         throw new BeanInstantiationException(clazz,"Specified class is an interface");
11                     }
12                     try {
13                         if (System.getSecurityManager() != null) {
14                             constructorToUse = AccessController.doPrivileged(
15                                     (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
16                         }
17                         else {
18                             constructorToUse = clazz.getDeclaredConstructor();
19                         }
20                         bd.resolvedConstructorOrFactoryMethod = constructorToUse;
21                     }
22                     catch (Throwable ex) {
23                         throw new BeanInstantiationException(clazz,"No default constructor found",ex);
24                     }
25                 }
26             }
27             return BeanUtils.instantiateClass(constructorToUse);
28         }
29         else {
30             // Must generate CGLIB subclass.
31             return instantiateWithMethodInjection(bd,owner);
32         }
33     }

分析:

这里主要判断使用哪个构造函数进行实例化bean,并且如果方法被覆盖则会采用CGLB来实例化bean,第9行,如果实例化一个接口会抛出异常。

这里直接转到27行:

 1 public static <T> T instantiateClass(Constructor<T> ctor,Object... args) throws BeanInstantiationException {
 2         Assert.notNull(ctor,"Constructor must not be null");
 3         try {
 4             ReflectionUtils.makeAccessible(ctor);
 5             /**
 6              * 这里通过反射实例化类
 7              */
 8             System.out.println("通过BeanUtils#instantiateClass反射生成bean");
 9             System.out.println("最终通过Constructor#newInstance方法生成bean");
10 //            Object object= ctor.newInstance(args); 该句代码多余,下面又用到了
11             return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
12                     KotlinDelegate.instantiateClass(ctor,args) : ctor.newInstance(args));
13         }
14         catch (InstantiationException ex) {
15             throw new BeanInstantiationException(ctor,"Is it an abstract class?",ex);
16         }
17         catch (IllegalAccessException ex) {
18             throw new BeanInstantiationException(ctor,"Is the constructor accessible?",ex);
19         }
20         catch (IllegalArgumentException ex) {
21             throw new BeanInstantiationException(ctor,"Illegal arguments for constructor",ex);
22         }
23         catch (InvocationTargetException ex) {
24             throw new BeanInstantiationException(ctor,"Constructor threw exception",ex.getTargetException());
25         }
26     }

最终来到了通过翻身生成bean实例,前几篇文章也有提到。注意第4行makeAccessible,表示即使bean的构造函数是private或者protected,都不会影响bean的构造。


by Shawn Chen,2018.12.25日,晚。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读