IOC容器之BeanFactory
1.什么是BeanFactory?
顾名思义,就是生产Bean的工厂。基础类型的IOC容器,可以提供完整的IOC服务支持。
是不是很难理解!!!打个比方BeanFactory就是生产汽车的工厂。你是不是从其他的汽车零件厂或者自己生产的零配件送到最后的组装线上啊!最后是不是在生产线的终点取得成品的汽车。类似的,你只要把所需的所有业务对象交给BeanFactroy,剩下的就是直接从BeanFactroy取得最终完成组装并且可以使用的对象。
2.有了BeanFactory的前后变化?
主要是对象之间依赖关系的解决方式改变了。
之前:系统业务对象需要什么样依赖的业务对象就自己去“拿”(想要什么自己去取)
有了之后:需要什么样的依赖让BeanFactory给送过来。
3.BeanFactory的对象注册与依赖注入绑定的方式有哪几种?
3.1 直接编码方式
public class BeanFactoryTest extends TestCase {
/**
* 直接编码方式
*/
public void testRedirectCode() {
DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
BeanFactory beanFactory = bindViaCode(beanRegistry);
Coder coder = (Coder) beanFactory.getBean("coder");
coder.getApp().say();
/**
* 输出为:
* //通过构造方法注入的情况
* 调用App无参构造
* 调用Coder有参构造,参数app为:App{says='App'}
* App.say():App
*
* //通过setter方式注入的情况下
* 调用Coder无参构造
* 调用App无参构造
* 调用Coder.setApp(), 参数app为: App{says='App'}
* App.say():App
*/
}
public static BeanFactory bindViaCode(BeanDefinitionRegistry registry){
AbstractBeanDefinition appBeanDefinition = new RootBeanDefinition(App.class);
AbstractBeanDefinition coderBeanDefinition = new RootBeanDefinition(Coder.class);
//将beanDefinition注册到容器中
registry.registerBeanDefinition("app", appBeanDefinition);
registry.registerBeanDefinition("coder", coderBeanDefinition);
//指定依赖关系
//1、可以通过构造方法注入
// ConstructorArgumentValues argumentValues = new ConstructorArgumentValues();
// argumentValues.addIndexedArgumentValue(0, appBeanDefinition);
// coderBeanDefinition.setConstructorArgumentValues(argumentValues);
//2、可以通过setter方法注入
MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
mutablePropertyValues.addPropertyValue("app", appBeanDefinition);
coderBeanDefinition.setPropertyValues(mutablePropertyValues);
//绑定完成
return (BeanFactory)registry;
}
}
3.2 外部配置文件方式
(i)XML文件格式
(ii)Properties文件格式
<?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:context="http://www.springframework.org/schema/context"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<bean id="app" class="com.me.sourcecode.bean.App"></bean>
<!--<bean id="coder" class="com.me.sourcecode.bean.Coder">-->
<!--<constructor-arg index="0">-->
<!--<ref bean="app" />-->
<!--</constructor-arg>-->
<!--</bean>-->
<bean id="coder" class="com.me.sourcecode.bean.Coder">
<property name="app" ref="app"></property>
</bean>
</beans>
3.3注解方式
4.BeanFactory的XML
4.1< beans >和< bean >
所有注册到容器的业务对象,在spring中统称为bean。
在XML中把这些< bean >的元素组织起来,就叫做 < beans >
< description >:在配置文件中指定一些描述性的信息。
< import >:加载主要配置文件时,用< import >元素对其所依赖的配置文件进行引用。
比如,如果A.xml中的< bean >可能依赖与B.xml中< bean >的某些定义,那么就可以在A.xml中使用< inport >将B.xml引入到A.xml< import resource=“B.xml”/ >
< alias>:通过< alias >为某些< bean >起一些“外号”,通常情况是为了减少输入。
4.2 < bean >
id属性: < bean >在容器中的标志。
class属性:每个注册到容器的对象都需要通过< bean >的class属性指定其类型。
5.spring在IOC容器的XML配置中,如何表达依赖性?
5.1通过构造方法注入XML
需要使用< constructor-arg>(constructor 构造函数)
public UserDaoImpl(String name){
this.name = name;
}
<bean id="userDao" class="com.spring.firstday.UserDaoImpl" destroy-method="">
<constructor-arg name="name" value="Hello"></constructor-arg>
</bean>
当无法明确配置项与对象的构造方法参数列表一一对应时,就需要引入< constructor-arg> 的type(类型)或者index(性质)属性。
5.1.1 type属性
public class ConstructorConfusion {
public ConstructorConfusion(String someValue) {
System.out.println("ConstructorConfusion(String) called");
}
public ConstructorConfusion(int someValue) {
System.out.println("ConstructorConfusion(int) called");
}
}
该类声明了两个构造方法,但是注意的是这两个构造函数名一样,这个时候就需要type来区别配置
<bean id="constructorConfusion" class="com.apress.prospring.ch4.ConstructorConfusion">
<constructor-arg>
<value>90</value>
</constructor-arg>
</bean>
这样的话spring只调用第一个构造方法。
<bean id="constructorConfusion" class="com.apress.prospring.ch4.ConstructorConfusion">
<constructor-arg type="int">
<value>90</value>
</constructor-arg>
</bean>
5.1.2 index属性
当只有一个构造函数,但是它的参数类型都相同的时候,就需要index来区分
public class ConstructorConfusion {
public ConstructorConfusion(String someValue1, String sone Value2) {
System.out.println("ConstructorConfusion(String) called");
System.out.println("ConstructorConfusion(String) called");
}
}
<bean id="constructorConfusion" class="com.apress.prospring.ch4.ConstructorConfusion">
<constructor-arg index="1"> <value>90</value>
<constructor-arg index="2"> <value>100</value>
</bean>
5.2 setter注入
需要使用< property>
< property >有一个name属性,用来指定该< property >将会注入的对象所对应的实例变量名称。之后通过value或者ref属性或者内嵌其他元素来指定具体的依赖对象引用或值。
<bean id="constructorConfusion" class="com.apress.prospring.ch4.ConstructorConfusion">
<property name = "newListener">
<ref bean = "djNewsListener"/>
</property>
</bean>