@[TOC]
bean的实例化
==bean本质上就是对象,对象在new的时候会使用构造方法完成,那创建bean也是使用构造方法完成的。==
接下来我们来说说Spring的IOC实例化对象的三种方式:
- 构造方法(常用)
- 静态工厂(了解)
实例工厂(了解)
- FactoryBean(实用)
构造方法
Spring底层用的是反射,因为这个构造函数无论是public还是private都可以被执行!==一定要有一个空参构造器==
因为每一个类默认都会提供一个无参构造函数,所以其实真正在使用这种方式的时候,我们什么也不需要做。这也是我们以后比较常用的一种方式。构造方法在类中默认会提供,但是如果重写了构造方法,默认的就会消失,在使用的过程中需要注意,如果需要重写构造方法,最好把默认的构造方法也重写下。
静态工厂
==首先我们来回顾一下使用工厂来创建对象。==
(1)准备一个OrderDao和OrderDaoImpl类
public interface OrderDao {
public void save();
}
public class OrderDaoImpl implements OrderDao {
public void save() {
System.out.println("order dao save ...");
}
}
(2)创建一个工厂类OrderDaoFactory并提供一个==静态方法==
//静态工厂创建对象
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
return new OrderDaoImpl();
}
}
(3)编写AppForInstanceOrder运行类,在类中通过工厂获取对象
public class AppForInstanceOrder {
public static void main(String[] args) {
//通过静态工厂创建对象
OrderDao orderDao = OrderDaoFactory.getOrderDao();
orderDao.save();
}
}
(4)运行后,可以查看到结果
如果代码中对象是通过上面的这种方式来创建的,如何将其交给Spring来管理呢?
这就要用到Spring中的静态工厂实例化的知识了,具体实现步骤为:
步骤①:在spring的配置文件application.properties中添加以下内容:
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
class:工厂类的类全名
factory-mehod:具体工厂类中创建对象的方法名
对应关系如下图:
步骤②:在AppForInstanceOrder运行类,使用从IOC容器中获取bean的方法进行运行测试
public class AppForInstanceOrder {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
orderDao.save();
}
}
步骤③:运行后,可以查看到结果
静态工厂的代码更加复杂,那么这么做的意义是什么?
在工厂的静态方法中,我们除了new对象还可以做其他的一些业务操作,这些操作必不可少,如:
之前new对象的方式就无法添加其他的业务内容
这种方式一般是用来兼容早期的一些老系统,所以==了解为主==:
实例工厂
我们还是先回顾一下如何使用实例工厂创建对象
(1)准备一个UserDao和UserDaoImpl类
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("user dao save ...");
}
}
(2)创建一个工厂类OrderDaoFactory并提供一个普通方法,==注意此处和静态工厂的工厂类不一样的地方是方法不是静态方法==
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
(3)编写AppForInstanceUser运行类,在类中通过工厂获取对象
public class AppForInstanceUser {
public static void main(String[] args) {
//创建实例工厂对象
UserDaoFactory userDaoFactory = new UserDaoFactory();
//通过实例工厂对象创建对象
UserDao userDao = userDaoFactory.getUserDao();
userDao.save();
}
(4)运行后,可以查看到结果
那么我们在spring中如何去实现呢?
步骤①:在spring的配置文件中添加以下内容:
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
实例化工厂运行的顺序是:
- 创建实例化工厂对象,对应的是第一行配置
调用对象中的方法来创建bean,对应的是第二行配置
- factory-bean:工厂的实例对象
- factory-method:工厂对象中的具体创建对象的方法名,对应关系如下:
步骤②:在AppForInstanceUser运行类,使用从IOC容器中获取bean的方法进行运行测试
public class AppForInstanceUser {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.save();
}
}
FactoryBean的使用
FactoryBean方法严格来说属于实例工厂方法的改良延深
我们从实例工厂的方法中可以看出配置非常的麻烦,所以Spring为了简化这种配置方式就提供了一种叫FactoryBean
的方式来简化开发。
我们借用前面的bookDao:
BookDao接口:
public interface BookDao {
public void save();
}
bookDao实现类:
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
接下来我们使用FactoryBean
来对他进行实例化。
步骤①:首先我们直接创造一个对应的工厂类,这个工厂类要实现FactoryBean<>(带泛型),并且重写其中的几个方法:
public class BookServiceFactoryBean implements FactoryBean<BookService> {
public BookService getObject() throws Exception {
return new BookServiceImpl();
}
public Class<?> getObjectType() {
return BookService.class;
}
public boolean isSingleton() {
return false;
}
}
方法一:getObject(),被重写后,在方法中进行对象的创建并返回
方法二:getObjectType(),被重写后,主要返回的是被创建类的Class对象
方法三:可以不去主动重写,因为它已经给了默认值,从方法名中可以看出其作用是设置对象是否为单例,默认true。(也就是说你不重写默认就是单例模式,如果不想单例模式就如上代码一样返回false)
步骤②:在Spring的配置文件中添加如下代码:
<bean id="bookService" class="factory.BookServiceFactoryBean"/>
也就是说容器中直接放工厂bean
接下来我们执行一下代码:
public class App2 {
public static void main(String[] args) {
//获取容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
结果:
然后我们验证他是否为单例:
public class App2 {
public static void main(String[] args) {
//获取容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService1 = (BookService) ctx.getBean("bookService");
BookService bookService2 = (BookService) ctx.getBean("bookService");
// bookService.save();
System.out.println(bookService1);
System.out.println(bookService2);
}
}
结果: