重点:
IOC实现原理:
在初始化一个Spring容器时,Spring会去解析指定的xml文件,当解析到其中的<bean>标签时,会根据该标签中的class属性指定的累的全路径名,通过反射创建该类的对象,并将该对象存入内置的Map中管理。其中键就是该标签的id值,值就是该对象。
由此可得:
多次获取同样一个id的bean,得到的是同一个对象。即使是同一个类,如果配置过多个<bean>标签具有不同的id,每个id都会在内置Map中有一个键值对,其中的值就是不同的对象。同一个<beans>标签下不允许配置多个同id的<bean>标签,如果配置则抛出异常。
IOC获取对象的方式:
通过context.getBeans()方法获取bean时,可以通过两种方式获取:
传入id值
传入class值
通过class方式获取bean时,如果同一个类型配置过多个bean,则获取是因为无法确定到底获取那个bean会抛出异常。
id唯一,不存在这样的问题,推荐用id获取。
别名标签:
在Spring中提供了别名标签<alias>可以为配置的<bean>起一个别名,要注意的是这仅仅是对指定的<bean>起的一个别名,并不会额外的创建对象存入map。
<alias name="要起别名的bean的id" alias="要指定的别名"/>
Spring创建对象的方式:
- 通过类的无参构造方法创建对象
当用最普通方式配置一个<bean>时,默认就是采用类的无参构造创建对象。在Spring容器初始化时,通过<bean>上配置的class属性反射得到字节码对象,通过newInstance()创建对象。
1 2 | Class c = Class .forName("类的全路径名称") Object obj = c.newInstance() |
当创建的类没有无参构造时,无法通过反射创建对象,会抛出异常。
- 通过静态工厂创建对象
很多的时候,我们面对的类是无法通过无参构造去创建的,例如该类没有无参构造、是一抽象类等等情况,此时无法要求spring通过无参构造创建对象,此时可以使用静态工厂 方式创建对象。
1 2 3 4 5 | public class CalendarStaticFactory { public static Calendar getCalendar(){ return Calendar.getInstance(); } } |
<bean id="calendar" class="cn.tedu.factory.CalendarStaticFactory" factory-method="getCalendar"></bean>
3.实例工厂创建对象
实例工厂也可以解决类是无法通过无参构造创建的问题,解决的思路和静态工厂类似,只不过实例工厂提供的方法不是静态的。spring需要先创建出实例工厂的对象,在调用实例工厂对象上指定的普通方法来创建对象。所以实例工厂也需要配置到Spring中管理。
1 2 3 4 5 6 9 |
public class CalendarFactory { public Calendar getCalendar(){ return Calendar.getInstance(); } } |
<bean id="calendarFactory" class="cn.tedu.factory.CalendarFactory"></bean>
<bean id="calendar" factory-bean="calendarFactory" factory-method="getCalendar"/>
4.Spring工厂创建对象
Spring内置了工厂接口,也可以通过实现这个接口来开发Spring工厂。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public class CalendarSpringFactory implements FactoryBean<Calendar>{
/** * Spring工厂生产对象的方法 */ @Override public Calendar getObject() throws Exception { return Calen dar.getInstance(); }
/** * 获取当前工厂生产的对象的类型的方法 */ @Override public Class<?> getObjectType() { return Calendar.class; }
/** * Spring工厂生产对象时是否采用单例模式 * 如果返回true,则在spring中该对象只创建一次 后续 重复使用 * 如果返回false,则每次获取该bean 都重新 创建对象 */ @Override public boolean isSingleton() { return true; } } |
<bean id="calendar" class="cn.tedu.factory.CalendarSpringFactory"></bean>
Spring中单例与多例的概念:
Spring容器管理的bean在默认情况下是单例的,也即一个bean只会创建一个对象,存于Map中,之后无论获取多少次该bean,都返回同给一个对象。
Spring中默认采用单例方式,减少了对象的创建,从而减少了内存的消耗。Spring提供了选项可以将bean设置为多例模式。
Bean中的Scope属性可以设置单例和多例:
singleton:当前bean处在单例模式下(默认)
prototype:当前模式bean处于多例模式
单例模式的生命周期:
单例模式下,Spring容器启动时解析xml发现Bean标签,直接创建该bean,并将该bean标签加入map中,此后无论调用多少次getBean()获取该bean都是从map中获取,一直是一个对象。
bean在多例模式下的生命周期:
bean在多例模式下,spring容器启动时解析xml发现bean标签后,只是将该bean进行管理,并不会创建对象,此后每次调用getBean()获取该bean时,spring都会重新创建该对象并返回,每次都是一个新对象。这个对象spring容器不持有。
懒加载机制:
Spring默认会在容器初始化的过程中,解析xml,并将单例的bean创建并保存到map中,这样的机制在bean比较少时问题不大,但一旦bean非常多时,spring的初始化将会花费大量的时间来创建bean,而又的bean长时间用不上,这种bean的启动价值不高。
spring的懒加载机制。规定bean只有在第一次使用时加载,减轻了对时间和内存的消耗。
懒加载机制只对单例bean有作用,对于多例bean设置懒加载没有意义,因为多例本身就是获取是创建。
懒加载关键字:lazy-init
<bean id="cart" class="cn.tedu.beans.Cart" lazy-init="true"></bean>
全局配置懒加载:
default-lazy-init="true"
配置的优先级:
局部>全局
配置初始化和销毁的方法
在Spring中如果某个bean在初始化之后,或者销毁之前要做一些 额外操作,可以为给bean配置初始化和销毁的方法,在方法中完成要完成的功能。
配置关键字:init-method , destroy-method
<bean id="prodDao" class="cn.tedu.beans.ProdDao"
init-method="init" destroy-method="destory"></bean>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package cn.tedu.beans;
public class ProdDao {
public ProdDao() { System.out.println("ProdDao 被创建。。。"); }
public void init(){ System.out.println("init。。连接数据库。。。。。"); }
public void destory(){ System.out.println("destory。。断开数据库。。。。。"); }
} |
Spring以上关键字的执行顺序:
在Spring创建bean对象时,先创建对象(通过无参构造或者工厂),之后立即调用init方法来执行初始化操作,之后此bean就可以调用其他方法,最后在对象销毁时调用Destory方法来完成结尾工作。