Spring 模块的手写分析
Spring 源码阅读注意事项:try catch 和 do开头的方法 重点阅读
BeanFactory 基本的类体系结构。 四级接口继承体系:
BeanFactory 作为一个主接口不继承任何接口,暂且称为一级接口 获取 bean,是否包含bean,是否单例与原型,获取bean类型,bean别名 api 。
AutowireCapableBeanFactory提供工厂的装配功能 、HierarchicalBeanFactory提供父容器的访问功能 、ListableBeanFactory容器内 bean 实例的枚举功能 3个子接口继承它,进行功能上的增强,这3个子接口称为二级接口。
ConfigurableBeanFactory 称为三级接口,对二级接口 HierarchicalBeanFactory 进行了再次增强,还继承了一个外来的接口 SingletonBeanRegistry
ConfigurableListableBeanFactory 是一个更强大的接口,继承了上述所有的接口,四级接口解析,修改bean定义,并初始化单例
接口隔离原则。
抽象类和实现类
AbstractBeanFactory
作为一个抽象类,实现了三级接口 ConfigurableBeanFactory
AbstractAutowireCapableBeanFactory
同样是抽象类,继承自 AbstractBeanFactory
,并额外实现了二级接口 AutowireCapableBeanFactory
大部分功能。
DefaultListableBeanFactory
继承自 AbstractAutowireCapableBeanFactory
,实现了最强大的四级接口 ConfigurableListableBeanFactory
,并实现了一个外来接口 BeanDefinitionRegistry
,它并非抽象类。
最后是最强大的 XmlBeanFactory
,继承自 DefaultListableBeanFactory
,重写了一些功能,使自己更强大
为什么要定义这么多层次的接口? 每个接口都有适用场合,主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程,对对象的数据访问所做的限制。例如:ListableBeanFactory
接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean。AutowireCapableBeanFactory
接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为。
BeanFactory 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public interface BeanFactory { Object getBean (String name) throws BeansException ; <T> T getBean (String name, Class<T> requiredType) throws BeansException ; <T> T getBean (Class<T> requiredType) throws BeansException ; Object getBean (String name, Object... args) throws BeansException ; boolean containsBean (String name) ; boolean isSingleton (String name) throws NoSuchBeanDefinitionException ; boolean isPrototype (String name) throws NoSuchBeanDefinitionException ; boolean isTypeMatch (String name, Class<?> targetType) throws NoSuchBeanDefinitionException ; Class<?> getType(String name) throws NoSuchBeanDefinitionException; String[] getAliases(String name); }
BeanFactory 中只对 IOC 容器的基本行为作了定义,根本不关心 Bean 是如何定义怎样加载的,只关心工厂里得到什么产品对象,至于怎样生产这些对象,这个接口不关心。
ListableBeanFactory 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public interface ListableBeanFactory extends BeanFactory { boolean containsBeanDefinition (String beanName) ; int getBeanDefinitionCount () ; String[] getBeanDefinitionNames(); String[] getBeanNamesForType(Class<?> type);, String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit); <T> Map<String, T> getBeansOfType (Class<T> type) throws BeansException ; <T> Map<String, T> getBeansOfType (Class<T> type,) throws BeansException ; Map<String, Object> getBeansWithAnnotation (Class<? extends Annotation> annotationType) throws BeansException ; <A extends Annotation> A findAnnotationOnBean (String beanName, Class<A> annotationType) ; }
ListableBeanFactory 3个跟BeanDefinition 有关的总体操作,包括 BeanDefinition 的总数、名字的集合、指定类型的名字的集合。
BeanDefinition 是 Spring 中非常重要的一个类,每个 BeanDefinition 实例都包含一个类在 Spring 工厂中的所有属性。
两个 getBeanNamesForType 重载方法,根据指定类型(包括子类)获取其对应的所有 Bean 名字
两个 getBeansOfType 重载方法,根据类型(包括子类) 返回指定 Bean 名和 Bean 的Map
2个跟注解查找有关的方法,根据注解类型,查找 Bean 名和 Bean 的 Map,根据指定 Bean 名和注解类型查找指定 Bean
这个工厂的最大特点就是可以列出工厂可以生产的所有实例。工厂并不能直接生产,但是可以返回指定类型的所有实例。
HierarchicalBeanFactory 分层的Bean工厂
1 2 3 4 5 6 public interface HierarchicalBeanFactory extends BeanFactory { BeanFactory getParentBeanFactory () ; boolean containsLocalBean (String name) ; }
第一个方法返回 Bean 工厂的父工厂,这个方法实现了工厂的分级 第二个方法判断本地工厂是否包含这个 Bean(忽略其他所有父工厂)
AutowireCapableBeanFactory 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public interface AutowireCapableBeanFactory extends BeanFactory { int AUTOWIRE_NO = 0 ; int AUTOWIRE_BY_NAME = 1 ; int AUTOWIRE_BY_TYPE = 2 ; int AUTOWIRE_CONSTRUCTOR = 3 ; <T> T createBean (Class<T> beanClass) throws BeansException ; void autowireBean (Object existingBean) throws BeansException ; Object configureBean (Object existingBean, String beanName) throws BeansException ; Object createBean (Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException ; Object autowire (Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException ; void autowireBeanProperties (Object existingBean, int autowireMode, boolean dependencyCheck) throws BeansException ; void applyBeanPropertyValues (Object existingBean, String beanName) throws BeansException ; Object initializeBean (Object existingBean, String beanName) throws BeansException ; Object applyBeanPostProcessorsBeforeInitialization (Object existingBean, String beanName) throws BeansException ; Object applyBeanPostProcessorsAfterInitialization (Object existingBean, String beanName) throws BeansException ; void destroyBean (Object existingBean) ; <T> NamedBeanHolder<T> resolveNamedBean (Class<T> requiredType) throws BeansException ; @Nullable Object resolveDependency (DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException ; @Nullable Object resolveDependency (DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException ; }
5个静态不可变常量指明装配策略。8个跟自动装配有关的方法,2个执行 BeanPostProcessors 方法,2个分解指定依赖的方法。
根据定义 BeanDefinition 装配 Bean。执行前、后处理器等。
ConfigurableBeanFactory 复杂的配置Bean工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 public interface ConfigurableBeanFactory extends HierarchicalBeanFactory , SingletonBeanRegistry { String SCOPE_SINGLETON = "singleton" ; String SCOPE_PROTOTYPE = "prototype" ; void setParentBeanFactory (BeanFactory parentBeanFactory) throws IllegalStateException ; void setBeanClassLoader (@Nullable ClassLoader beanClassLoader) ; @Nullable ClassLoader getBeanClassLoader () ; void setTempClassLoader (@Nullable ClassLoader tempClassLoader) ; @Nullable ClassLoader getTempClassLoader () ; void setCacheBeanMetadata (boolean cacheBeanMetadata) ; boolean isCacheBeanMetadata () ; void setBeanExpressionResolver (@Nullable BeanExpressionResolver resolver) ; @Nullable BeanExpressionResolver getBeanExpressionResolver () ; void setConversionService (@Nullable ConversionService conversionService) ; @Nullable ConversionService getConversionService () ; void addPropertyEditorRegistrar (PropertyEditorRegistrar registrar) ; void registerCustomEditor (Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass) ; void copyRegisteredEditorsTo (PropertyEditorRegistry registry) ; void setTypeConverter (TypeConverter typeConverter) ; TypeConverter getTypeConverter () ; void addEmbeddedValueResolver (StringValueResolver valueResolver) ; boolean hasEmbeddedValueResolver () ; @Nullable String resolveEmbeddedValue (String value) ; void addBeanPostProcessor (BeanPostProcessor beanPostProcessor) ; int getBeanPostProcessorCount () ; void registerScope (String scopeName, Scope scope) ; String[] getRegisteredScopeNames(); @Nullable Scope getRegisteredScope (String scopeName) ; AccessControlContext getAccessControlContext () ; void copyConfigurationFrom (ConfigurableBeanFactory otherFactory) ; void registerAlias (String beanName, String alias) throws BeanDefinitionStoreException ; void resolveAliases (StringValueResolver valueResolver) ; BeanDefinition getMergedBeanDefinition (String beanName) throws NoSuchBeanDefinitionException ; boolean isFactoryBean (String name) throws NoSuchBeanDefinitionException ; void setCurrentlyInCreation (String beanName, boolean inCreation) ; boolean isCurrentlyInCreation (String beanName) ; void registerDependentBean (String beanName, String dependentBeanName) ; String[] getDependentBeans(String beanName); String[] getDependenciesForBean(String beanName); void destroyBean (String beanName, Object beanInstance) ; void destroyScopedBean (String beanName) ; void destroySingletons () ; }
ConfigurableListableBeanFactory BeanFactory的集大成者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public interface ConfigurableListableBeanFactory extends ListableBeanFactory , AutowireCapableBeanFactory , ConfigurableBeanFactory { void ignoreDependencyType (Class<?> type) ; void ignoreDependencyInterface (Class<?> ifc) ; void registerResolvableDependency (Class<?> dependencyType, @Nullable Object autowiredValue) ; boolean isAutowireCandidate (String beanName, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException ; BeanDefinition getBeanDefinition (String beanName) throws NoSuchBeanDefinitionException ; Iterator<String> getBeanNamesIterator () ; void clearMetadataCache () ; void freezeConfiguration () ; boolean isConfigurationFrozen () ; void preInstantiateSingletons () throws BeansException ; }
工厂接口 ConfigurableListableBeanFactory
同时继承了3个接口, ListableBeanFactory
、AutowireCapableBeanFactory
和 ConfigurableBeanFactory
,扩展之后,加上自有的这8个方法,这个工厂接口总共有83个方法,实在是巨大到不行了。这个工厂接口的自有方法总体上只是对父类接口功能的补 充,包含了 BeanFactory 体系目前的所有方法,可以说是接口的集大成者。
BeanDefinition
手写 IOC 框架思路
读取配置文件的 bean 信息
将 bean 信息封装到 BeanDefinition 集合对象中
根据传递过来的 beanName 参数去 BeanDefinition 集合中查找对应的 BeanDefinition 信息
根据 BeanDefinition 中的信息去创建 Bean 的实例。
a.根据 class 信息包括里面的 constructor-arg 通过反射进行实例化
b.根据 BeanDefinition 中封装的属性信息集合去挨个给对象赋值
c.根据 initMethod 方法区调用对象的初始化操作
如果 singletonObjects 中已经包含了我们要找的对象,就不需要再创建了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class BeanFactory { Map<String, BeanDefination> beanDefinations = new HashMap<>; Map<String, Object> singletonObjects = new HashMap<>(); BeanFactory() { } public static Object getBean (String name) { } }
实现
在阅读源码时,需要抓住主线,在手写框架时也一样,先写使用。再写实现
pom.xml中引入自己的框架
1 2 3 4 5 <dependency > <groupId > cn.lizhaoloveit</groupId > <artifactId > spring-framework-custom</artifactId > <version > 1.0</version > </dependency >
bean.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <beans > <bean id ="student" class ="cn.lizhaoloveit.spring.po.Student" init-method ="initMethod" > <property name ="name" value ="zengkeyan" > </property > <property name ="course" ref ="course" > </property > </bean > <bean id ="course" class ="cn.lizhaoloveit.spring.po.Course" init-method ="init" > <property name ="name" value ="spring" > </property > <property name ="age" value ="18" > </property > </bean > </beans >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class Student { private String name; private Course course; public void initMethod () { System.out.println("初始化方法" ); } public void destroyMethod () { System.out.println("销毁方法" ); } } public class Course { private String name; private Integer age; public void init () { System.out.println("我是对象初始化方法" ); } } @Test public void test () { String location = "classpath:beans.xml" ; BeanFactory beanFactory = new DefaultListableBeanFactory(location); Student student = beanFactory.getBeans(Student.class); Student student1 = (Student) beanFactory.getBeans("student" ); System.out.println(student); System.out.println(student1); } 我是对象初始化方法 初始化方法 初始化方法 Student(name=zengkeyan, course=Course(name=spring, age=18 )) Student(name=zengkeyan, course=Course(name=spring, age=18 ))
初始化工厂 beanFactory
根据源码分析,先定义顶层逻辑:
BeanFactory
1 2 3 4 public interface BeanFactory { Object getBeans (String beanName) ; <T> T getBeans (Class<T> clazz) ; }
根据分析,为了避免循环引用导致对象创建失败,我们需要先将xml中的文本中的信息封装在BeanDefinition类中。
1 2 3 4 5 6 7 8 9 10 11 12 13 public class BeanDefinition { private String beanName; private String beanClassName; private String initMethod; private List<PropertyValue> propertyValues = new ArrayList<>(); public BeanDefinition (String clzName, String beanName) { this .beanClassName = clzName; this .beanName = beanName; } public void addPropertyValue (PropertyValue propertyValue) { propertyValues.add(propertyValue); } }
抽象类:AbstractBeanFactory,完成其他实现方便扩展。拆分接口,使其可以有更多的功能拆分,结构更明确。
1 2 3 4 5 6 7 8 9 10 11 12 public abstract class AbstractBeanFactory implements BeanFactory { @Override public <T> T getBeans (Class<T> clazz) { return null ; } @Override public Object getBeans (String beanName) { return null ; } public abstract void registerBeanDefinition (String beanName, BeanDefinition beanDefinition) ; public abstract void registerBeanDefinitionClz (String simpleName, BeanDefinition beanDefinition) ; }
new DefaultListableBeanFactory(location);
根据 location 初始化beanFactory。
1 2 3 4 5 6 7 8 9 10 11 public DefaultListableBeanFactory (String location) { registResource(); registConverters(); Resource resource = getResource(location); XmlBeanDefinitionParser parser = new XmlBeanDefinitionParser(); parser.loadBeanDefinations(this , resource); }
Resource 接口用于根据不同的方式来获取资源
1 2 3 4 public interface Resource { boolean isCanRead (String location) ; InputStream getInputStream () ; }
实现类 ClassPathResource
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class ClassPathResource implements Resource { private String location; @Override public boolean isCanRead (String location) { if (location == null || "" .equals(location)) { return false ; } if (location.startsWith("classpath:" )) { this .location = location; return true ; } return false ; } @Override public InputStream getInputStream () { if (location == null || "" .equals(location)) return null ; String replace = location.replace("classpath:" , "" ); return this .getClass().getClassLoader().getResourceAsStream(replace); } }
将资源实现类,加入 DefaultListableBeanFactory 的资源列表,如果有更多途经,可以添加更多的类,本着对修改关闭,对扩展开放的开闭原则。
1 2 3 private void registResource () { resources.add(new ClassPathResource()); }
拿到资源流后,根据资源创建 BeanDefinitions,此时需要一个解析器,将xml中的内容解析为 BeanDefinition 对象。
1 2 3 4 5 6 7 8 9 public class XmlBeanDefinitionParser { public void loadBeanDefinations (DefaultListableBeanFactory beanFactory, Resource resource) { InputStream inputStream = resource.getInputStream(); Document document = DocumentReader.createDocument(inputStream); XmlBeanDefinitionDocumentReader reader = new XmlBeanDefinitionDocumentReader(beanFactory); reader.loadBeanDefinitions(document.getRootElement()); } }
在每一处有可能有扩展的地方,使用面向对象的思想,XmlBeanDefinitionDocumentReader
专门解析 Document。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 public class XmlBeanDefinitionDocumentReader { private DefaultListableBeanFactory beanFactory; public XmlBeanDefinitionDocumentReader (DefaultListableBeanFactory beanFactory) { this .beanFactory = beanFactory; } public void loadBeanDefinitions (Element rootElement) { List<Element> elements = rootElement.elements(); for (Element element : elements) { String name = element.getName(); if (name.equals("bean" )) { parseBeansElement(element); } else { parseCustomElement(element); } } } private void parseBeansElement (Element element) { if (element == null ) return ; try { String id = element.attributeValue("id" ); String name = element.attributeValue("name" ); String clzName = element.attributeValue("class" ); Class<?> clzType = Class.forName(clzName); String initMethod = element.attributeValue("init-method" ); String beanName = id == null ? name : id; beanName = beanName == null ? clzType.getSimpleName() : beanName; BeanDefinition beanDefinition = new BeanDefinition(clzName, beanName); beanDefinition.setInitMethod(initMethod); List<Element> propertyElements = element.elements(); for (Element propertyElement : propertyElements) { parsePropertyElement(beanDefinition, propertyElement); } registerBeanDefinition(beanName, beanDefinition); registerBeanDefinitionClass(clzType.getSimpleName(), beanDefinition); } catch (ClassNotFoundException e) { e.printStackTrace(); } } private void parsePropertyElement (BeanDefinition beanDefinition, Element propertyElement) { if (propertyElement == null ) return ; String name = propertyElement.attributeValue("name" ); String value = propertyElement.attributeValue("value" ); String ref = propertyElement.attributeValue("ref" ); if (value != null && !value.equals("" ) && ref != null && !ref.equals("" )) return ; PropertyValue propertyValue = null ; if (value != null && !value.equals("" )) { Class<?> classType = ReflectUtils.getTypeByFieldName(beanDefinition.getBeanClassName(), name); TypeStringValue typeStringValue = new TypeStringValue(value, classType); propertyValue = new PropertyValue(name, typeStringValue); beanDefinition.addPropertyValue(propertyValue); } else if (ref != null && !ref.equals("" )) { RuntimeBeanReference reference = new RuntimeBeanReference(ref); propertyValue = new PropertyValue(name, reference); beanDefinition.addPropertyValue(propertyValue); } else return ; } private void parseCustomElement (Element element) { } private void registerBeanDefinitionClass (String simpleName, BeanDefinition beanDefinition) { this .beanFactory.registerBeanDefinitionClz(simpleName, beanDefinition); } private void registerBeanDefinition (String beanName, BeanDefinition beanDefinition) { this .beanFactory.registerBeanDefinition(beanName, beanDefinition); } } ``` 解析的过程实际上就是把xml中的Bean标签中的内容填给 BeanDefinition 对象。 值得一说的是 `property` 标签的解析,因为 property 可能有引用类型和数值类型的值。因此在赋值时,需要将两种类型分别创建对象 ```java public class PropertyValue { private String name; private Object value; } public class TypeStringValue { private String value; private Class<?> classType; } public class RuntimeBeanReference { private String ref; }
以上,初始化的过程就完结了。
取值
取值的过程实际上就是把 BeanDefinition 中的信息通过反射创建对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 @Override public Object getBeans (String beanName) { Object instance = singletonObjects.get(beanName); if (instance != null ) return instance; BeanDefinition beanDefinition = getBeanDefinitionIds().get(beanName); String beanClassName = beanDefinition.getBeanClassName(); instance = createBeanInstance(beanClassName, null ); setProperty(instance, beanDefinition); initBean(instance, beanDefinition); singletonObjects.put(beanName, instance); return instance; } @Override public <T> T getBeans (Class<T> clazz) { String clazzSimpleName = clazz.getSimpleName(); T instance = (T) singletonObjects.get(clazzSimpleName); if (instance != null ) return instance; BeanDefinition beanDefinition = getBeanDefinitionClzs().get(clazzSimpleName); String beanClassName = beanDefinition.getBeanClassName(); instance = (T) createBeanInstance(beanClassName, null ); setProperty(instance, beanDefinition); initBean(instance, beanDefinition); singletonObjects.put(clazzSimpleName, instance); return instance; } private <T> void initBean (T instance, BeanDefinition beanDefinition) { String initMethod = beanDefinition.getInitMethod(); if (initMethod == null || initMethod.equals("" )) return ; ReflectUtils.invokeMethod(instance, initMethod, null ); } private <T> void setProperty (T instance, BeanDefinition beanDefinition) { List<PropertyValue> propertyValues = beanDefinition.getPropertyValues(); for (PropertyValue propertyValue : propertyValues) { String name = propertyValue.getName(); Object value = propertyValue.getValue(); Object trueValue = null ; if (value instanceof TypeStringValue) { TypeStringValue typeStringValue = (TypeStringValue) value; String stringValue = typeStringValue.getValue(); Class<?> clazz = typeStringValue.getClassType(); for (TypeConverter typeConverter : typeConverters) { if (typeConverter.isType(clazz)) { trueValue = typeConverter.convert(stringValue); } } } else if (value instanceof RuntimeBeanReference) { RuntimeBeanReference reference = (RuntimeBeanReference) value; String ref = reference.getRef(); trueValue = getBeans(ref); } ReflectUtils.setProperty(instance, name, trueValue); } } private Object createBeanInstance (String beanClassName, Object... args) { return ReflectUtils.createObject(beanClassName, args); } ``` 需要说明的是,在给属性 property 赋值时,如果值类型为数据类型,则需要进行类型转换,将字符串转换成对应的数据类型。这里就需要用到类型转换器,`TypeConverter` 的作用就是识别类型并且将字符串类型的数据转换为其他数据类型。 ```java public interface TypeConverter { boolean isType (Class<?> clazz) ; Object convert (String source) ; } public class IntegerTypeConverter implements TypeConverter { @Override public Integer convert (String source) { return Integer.parseInt(source); } @Override public boolean isType (Class<?> clazz) { return clazz == Integer.class; } } public class StringTypeConverter implements TypeConverter { @Override public boolean isType (Class<?> clazz) { return clazz == String.class; } @Override public String convert (String source) { return source; } }
以上代码还用到了两个工具类,将反射的操作进行了封装,封装了 dom4j 的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 public class DocumentReader { public static Document createDocument (InputStream inputStream) { Document document = null ; SAXReader reader = new SAXReader(); try { document = reader.read(inputStream); } catch (DocumentException e) { e.printStackTrace(); } return document; } } public class ReflectUtils { public static Object createObject (String beanClassName, Object... args) { try { Class<?> clazz = Class.forName(beanClassName); Constructor<?> constructor = clazz.getConstructor(); return constructor.newInstance(args); } catch (Exception e) { e.printStackTrace(); } return null ; } public static void setProperty (Object beanInstance, String name, Object value) { try { Class<?> clazz = beanInstance.getClass(); Field field = clazz.getDeclaredField(name); field.setAccessible(true ); field.set(beanInstance, value); } catch (Exception e) { e.printStackTrace(); } } public static Class<?> getTypeByFieldName(String beanClassName, String name) { try { Class<?> clazz = Class.forName(beanClassName); Field field = clazz.getDeclaredField(name); return field.getType(); } catch (Exception e) { e.printStackTrace(); } return null ; } public static void invokeMethod (Object beanInstance, String initMethod, Object... args) { try { Class<?> clazz = beanInstance.getClass(); Method method = clazz.getDeclaredMethod(initMethod); method.setAccessible(true ); method.invoke(beanInstance, args); } catch (Exception e) { e.printStackTrace(); } } }
至此就是想了 spring 中的 IOC 功能。
SpringIoc源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 @Override public void refresh () throws BeansException, IllegalStateException { synchronized (this .startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); initMessageSource(); initApplicationEventMulticaster(); onRefresh(); registerListeners(); finishBeanFactoryInitialization(beanFactory); finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
AbstractApplicationContext#refresh: 刷新 spring 容器(删除原有容器,创建新容器)
refresh 里面12个步骤,和IoC相关的是:step2 和 step11,在初始化时一次性创建所有单例
obtainFreshBeanFactory
refreshBeanFactory() 创建 BeanFactory 对象(DefaultListableBeanFactory) 加载 bean信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 protected final void refreshBeanFactory () throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this .beanFactoryMonitor) { this .beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
这里用到里模板方法,具体的加载方法在子类中实现。将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中。
从子类 AbstractRefreshableApplicationContext.java 开始就加载 beanDefinition。 XmlBeanDefinitionReader#loadBeanDefinitions:通过 resource 定位 xml 资源,进行加载读取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public int loadBeanDefinitions (EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null" ); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } Set<EncodedResource> currentResources = this .resourcesCurrentlyBeingLoaded.get(); if (currentResources == null ) { currentResources = new HashSet<>(4 ); this .resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!" ); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null ) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this .resourcesCurrentlyBeingLoaded.remove(); } } }
doLoadBeanDefinitions
方法做具体工作,之前的步骤在堆 resource 进行编码工作。然后调用了下面的方法
registerBeanDefinitions(document, resource)
DefaultBeanDefinitionDocumentReader#registerBeanDefinition 中 调用doRegisterBeanDefinitions注册。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 protected void doRegisterBeanDefinitions (Element root) { BeanDefinitionParserDelegate parent = this .delegate; this .delegate = createDelegate(getReaderContext(), root, parent); if (this .delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return ; } } } preProcessXml(root); parseBeanDefinitions(root, this .delegate); postProcessXml(root); this .delegate = parent; }
parseBeanDefinitions 从根标签开始解析。然后 parseDefaultElement 解析 bean 标签等默认子标签。
processBeanDefinition 解析Bean标签,初始化。还有其他子标签。分情况解析。
BeanDefinitionParserDelegate#parseBeanDefinitionElement 委托 BeanDefinitionParserDelegate 解析。创建 beanDefinition 信息。
循环依赖问题
Spring 中循环依赖的场景
构造器的循环依赖,无法解决,只能将其转变为setter的循环依赖。
解决方案:通过递归方法找出当前 Bean 所依赖的 Bean,然后提前缓存放入cache中,通过提前暴露,exposedObject
用于返回提前暴露的 bean。
Spring 先将 bean 对象实例化(依赖无参构造器),再设置对象属性。Spring 先用构造器实例化 Bean 对象,将实例化结束的对象放到一个 Map 中,并且 Spring 提供获取这个未设置属性的对象的引用方法。如果 A 对象 引用B 对象,会直接从 Map 中获取 B 对象。就不会出现循环问题了。
三级缓存分别指:
singletonFactories
earlySingletonObjects : 提前曝光的的单例对象的 Cache 用于检测循环引用,与 singletonFactories 互斥
singletonObject 单例对象的 Cache。
在创建 bean 的时候,首先想到的是从 cache 中获取这个单例的 bean,如果对象为空或者正在创建中,(如果A在创建中依赖了B,就得先创建B,A就在处于创建中状态),Spring 首先从一级缓存 singletonObjects 中获取,如果获取不到,并且对象正在创建,就再从二级缓存 earlySingletonObjects 中获取,如果还是取不到,则从 三级缓存 singletonFactory.getObject 获取,如果取到了,就将该对象从三级缓存中删除,移入二级缓存中
1 this .earlySingletonObjects.put(beanName, singletonObject); this .singletonFactories.remove(beanName);
创建对象三步:
实例化对象,将当前的 beanName 和 一个 ObjectFactory 存储到三级缓存中,ObjectFactory 中的工作就是将第一步创建的空对象提前暴露
填充属性,填充属性B 需要先创建 B 对象,创建B对象,又需要A对象的属性注入(A 对象不会重新创建,而是从一二三级缓存中去取A对象,此时A对象在三级缓存中)
初始化对象。
总结
ClassPathXmlApplicationContext:可能是 ClassPath 也可能是 Context AbstractApplicationContext AbstractRefreshableApplicationContext AbstractXmlApplicationContext : 可能是 Xml 也可能是注解,
不同的部分用不同的面向对象,相同的部分用共同对象,比如不管是从 Context 中还是 ClassPath 中创建 Context 创建时的部分是一样的。
AbstractBeanDefinitionReader XmlBeanDefinitionReader
DefaultBeanDefinitionReader
BeanDefinitionParserDelegate 具体解析 Bean 标签成 BeanDefinition 对象是由该对象完成。
为什么 XmlBeanDefinitionReader 要继承 AbstractBeanDefinitionReader?
因为 AbstractXmlApplicationContext 想找阅读器,肯定是找一个通用的阅读器。具体阅读功能的实现是根据不同的情况来由子类实现。