目录:
🍕1.5.1 思考1:我们造的这个对象是单例的还是非单例的?
🥪一、Bean的实例化
实例化bean的三种方式,构造方法,静态工厂和实例工厂
bean本质上就是对象,对象在new的时候会使用构造方法完成,那创建bean也是使用构造方法完成的。
🍬1.1环境准备
(1)创建一个Maven项目
(2)pom.xml添加依赖
(3)resources下添加spring的配置文件applicationContext.xml
🍬1.2构造方法实例化(常用)
🍕步骤1:准备需要被创建的类
准备一个BookDao和BookDaoImpl类
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
🍕步骤2:将类配置到Spring容器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.system.dao.impl.BookDaoImpl"/>
</beans>
🍕步骤3:编写运行程序
public class AppForInstanceBook {
public static void main(String[] args) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
🍕步骤4:类中提供构造函数测试
在BookDaoImpl类中添加一个无参构造函数,并打印一句话,方便观察结果。
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
运行程序,如果控制台有打印构造函数中的输出,说明Spring容器在创建对象的时候也走的是构造函数
🍕步骤5:将构造函数改成private测试
public class BookDaoImpl implements BookDao {
private BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
运行程序,能执行成功,说明内部走的依然是构造函数,能访问到类中的私有构造方法,显而易见Spring底层用的是反射
🍕步骤6:构造函数中添加一个参数测试
public class BookDaoImpl implements BookDao {
private BookDaoImpl(int i) {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
运行程序,程序会报错,说明Spring底层使用的是类的无参构造方法。
🍬1.3静态工厂实例化(了解)
Spring的第二种bean创建方式:静态工厂实例化 。这种方式一般是用来兼容早期的一些老系统,了解即可
🍕1.3.1工厂方式创建bean
(1)首先创建一个OrderDao和OrderDaoImpl类
public interface OrderDao {
public void save();
}
public class OrderDaoImpl implements OrderDao {
public void save() {
System.out.println("工厂创建对象成功");
}
}
(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)运行后,可以查看到结果:
🍕 1.3.2静态工厂实例化
(1)在spring的配置文件application.properties中添加以下内容:
<bean id="orderDao" class="com.system.factory.OrderDaoFactory" factory-method="getOrderDao"/>
class:工厂类的类全名
factory-mehod:具体工厂类中创建对象的方法名
(2)在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();
}
}
(3)运行后,可以查看到结果
🍕1.3.3思考:
这种方式在工厂类中不也是直接new对象的,和我自己直接new没什么太大的区别,而且静态工厂的方式反而更复杂,这种方式的意义是什么?
因为在工厂的静态方法中,我们除了new对象还可以做其他的一些业务操作。如果按照之前new对象的方式,就无法添加其他的业务内容。例如:
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
System.out.println("工厂 配置");
return new OrderDaoImpl();
}
}
重新运行,查看结果
🍬1.4实例工厂(了解)
Spring的第三种bean的创建方式:实例工厂实例化
🍕1.4.1环境准备
(1)准备一个UserDao和UserDaoImpl类
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("实例工厂创建对象成功 ...");
}
}
(2)创建一个工厂类UserDaoFactory并提供一个普通方法,注意此处和静态工厂的工厂类不一样的地方是方法不是静态方法
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)运行后,可以查看到结果
🍕1.4.2 实例工厂实例化(了解)
具体实现步骤为:
(1)在spring的配置文件中添加以下内容:
<bean id="userFactory" class="com.system.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
实例化工厂运行的顺序是:
①创建实例化工厂对象,对应的是第一行配置
②调用对象中的方法来创建bean,对应的是第二行配置
factory-bean:工厂的实例对象
factory-method:工厂对象中的具体创建对象的方法名
factory-mehod:具体工厂类中创建对象的方法名
(2)在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();
}
}
(3)运行后,查看结果
<bean id="userFactory" class="com.system.factory.UserDaoFactory"/> <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>需要先配置一个实例工厂bean,就是第一行的userFactory。
下面要用factory-bean来指向工厂bean。第一行的bean只是为了配合使用,实际没有任何意义,只是为了造它去用的。
factory-method的问题是方法名不固定,每次都需要重新配置。
spring针对于写factory-method方法时固定一个方法,不用创造一个无用bean做了一次改良,这个改良方式就是FactoryBean
🍬1.5 FactoryBean的使用(实用,必须掌握)
具体的使用步骤为:
(1)创建一个UserDaoFactoryBean的类,实现FactoryBean接口,重写接口的方法
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
//返回所创建类的Class对象
public Class<?> getObjectType() {
return UserDao.class;
}
}
(2)在Spring的配置文件中进行配置
<bean id="userDao" class="com.system.factory.UserDaoFactoryBean"/>
(3)AppForInstanceUser运行类不用做任何修改,直接运行
🍕1.5.1 思考1:我们造的这个对象是单例的还是非单例的?
我们在AppForInstanceUser文件中重新编译一下即可
public class AppForInstanceUser {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao1 = (UserDao) ctx.getBean("userDao");
UserDao userDao2 = (UserDao) ctx.getBean("userDao");
System.out.println(userDao1);
System.out.println(userDao2);
}
}
运行一下,看看结果是单例还是非单例
显然,这个对象是一种单例的
🍕1.5.2 思考2:怎么去把单例变成非单例呢?
在UserDaoFactoryBean文件中生成一个 isSingleton()方法,修改返回为false,即变成非单例。写true则为单例。
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
// 代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
//返回所创建类的Class对象
public Class<?> getObjectType() {
return UserDao.class;
}
//设置单例和非单例
public boolean isSingleton() {
return false;
}
}
重新运行AppForInstanceUser,查看结果
从结果中可以看出现在已经是非单例了,但是一般情况下默认是单例,所以isSingleton()方法一般不需要写。
🍬1.6 Bean实例化总结
🍕(1)bean是如何创建的?
构造方法
🍕(2)Spring的IOC实例化对象的三种方式分别是?
①构造方法(常用)
②静态工厂(了解)
③实例工厂(了解)
④FactoryBean(实用)
重点掌握构造方法和FactoryBean即可
需要注意的一点是,构造方法在类中默认会提供,但是如果重写了构造方法,默认的就会消失,在使用的过程中需要注意,如果需要重写构造方法,最好把默认的构造方法也重写下。