Spring Bean相关内容
1 Bean的基础配置
//bean标签抽象理解就是将某个类添加到Ioc容器中,然后实例化为类对象(bean)。
//以下均为<bean>标签的属性。
(1) id和class属性
<1> id:使用容器可以通过id值获取bean,在一个容器中id值唯一。
<2> class:bean的类型,即配置的bean的全路径类名。
(2) 设置别名:name
//与id的使用上几乎没有区别。
<1> 定义bean的别名,可以定义多个,使用逗号,分号;空格 分隔。<bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl"/>
//通过Ioc容器获取时,既可以使用bookService获取,也可以使用service、service4、bookEbi获取。
//说明:Ebi全称Enterprise Business Interface,翻译为企业业务接口。
<2> 获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionException。
(3) 控制范围:scope
<1> 定义bean的作用范围,可选范围如下:singleton(默认单例)、prototype(非单例)。<bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>
//单例:被多次使用的该bean,对象地址相同,是同一个对象,即在Spring的IOC容器中只会有该类的一个对象。
//非单例:每次使用的该bean,对象地址不同,每次都实例化一个对象,即在Spring的IOC容器中可能有该类的多个对象。
<2> bean默认为单例避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高。
<3> 表现层对象、业务层对象、数据层对象、工具对象适合交给容器进行管理;封装实例的域对象不适合交给容器进行管理。
(4) 小结
<bean id="bean的唯一标识" class="bean的路径" scope="bean的作用范围,有singleton(默认)和prototype两种" name="bean的别名"/>
2 Bean的实例化
//当Ioc容器被获取时类开始实例化,实例化完成后成为bean,bean本质是类对象。
//Ioc容器默认立即加载,会在初始化容器时实例化所有bean(按Spring配置文件中的bean标签顺序)。
//当Ioc容器被手动销毁时,其中的所有bean也会被销毁,与Spring配置文件中的bean标签顺序相反。
(1) 构造方法实例化
<1> 准备需要被创建的类
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("BookDaoImpl_save");
}
}
<2> 类中提供构造函数测试
//在BookDaoImpl类中添加一个无参构造函数,并打印一句话,方便观察结果。
public class BookDaoImpl implements BookDao {
//构造方法
public BookDaoImpl() {
//将构造函数改成private测试,运行程序,能执行成功。内部走的依然是构造函数,能访问到类中的私有构造方法,显而易见Spring底层用的是反射。
//构造函数中添加一个参数测试,运行程序,程序会报错,说明Spring底层使用的是类的无参构造方法。
//因为每一个类默认都会提供一个无参构造函数,所以其实真正在使用这种方式的时候,我们什么也不需要做。这也是我们以后比较常用的一种方式。
System.out.println("BookDaoImpl的构造函数正在运行...");
}
public void save() {
System.out.println("BookDaoImpl_save");
}
}
<3> 将类配置到Spring容器<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<4> 编写运行类
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("applicationContext.xml");
//该语句运行后,构造函数就会被执行。
//当容器被获取时,其中所有的bean都会实例化。
BookDao bookDao = (BookDao) cpxac.getBean("bookDao");
bookDao.save();
}
}
//运行结果:BookDaoImpl的构造函数正在运行...BookDaoImpl_save
(2) 静态工厂实例化
//介绍完静态工厂实例化后,这种方式一般是用来兼容早期的一些老系统,所以了解为主。
//通过scope属性实现非单例。
<1> 准备需要被创建的类
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("BookDaoImpl_save");
}
}
<2> 创建一个工厂类并提供一个静态方法
//静态工厂创建对象
public class BookDaoFactory {
public static BookDao getBookDao(){
//静态方法可直接通过类名访问,然后执行方法体,返回一个对象。
return new BookDaoImpl();
}
}
<3> 将工厂类配置到Spring容器<bean id="bookDao" class="com.itheima.factory.BookDaoFactory" factory-method="getBookDao"/>
//class:工厂类的路径 factory-mehod:具体工厂类中创建对象的方法名
//代表实例化工厂类BookDaoFactory,并执行其中的getBookDao方法来创建bean。
<4> 编写运行类,在类中通过工厂获取对象
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) cpxac.getBean("BookDaoImpl");
bookDao.save();
}
}
//运行结果:BookDaoImpl_save
//工厂类存在的理由:在工厂的静态方法中,我们除了new对象还可以做其他的一些业务操作,这些操作必不可少。之前new对象的方式就无法添加其他的业务内容。
public class BookDaoFactory {
public static BookDao getBookDao(){
System.out.println("工厂启动...");
//模拟必要的业务操作
return new BookDaoImpl();
}
}
(3) 实例工厂实例化
//通过scope属性实现非单例。
<1> 准备需要被创建的类
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("BookDaoImpl_save");
}
}
<2> 创建一个工厂类并提供一个普通方法
//注意此处和静态工厂的工厂类不一样地方是方法不是静态方法。
public class BookDaoFactory {
public BookDao getBookDao(){
return new BookDaoImpl();
}
}
<3> 将工厂类配置到Spring容器
<bean id="bookFactory" class="com.itheima.factory.BookDaoFactory"/>
<!--代表实例化工厂类bookFactory。-->
<!--因为工厂类中的方法不是静态方法,所以必须先示例化工厂类,再来通过另一条XML语句调用工厂类对象中的方法创建bean。-->
<!--注意:实例化类的XML语句结束后才代表类实例化完成。因此不能将调用方法属性写在XML语句中,因为此时类对象还为实例化完成。除非为静态方法。-->
<bean id="bookDao" factory-bean="bookFactory" factory-method="getBookDao"/>
<!--代表调用bean(工厂类对象bookFactory)中的方法来创建bean。-->
<4> 编写运行类,在类中通过工厂获取对象
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) cpxac.getBean("bookDao");
bookDao.save();
}
}
//运行结果:BookDaoImpl_save
(4) FactoryBean实例化
//简化实例工厂实例化的开发
<1> 准备需要被创建的类
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("BookDaoImpl_save");
}
}
<2> 创建一个工厂类,实现FactoryBean接口,重写接口的方法
public class BookDaoFactoryBean implements FactoryBean<BookDao> {
//代替原始实例工厂中创建对象的方法
public BookDao getObject() throws Exception {
return new BookDaoImpl();
}
//返回所创建类的Class对象
public Class<?> getObjectType() {
return BookDao.class;
}
}
<3> 将工厂类配置到Spring容器
<bean id="bookDao" class="com.itheima.factory.BookDaoFactoryBean"/>
//因为工厂类实现了FactoryBean<?>接口,所以不必再先用一条XML语句实例化工厂类,再用另一条XML语句执行对应方法。
//getObject()方法代替原始实例工厂中创建对象的方法,该方式任何情况下,所需执行的方法都是getObject(),所以不必再写factory-method属性。
<4> 编写运行类,在类中通过工厂获取对象
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) cpxac.getBean("bookDao");
bookDao.save();
}
}
//运行结果:BookDaoImpl_save
// FactoryBean接口其实会有三个方法
// 方法一:getObject(),被重写后,在方法中进行对象的创建并返回。
// 方法二:getObjectType(),被重写后,主要返回的是被创建类的Class对象。
// 方法三:isSingleton(),设置对象是否为单例,没有被重写,因为它已经给了默认值,默认为true。
// 那如果想改成单例,只需要将isSingleton()方法进行重写,修改返回为false,即可
public boolean isSingleton() {
return false;
}
3 bean的生命周期
(1) 生命周期设置
<1> 准备需要被创建的类,添加初始化和销毁方法
//在BookDaoImpl类中分别添加两个方法,方法名任意
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("BookDaoImpl_save");
}
//表示bean初始化对应的操作
public void init(){
System.out.println("BookDaoImpl_init");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("BookDaoImpl_destory");
}
}
<2> 配置生命周期<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
//init-method属性对应初始化方法的方法名。
//destroy-method属性对应销毁方法的方法名。
<3> 运行程序
public class App {
public static void main( String[] args ) {
ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) cpxac.getBean("bookDao");
bookDao.save();
}
}
//运行结果:BookDaoImpl_initBookDaoImpl_save
//从结果中可以看出,init方法执行了,但是destroy方法却未执行。
//pring的IOC容器是运行在JVM中。运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方法执行。
//main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了,所以没有调用对应的destroy方法。
(2) Spring简化生命周期配置
//Spring提供了两个接口来完成生命周期的控制,好处是可以不用再进行配置 init-method和destroy-method。
<1> 准备需要被创建的类,添加初始化和销毁方法
//添加两个接口InitializingBean、DisposableBean并实现接口中的两个方法afterPropertiesSet和destroy。
public class BookServiceImpl implements BookService,InitializingBean,DisposableBean {
//实现InitializingBean,DisposableBean两个接口,其中分别有destroy()和afterPropertiesSet()方法。
private BookDao bookDao;
//setBookDao方法是Spring的IOC容器为其注入属性的方法。
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("BookDaoImpl_save");
bookDao.save();
}
public void destroy() throws Exception {
System.out.println("BookDaoImpl_destroy");
}
public void afterPropertiesSet() throws Exception {
//对于InitializingBean接口中的afterPropertiesSet方法,翻译过来为属性设置之后。
System.out.println("BookDaoImpl_init");
}
}
<2> 配置生命周期<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
//不用再进行配置 init-method和destroy-method。
(3) close()关闭容器
ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("applicationContext.xml");
cpxac.close();
//运行上述程序,就能执行destroy方法的内容。
(4) 注册钩子关闭容器
<1> 在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器。
ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("applicationContext.xml");
cpxac.registerShutdownHook();
//注意:registerShutdownHook在ApplicationContext中也没有。
<2> 两种方式异同
相同点:这两种都能用来关闭容器。
不同点:close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭。
//close()方法只能写在代码最后,registerShutdownHook()方法可以写在代码任意位置。
(5) 小结
<1> 关于Spring中对bean生命周期控制提供了两种方式:
在配置文件中的bean标签中添加init-method和destroy-method属性。
bean点对应类实现InitializingBean与 DisposableBean接口,这种方式了解下即可。
<2> 关闭容器的两种方式:close()方法registerShutdownHook()方法
<3> 对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:
<3.1> 初始化容器
创建对象
执行构造方法(构造方法)
//因为先要创建对象,而创建对象后,会先执行构造方法。
执行属性注入(setter方法)
//因为所创建的对象需要另一个对象,所以要执行setter方法后,该对象才算创建完成。
执行bean初始化方法(afterPropertiesSet方法)
//对象创建完全创建完成后,执行初始化方法。
<3.2> 使用bean
执行业务操作
<3.3> 销毁容器
执行bean销毁方法(destroy方法)

浙公网安备 33010602011771号