BeanFactory是个Factory,也就是 IOC 容器或对象工厂,所有的 Bean 都是由 BeanFactory( 也就是 IOC 容器 ) 来进行管理。
FactoryBean是一个能生产或者修饰生成对象的工厂Bean,可以在IOC容器中被管理,所以它并不是一个简单的Bean。当使用容器中factory bean的时候,该容器不会返回factory bean本身,而是返回其生成的对象。
以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。写的不错
http://www.cnblogs.com/ITtangtang/p/3978349.html
//根据Xml配置文件创建Resource资源对象,该对象中包含了BeanDefinition的信息 ClassPathResource resource =new ClassPathResource("application-context.xml"); //创建DefaultListableBeanFactory DefaultListableBeanFactory factory =new DefaultListableBeanFactory(); //创建XmlBeanDefinitionReader读取器,用于载入BeanDefinition。之所以需要BeanFactory作为参数,是因为会将读取的信息回调配置给factory XmlBeanDefinitionReader reader =new XmlBeanDefinitionReader(factory); //XmlBeanDefinitionReader执行载入BeanDefinition的方法,最后会完成Bean的载入和注册。完成后Bean就成功的放置到IOC容器当中,以后我们就可以从中取得Bean来使用 reader.loadBeanDefinitions(resource);
前一段时候我把Spring技术内幕的关于IOC原理一章看完,感觉代码太多,不好掌握,我特意又各方搜集了一些关于IOC原理的资料,特加深一下印象,以便真正掌握IOC的原理。 IOC的思想是:Spring容器来实现这些相互依赖对象的创建、协调工作。对象只需要关系业务逻辑本身就可以了。 SpringIOC容器的执行步骤是: 1、资源定位,即首先要找到applicationContext.xml文件 2、BeanDefinition的载入,把XML文件中的数据统一加载到BeanDefinition中,方便以后的处理 3、向IOC容器中注入BeanDefinition数据 4、将BeanDefinition中的数据进行依赖注入 IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。 举个现实生活中例子,现在有很多中介公司,例如我爱我家。我爱我家会有各种各样的房源资料,当我们找房子时我们只需把需要的房子告诉我爱我家,我爱我家会根据我们的需求给我们提供适合的房子。这样我们就不用自己去网上、小区广告等各个地方去搜集寻求适合自己的房子,整个过程由我爱我家中介来控制就行了,现在想想有个这个中介是不是使整个过程变得简单愉快了。当然,在实际生活中面对中介我们是需要交中介费的,好比SpringIOC我们也需要维护ApplicationContext这个配置文件,都是成本,面对Spring我们可以忽略成本,哈哈。 下面让我看看SpringIOC的运行过程: 1、首先加载ApplicationContext.xml,资源定位 首先资源定位最终是在Springframe下的AbstractBeanDefinitionReader类中的LoaderBeanDefinitions(String location,Set actualResources) line 98,下面举例说明:
? 1 2 3 4 5 6 <code class = "hljs cs" > public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext( "applicationContext.xml" ); User user= (User) context.getBean( "user" ); user.write(); }</code> ? 1 2 3 <code class = "hljs applescript" > <bean class = "com.jader.spring.Model.User" id= "user" > <property name= "name" value= "jader" > </property></bean></code> ? 1 2 3 4 5 6 7 8 9 <code class = "hljs cs" > public class User{ private String name; public void write() { System.out.println( "my name is:" +name); } public void setName(String name) { this .name = name; } }</code>运行程序会输出:my name is jader,很明显,SpringIOC已经把property里的value注入到User的name属性当中。 下面我们来分析Spring是怎么实现的 2、BeanDefinition的载入 载入和解析最终是在Springframework下的AbstractApplicationContext类的refresh()方法实现的,这个方法非常关键,里面包含了资源载入和解析,包括对lazy-init的额外处理等,line 445,下面举例说明: 首先我们定义一个Bean,用来存放Bean拥有的属性
? 1 2 3 4 5 6 <code class = "hljs lasso" > /* Bean Id */ private String id; /* Bean Class */ private String type; /* Bean Property */ private Map<string, object= "" > properties = new HashMap<string, object= "" >();</string,></string,></code>接下来Spring 就开始加载我们的配置文件了,将我们配置的信息保存在一个HashMap中,HashMap的key就是Bean 的 Id ,HasMap 的value是这个Bean,只有这样我们才能通过context.getBean(“user”)这个方法获得Animal这个类。我们都知道Spirng可以注入基本类型,而且可以注入像List,Map这样的类型,接下来就让我们以Map为例看看Spring是怎么保存的
? 1 2 3 4 5 6 7 8 9 10 11 <code class = "hljs xml" > <bean class = "BeanMap" id= "beanMap" > <property name= "myBeanMap" ><map> <entry key= "name" > <value>jader</value> </entry> <entry key= "age" > <value> 26 </value> </entry></map> </property> </bean></code>3、向IOC容器中注册BeanDefinition 注册最终是在Spring frame的DefaultListableBeanFactory类下的registerBeanDefinition(String beanName,BeanDefinition beanDefinition)方法中实现,line 664;下面举例说明:
? 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 <code class = "hljs avrasm" > if (beanProperty.element( "map" ) != null ) { Map<string, object= "" > propertiesMap = new HashMap<string, object= "" >(); Element propertiesListMap = (Element) beanProperty .elements().get( 0 ); Iterator<!--?--> propertiesIterator = propertiesListMap .elements().iterator(); while (propertiesIterator.hasNext()) { Element vet = (Element) propertiesIterator.next(); if (vet.getName().equals( "entry" )) { String key = vet.attributeValue( "key" ); Iterator<!--?--> valuesIterator = vet.elements() .iterator(); while (valuesIterator.hasNext()) { Element value = (Element) valuesIterator.next(); if (value.getName().equals( "value" )) { propertiesMap.put(key, value.getText()); } if (value.getName().equals( "ref" )) { propertiesMap.put(key, new String[] { value .attributeValue( "bean" ) }); } } } } bean.getProperties().put(name, propertiesMap); }</string,></string,></code>4、依赖注入 SpringIOC的最终依赖注入是是通过AbstractAutowireCapableBeanFactory的doCreateBean(finale String beanName,final RootBeanDefinition mbd,final Object[] args)方法(line 480)的,这个方法里的关键方法有populateBean()和createBeanInstance(),正在实现注入是通过BeanWrapperImpl extends AbstractPropertyAccessor类的setPropertyValue()方法实现 line 911 原理是:通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <code class = "hljs cs" > public static Object newInstance(String className) { Class<!--?--> cls = null ; Object obj = null ; try { cls = Class.forName(className); obj = cls.newInstance(); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } return obj; }</code> ? 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 <code class = "hljs cs" > public static void setProperty(Object obj, String name, String value) { Class<!--? extends Object--> clazz = obj.getClass(); try { String methodName = returnSetMthodName(name); Method[] ms = clazz.getMethods(); for (Method m : ms) { if (m.getName().equals(methodName)) { if (m.getParameterTypes().length == 1 ) { Class<!--?--> clazzParameterType = m.getParameterTypes()[ 0 ]; setFieldValue(clazzParameterType.getName(), value, m, obj); break ; } } } } catch (SecurityException e) { throw new RuntimeException(e); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } }</code>最后它将这个类的实例返回给我们,我们就可以用了。我们还是以Map为例看看它是怎么做的,我写的代码里面是创建一个HashMap并把该HashMap注入到需要注入的类中
? 1 2 3 4 5 6 7 8 9 10 11 12 13 <code class = "hljs javascript" > if (value instanceof Map) { Iterator<!--?--> entryIterator = ((Map<!--?, ?-->) value).entrySet() .iterator(); Map<string, object= "" > map = new HashMap<string, object= "" >(); while (entryIterator.hasNext()) { Entry<!--?, ?--> entryMap = (Entry<!--?, ?-->) entryIterator.next(); if (entryMap.getValue() instanceof String[]) { map.put((String) entryMap.getKey(), getBean(((String[]) entryMap.getValue())[ 0 ])); } } BeanProcesser.setProperty(obj, property, map); }</string,></string,></code>以上每一步的具体实现我都标注了类名、方法名和行数,大家可以自行查看Spring源码,这里不展示了。 面对Spring技术内幕的第一章介绍SpringIOC原理,难用理解,借助于这边文章可以帮我们理解一下。书读百遍,其义自现,当你读一遍不明白的时候可以反复阅读,这篇文章我都是从网上多方搜集的资料,在这里我表示感谢,希望我们共同进步。