IOC实现之BeanFactory体系结构(一)

来源:互联网 发布:java iterator next 编辑:程序博客网 时间:2024/06/07 02:24

我们通过讲Spring的容器是怎样启动的,它在启动过程中做了些什么,以此来引发我们IOC原理的解析,在这里我们直接使用编程式的方式来启动容器,而不会涉及到SpringMVC,如果你担心你大多数时候是SpringMVC与Spring一起使用的,看这文章没有用,请放心,在后面解析SpringMVC的时候,你会发现,无论怎么变化,无非是启动容器的触发代码位置不同而已,这里是我们直接写代码,而SpringMVC会通过对Servlet的上下文监听而启动容器...


我们先来写一个例子,这个例子注重点在于讲清楚以下几点,你可以记下这个例子,后面的一系列解析过程都是围绕着它展开的喔!

1:编程式容器的启动;

2:资源文件的定位与加载;

3:资源文件的解析;

4:Bean的生成与注册;

5:依赖注入的全过程;

/**短裤*/public class Pants {private String color;//演示构造器注入过程public Pants( String color ) {this.color = color;}@Overridepublic String toString() {return "Pants [color=" + color + "]";}}
/**人类*/public class Person {//演示引用依赖注入过程private Pants pants;private String name ;private int age;//演示集合注入过程,其它几种就不用演示了,原理一样,可举一反三private List<String> girls;public Pants getPants() {return pants;}public void setPants(Pants pants) {this.pants = pants;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public List<String> getGirls() {return girls;}public void setGirls(List<String> girls) {this.girls = girls;}@Overridepublic String toString() {return "Person [pants=" + pants + ", name=" + name + ", age=" + age+ ", girls=" + girls + "]";}}

在src/main/resources下放入以下资源文件:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd" default-lazy-init="true"><bean id="pants" class="com.fyrj.compoment.spring.test.ioc.Pants"><constructor-arg index="0" name="color" value="黄色"/></bean><bean id="person" class="com.fyrj.compoment.spring.test.ioc.Person"><property name="pants" ref="pants"/><property name="name" value="张三丰"/><property name="age" value="18"/><property name="girls"><list><value>景甜</value><value>刘亦菲</value><value>克拉拉</value></list></property></bean></beans>


OK,就这两个类以及资源文件,接下来就正式开始原理解析了,你可以将源码准备好,然后跟着我一步步进行调试,进入Spring作者的思维之中,我相信,看完整个Spring系列文章,对你的帮助肯定是会有的!


我们先来看一段代码:

public class TestSpringIOC {public static void main(String[] args) {DefaultListableBeanFactory factory = new DefaultListableBeanFactory();XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);Resource resource = new ClassPathResource("testSpringIOC.xml");reader.loadBeanDefinitions(resource);Person person = factory.getBean(Person.class);System.out.println(person);//上面的4行代码相当于下面的1行代码ApplicationContext context = new ClassPathXmlApplicationContext("testSpringIOC.xml");Person newPerson = context.getBean(Person.class);System.out.println(newPerson);}}


输出:******************************************************************************

Person [pants=Pants [color=黄色], name=张三丰, age=18, girls=[景甜, 刘亦菲, 克拉拉]]
Person [pants=Pants [color=黄色], name=张三丰, age=18, girls=[景甜, 刘亦菲, 克拉拉]]

*************************************************************************************

我们知道,我们的Bean都是由Spring来进行管理的,包括Bean的创建与依赖关系的管理,那么管理它的容器是什么呢?就是BeanFactory类,如果把Bean比作水滴,那么BeanFactory类就相当于一个桶子,它装载着大量的Bean;

我们来看看代码,上面首先声明了一个DefaultListableBeanFactory,它就是一个BeanFactory,接下来是XmlBeanDefinitionReader,见名知意,这是通过XML文件来读取BeanDefinition的类,(BeanDefinition是Spring对Bean的抽象描述类,这个类中维护折后期实例化一个Bean时所有的配置,包括我们在XML中声明的构造参数,方法参数等等...)而后声明了Resource,这是Spring对资源文件的抽象,最后调用XML读取器来载入bean定义;关于这些类的详细描述,后面解析,这里只需要有个印象即可;


由此我们看到,bean的创建过程大致是这样的,首先我们在XML中声明对POJO的配置,而后通过Resource接口转换为Spring的资源类,再通过bean读取器对XML内容进行读取,它将读取到的各种配置转换解析为BeanDefintion类,而转换后的类放入哪里,当然是它持有的引用DefaultListableBeanFactory之中; 实际上,Spring已经帮我们封装好了这一切,通过下面那一行代码,就可以完成;


说到这里,是时候来了解下Spring中BeanFactory的体系结构了;


看不清楚的话放大看吧,我们看到,BeanFactory的类关系有大量的类,还有些我没有画出来,那些我们先不去关心,通过图我们发现,Spring的Bean工厂大概沿着3条主线走,首先是最终实现类为DefaultListableBeanFactory的基础实现,而后是以上下文形式存在的的ApplicationContext的实现,而上下文又分为普通环境上下文以及WEB环境上下文,普通环境上下文以FileSystemXmlApplicationContext以及ClassPathXmlApplicationContext类来进行实现,通过名字就能知道,一个是通过从本地文件系统中读取XML配置来形成上下文另一个是通过扫描类路径中的XML配置来形成上下文环境;WEB环境是以XmlWebApplicationContext来实现的;这个类也是SpringMVC启动时构建的web上下文类,后面我们再做解析;


接下来,我们来看看BeanFactory接口的代码;

public interface BeanFactory {//通过名字获得一个BeanObject getBean(String name) throws BeansException;//通过名字与类型类获得一个Bean<T> T getBean(String name, Class<T> requiredType) throws BeansException;<T> T getBean(Class<T> requiredType) throws BeansException;//通过Bean名称与创建参数来获得一个BeanObject getBean(String name, Object... args) throws BeansException;<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;//是否包含某个Beanboolean containsBean(String name);//是否是一个共享Bean,这取决于我们的配置boolean isSingleton(String name) throws NoSuchBeanDefinitionException;//是否是一个原型Beanboolean isPrototype(String name) throws NoSuchBeanDefinitionException;}

这些方法我们经常用到,就不多说了,接下来是它的子接口AutowireCapableBeanFactory,这是一个支持通过注解来发现与注册Bean的bean工厂,然后是ListableBeanFacrory接口,这是用来管理bean的依赖关系图的接口,然后是ConfigurableListableBeanFactory,这是用来对Bean工厂做额外配置的接口,最后它的最终实现类是DefaultListableBeanFactory,这是Spring中提供的一个成熟的Bean工厂,通过它的类关系我们知道它能做到管理bean的依赖关系,配置bean,根据注解生成bean等等功能...


如果我们使用DefaultListableBeanFactory来完成对Bean的管理,那么就像先前的代码一样,它需要借助于其它的类来加载资源,解析载入资源等等...这些都需要我们手动来完成,而ApplicationContext则不同,它虽然也要这样做但它已经帮我们将这些步骤封装好了,至于它的内部具体是怎么工作的,是怎么将XML描述转换为BeanDefinition的...这就是我们接下来要做的事情了!






0 0
原创粉丝点击