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

我们通过讲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;
	}
	@Override
	public 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;}
	@Override
	public 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.xsd
		http://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 {
	//通过名字获得一个Bean
	Object 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名称与创建参数来获得一个Bean
	Object getBean(String name, Object... args) throws BeansException;
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
	//是否包含某个Bean
	boolean containsBean(String name);
	//是否是一个共享Bean,这取决于我们的配置
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
	//是否是一个原型Bean
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
}

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


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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值