定义实现类如下:
package com.example.demo231116.dao.impl;
import com.example.demo231116.dao.BookDao;
public class BookDaoImpl implements BookDao {
public void save(){
System.out.println("book dao save...");
}
public void init(){
System.out.println("book dao init...");
}
public void destroy(){
System.out.println("book dao destroy...");
}
}
配置方法如下:
<bean id="bookDaoCycle" class="com.example.demo231116.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy" />
最终调用跟平时一样:
// IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
System.out.println(bookDao5);
输出结果为:
book dao init...
com.example.demo231116.dao.impl.BookDaoImpl@5dd6264
并没有自动调用destroy方法,因为在程序执行结束后,java虚拟机关闭,程序不会自动调用destroy方法,如果需要调用,可以在程序的末尾加上:ctx.close()
,即在java虚拟机关闭之前执行destroy方法
但是事实上,ApplicationContext
并没有close方法, ApplicationContext
下的一个接口才有定义close方法,所以这里想要使用close方法,可以修改IoC容器定义:ClassPathXmlApplicationContextctx = new ClassPathXmlApplicationContext("applicationContext.xml");
然后再末尾调用ctx.close():
// IoC容器
ClassPathXmlApplicationContextctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
System.out.println(bookDao5);
ctx.close()
输出结果为:
book dao init...
com.example.demo231116.dao.impl.BookDaoImpl@5dd6264
book dao destroy...
但是如果是这样的话,ctx.close()
只能在程序的末尾写,因为在开头定义结束就写的话,这个IoC容器就被销毁了,下面也不可能执行一些getBean的操作
我们可以注册一个关闭钩子,在不用强行关闭IoC容器的情况下,设置在java虚拟机关闭之前让程序执行销毁的方法:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
System.out.println(bookDao5);
这样就不再需要强硬地执行ctx.close()
方法了
注:我在写这些代码的过程中发现一个老师没有提及的点,也是我之前一直忽略的,这些init方法的执行,是在初始化IoC容器时候就执行了,我的完整代码如下:
package com.example.demo231116;
import com.example.demo231116.dao.BookDao;
import com.example.demo231116.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo231116Application2 {
public static void main(String[] args) {
// 3. 获取IoC容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
// 4. 获取bean
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
BookDao bookDao = (BookDao) ctx.getBean("dao");
BookDao bookDao1 = (BookDao) ctx.getBean("dao");
System.out.println(bookDao);
System.out.println(bookDao1);
BookDao bookDao2 = (BookDao) ctx.getBean("bookDaoFactory");
System.out.println(bookDao2);
BookDao bookDao3 = (BookDao) ctx.getBean("bd");
System.out.println(bookDao3);
BookDao bookDao4 = (BookDao) ctx.getBean("bookDaoFactoryMethod");
System.out.println(bookDao4);
BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
System.out.println(bookDao5);
// ctx.close();
}
}
得到的结果是这样的:
Factory method....
实例工厂方法...
book dao init...
book service save...
book dao save...
com.example.demo231116.dao.impl.BookDaoImpl@6193932a
com.example.demo231116.dao.impl.BookDaoImpl@6193932a
com.example.demo231116.dao.impl.BookDaoImpl@647fd8ce
com.example.demo231116.dao.impl.BookDaoImpl@159f197
com.example.demo231116.dao.impl.BookDaoImpl@78aab498
com.example.demo231116.dao.impl.BookDaoImpl@5dd6264
book dao destroy...
事实上,init方法是在IoC容器初始化的时候执行了,而不是在我具体调用getBean()的时候才运行的,默认bean是单例模式,一开始就把init()
给执行掉了
如果我不使用单例而是定义多例的scope:
<bean id="bookDaoCycle" class="com.example.demo231116.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy" scope="prototype" />
主代码如下:
package com.example.demo231116;
import com.example.demo231116.dao.BookDao;
import com.example.demo231116.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo231116Application2 {
public static void main(String[] args) {
// 3. 获取IoC容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
// 4. 获取bean
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
BookDao bookDao = (BookDao) ctx.getBean("dao");
BookDao bookDao1 = (BookDao) ctx.getBean("dao");
System.out.println(bookDao);
System.out.println(bookDao1);
BookDao bookDao2 = (BookDao) ctx.getBean("bookDaoFactory");
System.out.println(bookDao2);
BookDao bookDao3 = (BookDao) ctx.getBean("bd");
System.out.println(bookDao3);
BookDao bookDao4 = (BookDao) ctx.getBean("bookDaoFactoryMethod");
System.out.println(bookDao4);
BookDao bookDao5 = (BookDao) ctx.getBean("bookDaoCycle");
BookDao bookDao6 = (BookDao) ctx.getBean("bookDaoCycle");
System.out.println(bookDao5);
System.out.println(bookDao6);
// ctx.close();
}
}
这样运行的结果是:
Factory method....
实例工厂方法...
book service save...
book dao save...
com.example.demo231116.dao.impl.BookDaoImpl@d4342c2
com.example.demo231116.dao.impl.BookDaoImpl@d4342c2
com.example.demo231116.dao.impl.BookDaoImpl@2bbf180e
com.example.demo231116.dao.impl.BookDaoImpl@163e4e87
com.example.demo231116.dao.impl.BookDaoImpl@56de5251
book dao init...
book dao init...
com.example.demo231116.dao.impl.BookDaoImpl@78aab498
com.example.demo231116.dao.impl.BookDaoImpl@5dd6264
是在具体定义实例的时候才执行的init方法,所以scope不同,init方法执行的先后顺序是不一样的
只需要在bean类下多实现这两个接口:
并继承必要的方法:
定义代码如下:
package com.example.demo231116.dao.impl;
import com.example.demo231116.dao.BookDao;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean {
public void save(){
System.out.println("book dao save...");
}
// public void init(){
// System.out.println("book dao init...");
// }
@Override
public void destroy() throws Exception {
System.out.println("接口destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("接口init");
}
}
Spring Config配置如下:
<bean id="bookDaoCycle" class="com.example.demo231116.dao.impl.BookDaoImpl" />
这个afterPropertiesSet
的init方法,是在先执行属性设置后再执行init方法