属性注入中,我们做的工作是:
利用IoC思想,采取属性注入。
1 为属性添加一个set方法
2 在xml文件中配置Bean
我们把调用类对某一接口实现类的依赖关系由第三方注入,以移除调用类对某一实现类的依赖。spring就是那个第三方,确切来说,第三方是spring IoC容器。它会根据我们的xml文件来实现注入的吧?
什么是 IoC容器?
IoC容器相当于一个水桶,水桶最起码的功能就是装水。而我们的IoC容器最起码就是要能放置对象。
水桶起码要能装水,这是一个基本规范,而我们的IoC容器也有一个基本的功能规范,由BeanFactory接口提供了这么一个规范,定义了spring IoC的基本功能,所有其他IoC容器都要实现这个规范。
了解spring IoC容器的基本规范:BeanFactory
我们知道BeanFactory定义了IoC容器的基本功能规范,所以,下面我们就从BeanFactory这个最基本的容器定义来进入Spring的IoC容器体系,去了解IoC容器的实现原理。下面来看BeanFactory的源码
public interface BeanFactory {
/**
用户使用容器时,可以使用转义符“&”来得到FactoryBean本身
*/
String FACTORY_BEAN_PREFIX = "&";
/**
通过name获取bean
*/
Object getBean(String name) throws BeansException;
/**
*/
T getBean(String name, Class requiredType) throws BeansException;
/**
*/
Object getBean(String name, Object... args) throws BeansException;
/**
通过class类型获取bean
*/
T getBean(Class requiredType) throws BeansException;
/**
通过Class类型
*/
T getBean(Class requiredType, Object... args) throws BeansException;
/**
不清楚emm
*/
ObjectProvider getBeanProvider(Class requiredType);
/**
*/
ObjectProvider getBeanProvider(ResolvableType requiredType);
/**
通过containsBean(String name)能让用户判断容器是否含有指定名字的Bean
*/
boolean containsBean(String name);
/**
判断指定名字的Bean是不是单例
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/**
判断指定名字的Bean是不是prototype
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/**
判断指定name的bean是不是特定的Class类型
*/
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
/**
判断指定name的bean是不是特定的Class类型
*/
boolean isTypeMatch(String name, Class> typeToMatch) throws NoSuchBeanDefinitionException;
/**
获取bean的class类型
*/
@Nullable
Class> getType(String name) throws NoSuchBeanDefinitionException;
/**
获取名为name的bean的所有别名
*/
String[] getAliases(String name);
}
这些定义的接口方法勾画出了IoC容器的基本特性,因为BeanFactory接口定义了IoC容器。
定义一个普通的java对象
public class MyTestBean {
private String testStr = "testStr";
public String getTestStr() {
return testStr;
}
public void setTestStr(String testStr) {
this.testStr = testStr;
}
}
配置xml文件:
读取(重点来了)
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class BeanFactoryTest {
@Test
public void testSimpleLoad() {
/*
XmlBeanFactory继承自DefaultListableBeanFactory,在其基础上增加了XMl读取器XmlBeanDefinitionReader(这是个接口吧)
DefaultListableBeanFactory继承了AbstractAutowireCapableBeanFactory并实现了ConfigurableListableBeanFactory以及BeanDefinitionRegistry接口
*/
//这里使用了XmlBeanFactory来获取容器,然后使用容器的getBean方法获得容器的对象
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("analysis2.xml"));
MyTestBean myTestBean = (MyTestBean)beanFactory.getBean("myTestBean");
System.out.println(myTestBean.getTestStr());
System.out.println();
}
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.io.Resource;
/**
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @since 15 April 2001
* 2001年就已经出现啦
*/
@Deprecated
@SuppressWarnings({"serial", "all"})
//继承自DefaultListableBeanFactory
public class XmlBeanFactory extends DefaultListableBeanFactory {
//初始化一个XmlBeanDefinitionReader对象,有了这个Reader对象,那些以XML的方式定义的 BeanDefinition就有了处理的地方。
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
/**
* 提供了两个构造方法
*/
public XmlBeanFactory(Resource resource) throws BeansException {
//调用XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)这个构造方法
this(resource, null);
}
/**
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//我们可以看到,对这些XML形式的信息的处理实际上是由这个XmlBeanDefini-tionReader来完成的。
this.reader.loadBeanDefinitions(resource);
}
}
构造XmlBeanFactory这个IoC容器时,需要指定BeanDefinition的信息来源,而这个信息来源需要封装成Spring中的Resource类来给出。Resource是Spring用来封装IO操作的类。比如,我们的BeanDefinition信息是以xml文件形式存在的,那么可以使用像ClassPathResource res = new ClassPathResource(“beans.xml”);这样具体的ClassPathResource来构造需要的Resource,然后作为构造参数传递给XmlBeanFactory构造函数。这样,IoC容器就可以方便地定位到需要的BeanDefinition信息来对Bean完成容器的初始化和依赖注入过程。
说起来上面都是说的如何构造容器,那容器里装的水(bean)又如何装进去?或者说定义?
答案是使用BeanDefinition
什么是BeanDefinition?
在这些Spring提供的基本IoC容器的接口定义和实现的基础上,Spring通过定义BeanDefinition来管理基于Spring的应用中的各种对象以及它们之间的相互依赖关系。BeanDefinition抽象了我们对Bean的定义,是让容器起作用的主要数据类型。我们都知道,在计算机的世界里,所有的功能都是建立在用数据对现实进行抽象的基础上完成的。IoC容器是用来管理对象依赖关系的,对IoC容器来说,BeanDefinition就是对依赖反转模式中管理的对象依赖关系的数据抽象,也是容器实现依赖反转功能的核心数据结构,依赖反转功能都是围绕对这个BeanDefinition的处理上完成的。这些BeanDefinition就像是容器里装的水,有了这些基本数据,容器才能够发挥作用。
XmlBeanDefinitionReader 做了什么?