8/13
传统JavaBean和Spring中的Bean的区别:
1.用处不通:传统的JavaBean通常只是作为数值传递的载体;Spring中的Bean可以是任何组件
2.结构不通:传统JavaBean需要为每个变量提供get/set方法;Spring中的Bean只需要为设置注入的变量提供set方法
3.生命周期不通:传统JavaBean不接受任何容器管理其生命周期;Spring中的Bean由Spring容器管理其生命周期
Spring如何将XML配置文件中的Bean放入自己的容器(Spring如何通过反射机制来获取Bean):
首先在XML配置文件中,一个bean标签包含两个元素:id(唯一标示),class(完整类名,不能是接口或者抽象类,必须是实现类)。之后Spring读取这两个元素的值,简化为如下
代码将该bean添加到容器中:
//id元素
String id = ....
//class元素
String className = ....
//反射获取Class
Class clazz = Class.forName(className);
//利用Class无参构造器生产Bean实例
Object obj = class.newInstance();
//加入到Spring容器中
container.put(id,obj)
依赖注入的方式:设值注入和构造注入
如果Spring管理的Bean包含一些私有属性,那么在Spring初始化该Bean实例的时候,会通过以上两种方式为其注入属性值。也就是说Spring生成的Bean实例是完整的,包含
属性参数的。
1.设值注入:IOC容器使用Bean中的SET方法来为其注入被依赖的对象
在XML配置文件中,如果bean标签下含有property子标签,说明该Bean类包含一些属性,在初始化Bean对象时,会根据property标签中的子元素来判断该属性所属的类型
<bean ...>
//value子元素说明该属性是基本数据类型或其封装类或者String等类型
<property name="属性名" value="..."/>
//ref子元素说明该属性是其他bean类型
<property name="属性名" ref="其他bean id"/>
<bean/>
使用设值注入一定要在该Bean中提供需要注入属性的set方法
//定义一个主bean
<bean id ="person" class="....service.Person">
//该主bean依赖一个id为axe的bean
<property name="axe" ref="axe"/>
</bean>
//被依赖的axe bean
<bean id="axe" class="....service.Axe"/>
这时在主bean Person中包含一个Axe类型的属性,我们要利用Spring容器为它注入值以完成整个Person的实例化过程。
Public class Person{
//变量名axe应该与property中的name一致
private Axe axe;
//提供set方法帮助Spring完成设置注入,注意方法名一定要是小写"set" + 大写变量首字母后的变量名 "Axe"
public void setAxe(Axe a){
this.axe = a;
}
}
Spring在调用默认构造器实例化该Bean之后,立即调用对应的set方法为Bean的属性注入相应类型的值,注入的代码也是通过反射原理实现的:
String proName = axe;
String proClass = ....service.Axe;
String setName = "set" + proName.substring(0,1).toUpperCase() + proName.substring(1); //setAxe
Object paramBean = container.get(proName);//获取Axe实例
//获取方法名为setAxe,方法形参类型为Axe的set方法
Method setter = clazz.getMethod(setName ,paramBean.getClass());
//反射执行person的setAxe方法
setter.invoke(obj,paramBean );
2.构造注入:IOC容器使用构造器来注入被依赖对象
构造注入不需要像设值注入一样提供set方法,但却需要提供带参数的构造方法;换句话说,设值注入是在Spring底层通过无参构造器生产Bean实例,然后调用set方法注入属
性,而构造注入则是Spring在底层通过反射执行带参构造器对Bean进行实例化,构造实例的同时为其注入属性。构造注入需要提供<constructor-arg...>子标签
//定义一个主bean
<bean id ="person" class="....service.Person">
//该person拥有一个参数类型为Axe的构造方法,也可以使用value元素,代表常用类型,并且可以指定type 例如:<constructor-arg value="123" type="in"/>
<constructor-arg ref="axe"/>
//可以有多个constructor-arg标签,代表调用多个参数的构造方法,标签具有前后顺序,第一个标签对应第一个参数
<....>
</bean>
//被依赖的axe bean
<bean id="axe" class="....service.Axe"/>
Public class Person{
private Axe axe;
//使用构造注入必须提供一个与<constructor-arg>标签列表相符的构造方法
public Person(Axe a){
this.axe = a
}
}
与之前反射生成bean实例放入容器中类似:
//id元素
String id = ....//person
//class元素 //....service.Person
String className = ....
//反射获取Class
Class clazz = Class.forName(className);
//利用Class带参构造器生产Bean实例
Constructor c=clazz.getDeclaredConstructor(Class.forName(....service.Axe));
Object obj = c.newInstance(axe)
//加入到Spring容器中
container.put(id,obj)
理解依赖注入:
A对象需要调用B对象的方法,这种情形Spring称之为以来,即A对象以来B对象,传统方式往往调用者主动创建被调用对象,然后再调用被依赖对象的方法这种硬编码方式,或
者通过工厂模式获得被依赖对象。这两种方法或多或少都增加了代码的耦合度。而Spring通过容器管理所有Bean,并在Bean类初始化对象时为其注入相应的属性值,极大程度
上对代码进行了解耦。
依赖注入:Spring容器将被依赖对象赋值给调用者,相当于为调用者注入依赖的实例的这种方式叫做依赖注入
控制反转:调用者无需主动去创建或获取被依赖对象,调用者只需要被动的接受Spring容器注入的依赖实例。调用者从原先的主动获取到现在的被动接受的这种方式称为控制反
转
8/14
Spring容器有两个核心借口:BeanFactory和ApplicationContext,其中ApplicationContext是前者的子接口,BeanFactory接口含有以下几个方法:
判断Spring容器是否包含该id为name的Bean实例 boolean containsBean(String name)对应xml中bean的id
获取Spring容器中id为name的Bean的class类型 Class<?> getType(String name) 对应xml中bean的id
获取Spring容器中属于requiredType类型的唯一的Bean实例 <T> T getBean(Class<T> requiredType)对应xml中bean的class
获取Spring容器中id为name的Bean实例 Object getBean(String name)对应xml中bean的id
获取Spring容器中id为name,类型为requiredType的Bean实例 <T> T getBean(String name ,Class<T> requiredType) 对应xml中bean的id,class
ApplicationContext对BeanFactory的增强:
容器初始化时,默认初始化所有singleton Bean
可利用如ContextLoader的支持类,在web应用中自动创建ApplicationContext,而不需要手动创建它
ApplicationContext事件机制:
Spring容器中继承了ApplicationEvent类的Bean被称为容器事件
Spring容器中实现了ApplicationListener接口的Bean被称为监听器,实现该接口必须实现以下方法
onApplicationEvent(ApplicationEvent event):当容器中发生任何事件时,此方法都将触发
8/17
之前都是论述Spring容器如何将xml配置文件中的Bean放入容器中,假设现在有一个Bean,需要获取自己当前所在的Spring容器作为自己的参数(属性),来实现类似国际
化、发布事件等功能(该类事件需要用Spring 容器来实现).Bean获取当前管理自己的Spirng容器需要实现ApplicationContextAware接口,并定义一个私有的容器属性,该接
口包含一个setApplicationContext(ApplicationContext ctx)接口,当Spring容器检测所有Bean的时候,一旦发现某些Bean实现了ApplicationContextAware接口,就会将自己作
为参数传给该Bean的实例对象中的容器变量,例子如下:
pubic class Person implement ApplicationContextAware{
private ApplicationContext ctx;
public void setApplicationContext(ApplicationContext ctx){
this.ctx = ctx;
}
}
xml配置Bean的一些参数详解: