Spring学习小结
文章目录
1. BeanFactory与ApplicationContext的关系
- BeanFactory是Spring的早期接口,称为Spring的Bean工厂,ApplicationContext是后期更高级接口,称之为Spring容器;
- ApplicationContext在BeanFactory基础上对功能进行了扩展,例如:监听功能、国际化功能等。BeanFactory的API更偏向底层,ApplicationContext的API大多数是对这些底层API的封装;
- Bean创建的主要逻辑和功能都被封装在BeanFactory中,ApplicationContext不仅继承了BeanFactory,而且ApplicationContext内部还维护着BeanFactory的引用,所以,ApplicationContext与BeanFactory既有继承关系,又有融合关系。
- Bean的初始化时机不同,原始BeanFactory是在首次调用getBean时才进行Bean的创建,而ApplicationContext则是配置文件加载,容器一创建就将Bean都实例化并初始化好。
2.只在Spring基础环境下,常用的三个ApplicationContext
实现类 | 功能描述 |
---|---|
ClassPathXmlApplicationContext | 加载类路径下的xml配置的ApplicationContext |
FileSystemXmlApplicationContext | 加载磁盘路径下的xml配置的ApplicationContext |
AnnotationConfigApplicationContext | 加载注解配置类的ApplicationContext |
3.Spring开发中Bean的配置
Bean的常用配置
Xml配置方式 | 功能描述 |
---|---|
<bean id=“” class=“”> | Bean的id和全限定名配置 |
<bean name=“”> | 通过name设置Bean的别名,通过别名也能直接获取到Bean实例 |
<bean scope=“”> | Bean的作用范围,BeanFactory作为容器时取值singleton和prototype |
<bean lazy-init=“”> | Bean的实例化时机,是否延迟加载。BeanFactory作为容器时无效 |
<bean init-method=“”> | Bean实例化后自动执行的初始化方法,method指定方法名 |
<bean destroy-method=“”> | Bean实例销毁前的方法,method指定方法名 |
<bean autowire=“byType”> | 设置自动注入模式,常用的有按照类型byType,按照名字byName |
<bean factory-bean=“” factory-method=“”/> | 指定哪个工厂Bean的哪个方法完成Bean的创建 |
beanName
例如:
配置UserDaolmpl由Spring容器负责管理
<bean id="testDaoService" class="com.hyl.service.TestDaoService"/>
此时存储到Spring容器(singleObjects单例池Map
)中的Bean的beanName是testDaoService,值是TestDaoService对象,可以根据beanName获取Bean实例
applicationContext.getBean ( "testDaoService");
如果不配置id,则Spring会把当前Bean实例的全限定名作为beanName
applicationContext.getBean ( "com.hyl.service.TestDaoService");
如果起别名,在没有配置id的时候,默认第一个别名为beanName;
如果配置的有id,同时也起了别名,这时候别名对应的还是id名,beanName还是id。
默认情况下,单纯的Spring环境Bean的作用范围有两个: Singleton和Prototype
- singleton:单例,默认值,Spring容器创建的时候,就会进行Bean的实例化,并存储到容器内部的单例池中,每次getBean时都是从单例池中获取相同的Bean实例;
- prototype:原型,Spring容器初始化时不会创建Bean实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例。
Bean的延迟加载
当lazy-init设置为true时为延迟加载,也就是当Spring容器创建的时候,不会立即创建Bean实例,等待用到时在创建Bean实例并存储到单例池中去,后续在使用该Bean直接从单例池获取即可,本质上该Bean还是单例的。
4. Bean的初始化和销毁方法配置
- 我们可以直接在bean里面配置对应的映射方法。
init-method="方法名1" destroy-method="方法名2"
- 我们还可以通过实现InitializingBean 接口,完成一些Bean的初始化操作,如下:
public class UserDaoImpl implements UserDao,InitializingBean {public UserDaoImpl() {System.out.println ( "UserDaoImpl创建了...");}public void init() {System.out.println("初始化方法..."); }public void destroy () {System.out.println("销毁方法...");}//执行时机早于init-method配置的方法public void afterPropertiesSet ( ) throws Exception {System. out.println ( "InitializingBean . . . " )}
}
5 Bean的实例化配置
Spring的实例化方式主要如下两种:
构造方式实例化:底层通过构造方法对Bean进行实例化
工厂方式实例化:底层通过调用自定义的工厂方法对Bean进行实例化
构造方式实例化Bean:
分为无参构造方法实例化和有参构造方法实例化,Spring中配置的几乎都是无参构;有参构造在实例化Bean时,需要参数的注入,通过<constructor-arg>标签,嵌入在<bean>标签内部提供构造参数
工厂方式实例化Bean,可分为如下三种:
静态工厂方法实例化Bean
实例工厂方法实例化Bean
实现FactoryBean规范延迟实例化Bean
静态工厂方法实例化Bean,其实就是定义一个工厂类,提供一个静态方法用于生产Bean实例,在将该工厂类及其静态方法配置给Spring即可。
//工厂类
public class UserDaoFactoryBean {//非静态工厂方法public static UserDao getUserDao(String name){//可以在此编写一些其他逻辑代码return new UserDaoImpl();}
}<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean" factory-method="getUserDao"><constructor-arg name="name" value="haohao"/>
</bean>
UserDaoImpl实例对象会存在于单例池中。
实例工厂方法,也就是非静态工厂方法产生Bean实例,与静态工厂方式比较,该方式需要先有工厂对象,在用工厂对象去调用非静态方法,所以在进行配置时,要先配置工厂Bean,在配置目标Bean。
//工厂类
public class UserDaoFactoryBean2 {//非静态工厂方法public UserDao getUserDao(String name){//可以在此编写一些其他逻辑代码return new UserDaoImpl();}
}<!-- 配置实例工厂Bean -->
<bean id="userDaoFactoryBean2" class="com.itheima.factory.UserDaoFactoryBean2"/>
<!-- 配置实例工厂Bean的哪个方法作为工厂方法 -->
<bean id="userDao" factory-bean="userDaoFactoryBean2" factory-method="getUserDao"><constructor-arg name="name" value="haohao"/>
</bean>
在Spring容器创建时,就完成了Bean的实例化,单例池中既有工厂Bean实例,也有目标Bean实例.
注:
<constructor-arg>标签不仅仅是为构造方法传递参数,只要是为了实例化对象而传递的参数都可以通过<constructor-arg>标签完成,例如上面通过工厂方法实例化Bean所传递的参数也是要通过<constructor-arg>进行传递的
Spring提供的FactoryBean接口规范(源码)
package org.springframework.beans.factory;public interface FactoryBean<T> {//获得实例对象方法T getObject() throws Exception;//获得实例对象类型方法Class<?> getObjectType();boolean isSingleton();
}
实现过程
定义工厂实现FactoryBean
public class UserDaoFactoryBean3 implements FactoryBean<UserDao> {public UserDao getObject() throws Exception {return new UserDaoImpl();}public Class<?> getObjectType() {return UserDao.class;}
}<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean3"/>
ps:
通过断点观察发现Spring容器创建时,FactoryBean被实例化了,并存储到了单例池singletonObjects中,但是getObject() 方法尚未被执行,UserDaoImpl也没被实例化,当首次用到UserDaoImpl时,才调用getObject() ,此工厂方式产生的Bean实例不会存储到单例池singletonObjects中,会存储到 factoryBeanObjectCache 缓存池中,并且后期每次使用到userDao都从该缓存池中返回的是同一个userDao实例。