Java Spring IOC 框架原理解析
在 Spring的某個版本之後,它就放棄了直接使用XmlBeanFactory .現在面向的企業級IOC運用都是ApplicationContext結尾的容器,比如ClassPathXmlApplicationContext,XmlWebApplicationContext,GenericApplicationContext等。
但實際上這些類繁瑣負載,並且增加了平常開發中不必須要的東西。實際上一般還是用XmlBeanFactory這種簡潔方式。
ClassPathResource resource=new ClassPathResource("Beans.xml"); BeanFactory context=new DefaultListableBeanFactory(); BeanDefinitionReader bdr=new XmlBeanDefinitionReader((BeanDefinitionRegistry) context); bdr.loadBeanDefinitions(resource);
Student student = (Student) context.getBean("student"); System.out.println(student.toString());
XmlBeaenDefinitionReader利用beanfactory 來載入裝配Bean以及Bean例項化類以及屬性值等等。
XmlBeaenDefinitionReader呼叫loadBeanDefinitions整個過程解析了Beans.XML整個配置檔案裡的所有配置的東西。
通過BeanName,GenericBeanDefinition的Map形式儲存。
當通過 context.getBean("student");去獲取類例項的時候,他首先會去beanMapDefinition裡面獲取beanname 對應的genericbeandefinition然後轉換成rootbeandefinition 。
下面的執行過程是:
createbean->docreate->createBeanInstance->populateBean->applyPropertyValues 最後返回相對應的bean例項。
篩選類屬性核心程式碼:
private CachedIntrospectionResults(Class<?> beanClass) throws BeansException { try { if (logger.isTraceEnabled()) { logger.trace("Getting BeanInfo for class [" + beanClass.getName() + "]"); }
BeanInfo beanInfo = null; for (BeanInfoFactory beanInfoFactory : beanInfoFactories) { beanInfo = beanInfoFactory.getBeanInfo(beanClass); if (beanInfo != null) { break; } } if (beanInfo == null) { // If none of the factories supported the class, fall back to the default beanInfo = (shouldIntrospectorIgnoreBeaninfoClasses ? Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) : Introspector.getBeanInfo(beanClass)); } this.beanInfo = beanInfo;
if (logger.isTraceEnabled()) { logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]"); } this.propertyDescriptorCache = new LinkedHashMap<>();
// This call is slow so we do it once. PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors(); for (PropertyDescriptor pd : pds) { if (Class.class == beanClass && ("classLoader".equals(pd.getName()) || "protectionDomain".equals(pd.getName()))) { // Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those continue; } if (logger.isTraceEnabled()) { logger.trace("Found bean property '" + pd.getName() + "'" + (pd.getPropertyType() != null ? " of type [" + pd.getPropertyType().getName() + "]" : "") + (pd.getPropertyEditorClass() != null ? "; editor [" + pd.getPropertyEditorClass().getName() + "]" : "")); } pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd); this.propertyDescriptorCache.put(pd.getName(), pd); }
// Explicitly check implemented interfaces for setter/getter methods as well, // in particular for Java 8 default methods... Class<?> clazz = beanClass; while (clazz != null) { Class<?>[] ifcs = clazz.getInterfaces(); for (Class<?> ifc : ifcs) { BeanInfo ifcInfo = Introspector.getBeanInfo(ifc, Introspector.IGNORE_ALL_BEANINFO); PropertyDescriptor[] ifcPds = ifcInfo.getPropertyDescriptors(); for (PropertyDescriptor pd : ifcPds) { if (!this.propertyDescriptorCache.containsKey(pd.getName())) { pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd); this.propertyDescriptorCache.put(pd.getName(), pd); } } } clazz = clazz.getSuperclass(); }
this.typeDescriptorCache = new ConcurrentReferenceHashMap<>(); } catch (IntrospectionException ex) { throw new FatalBeanException("Failed to obtain BeanInfo for class [" + beanClass.getName() + "]", ex); } }