文章目录
bean是如何创建出来的?
bean实例化——1.构造方法
- 本质上是对象,创建bean使用构造方法完成的。
//dao层接口:
public interface UserDao {
public void save(User user);
}
配置
<bean id="userDao" class="com.jules.dao.impl.UserDaoImpl"/>
//dao层实现类
public class UserDaoImpl implements UserDao {
//提供可访问的构造方法
//private UserDaoImpl(){}私有的也可以使用(反射)
public UserDaoImpl() {
System.out.println("执行UserDaoImpl的构造方法……");
}
public void save(User user) {
System.out.println("保存用户信息到数据库~");
}
}
//测试类:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (userDao) context.getBean("userDao");
userDao.save();
打印结果:-------------------------------------------------
执行UserDaoImpl的构造方法……
保存用户信息到数据库~
【Spring创建bean调的是无参的构造方法,并且私有的方法也可以使用】
【无参的构造方法如果不存在(有参),将会抛出异常BeanCreationException】
bean实例化——2.静态工厂
//dao层接口:
public interface UserVODao {
public void save();
}
//dao层实现类
public class UserVODaoImpl implements UserVODao {
public void save() {
System.out.println("UserVODao 保存~");
}
}
public class UserVODaoFactory{
//静态工厂----
public static UserVODao getUserVODao(){
//System.out.println("factory 创建~");
return new UserVODaoImpl();
}
}
//以前的测试类:
//通过静态工厂创建对象
UserVODao userVODao = new userVODaoFactory.getUserVODao();
userVODao.save();
//控制台输出-------------:UserVODao 保存~
=换模式:
<!--配置:使用静态工厂示例bean。-->
<!--注意:不仅要完全限定名到工厂类,还要factory-method指定工厂-->
<bean id="userVODao" class="com.jules.factory.UserVODaoFactory" factory-method="getUserVODao"/>
//测试类:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserVODao userVODao = (userVODao) context.getBean("userVODao");
userVODao.save();
bean实例化——3.实例工厂
//dao层接口:
public interface UserVODao {
public void save();
}
//dao层实现类
public class UserVODaoImpl implements UserVODao {
public void save() {
System.out.println("UserVODao 保存~");
}
}
public class UserVODaoFactory{
//工厂----
public UserVODao getUserVODao(){
return new UserVODaoImpl();
}
}
//以前的测试类:
//创建实例工厂对象
UserVODaoFactory userVODaoFactory = new UserVODaoFactory();
//通过实例工厂对象创建对象
UserVODao userVODao = new userVODaoFactory.getUserVODao();
userVODao.save();
//控制台输出:UserVODao 保存~
=换模式:
<!--配置:使用实例工厂示例bean-->
<!--先创建工厂的实例对象-->
<bean id="userFactory" class="com.jules.factory.UserVODaoFactory" />
<!---->
<bean id="userVODao" factory-method="getUserVODao" factory-bean="userFactory"/>
//测试类:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserVODao userVODao = (userVODao) context.getBean("userVODao");
userVODao.save();
bean实例化——4.FactoryBean(改良方法3)
【在spring中实例化bean的实例工厂方法的配置文件会有多余:接下来处理无用bean和方法的固定】
步骤:
-
1.创建一个UserDaoFactoryBean的工厂实现接口FactoryBean,此处泛型,你用它造什么对象就写什么
public class UserDaoFactoryBean implements FactoryBean<UserVODao> { //代替原始实例工厂中创建对象的方法 public UserDaoVO getobject() throws Exception { return new UserDaoVOImpl(); } //设置类型:对象什么类型 public class<?> getobjectType() { return UserDaoVO.class; } }
-
2.按照此种工厂配置bean
<bean id="userVODao" class="com.jules.factory.UserDaoFactoryBean"/>
【此时继续测试,依旧可行,并且还是单例模式,如何非单例呢?】
在 UserDaoFactoryBean 类中写方法:
public boolean isSingleton() {
//return true; //单例
return true; //非单例
}
bean生命周期控制
- bean生命周期:bean从
创建到销毁
的整体过程 - bean生命周期控制:在bean创建后到销毁
前
做的一些事情 - 上代码解释bean生命周期控制的两种方法-----------------------------------------------:
方法一、用配置控制:init-method、destory-method
//dao层接口:
public interface UserDao {
public void save(User user);
}
【在dao实现里面写两个方法--初始化和销毁方法,此时这两个方法是不能代表真正的初始化和销毁,需要在配置文件中配置:】
//提供生命周期控制方法
public class UserDaoImpl implements UserDao {
public void save(User user) {
System.out.println("保存用户信息到数据库~");
}
public void init(){
System.out.println("初始化init方法……");
}
public void destory(){
System.out.println("销毁destory方法……");
}
}
【配置bean生命周期的方法:init-method 和 destory-method】
<bean id="userDao" class="com.jules.dao.impl.UserDaoImpl" init-method="init" destory-method="destory"/>
//测试类:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (userDao) context.getBean("userDao");
userDao.save();
控制台打印结果:-------------------------------------
初始化init方法……
保存用户信息到数据库~
【看到输出结果你会发现,只执行了初始化方法,并没有销毁,why?如何让它销毁呢?】
我们现在的程序是写在java虚拟机中,虚拟机启动了,IoC容器加载了配置applicationContext.xml
,把bean初始化了,从中拿到beangetBean()
执行完程序,虚拟机退出了,但在退出过程中没有给bean一个销毁的状态。
如何销毁?就是让容器关闭了,关闭容器的两种方法:
-
①在虚拟机退出之前手动把容器关闭了
close()方法
。此种方法比较暴力,直接关闭容器在
ApplicationContext
中并没有close()方法,子类ConfigurableApplicationContext接口
中有close()方法,new对象ClassPathXmlApplicationContext
类可以使用close()。简单说一下他们三个的关系:ApplicationContext父类接口—子类ConfigurableApplicationContext接口----ClassPathXmlApplicationContext实现类
看图更清晰:close()根源是ConfigurableApplicationContext接口中的方法
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //context.close();//不可以放这里,报错 UserDao userDao = (userDao) context.getBean("userDao"); userDao.save(); context.close();
控制台打印结果:此时可以看到销毁过程已执行----------------------
初始化init方法……
保存用户信息到数据库~
销毁destory方法…… -
②注册关闭钩子:容器启动以后,加一个标志
ConfigurableApplicationContext接口
中registerShutdownHook()操作
,让虚拟机退之前,先把容器关闭后再退。ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //注册关闭钩子,关虚拟机之前先把容器关了。 context.registerShutdownHook(); UserDao userDao = (userDao) context.getBean("userDao"); //context.registerShutdownHook(); //在任何时间都可以,放这里执行也行 userDao.save();
close()和registerShutdownHook()的区别:
- close(); 暴力,说关就关,所以只能放在最后,如果放在getBean前面,会报错
BeanFactory not initializes or already closed……
- registerShutdownHook(); 就比较灵活,告知关闭虚拟机之前先把容器关闭,方法都可以执行。
【在实际开发中,此过程我们不需要写,我们最终做的是web应用,关闭容器这件事会伴随Tomcat】
方法二、使用接口,实现InitializingBean, DisposableBean接口:
上述范例中的初始化和销毁使我们随便写的,通过配置让它转为真正的初始化和销毁方法,这样不规范,spring就给我们提供了接口,就不用再配置在中init-method="init" destory-method="destory"
。
public class UserDaoImpl implements UserDao, InitializingBean, DisposableBean {
public void save(User user) {
System.out.println("保存用户信息到数据库~");
}
public void destory() throws Exception {
System.out.println("destory……");
}
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet……");
}
}
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (userDao) context.getBean("userDao");
userDao.save();
context.close();
}
控制台打印结果:-------------------------------
afterPropertiesSet……
保存用户信息到数据库~
destory……
【解释一下afterPropertiesSet(),上述案例我是在dao层实现中测试的,若换到service层的实现,直接上个图,观察一下:】