Spring-bean相关
一、bean配置
1.1 bean的别名配置
-
除了
id
属性外,可以通过name
属性给bean设置别名; -
可以通过
id
属性或name
属性设置的别名来获取bean,如下所示:<?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"> <!-- 1.在pom.xml中导入spring和junit的坐标 --> <!-- 2.配置bean(id需唯一) --> <bean id="bookDao_" name="bD, bookD" class="com.sea.dao.impl.BookDaoImpl"/> <bean id="bookService_" name="bService bookS BSer" class="com.sea.service.impl.BookServiceImpl"> <!-- bean标签的name属性用于给该bean起别名,多个别名之间使用逗号、分号或者空格分隔 --> <!-- 3.配置service与dao之间的关系 --> <property name="bookDao" ref="bD"/> <!-- name: 表示配置当前Service中哪一个具体的属性 --> <!-- ref: 表示参照哪一个bean --> </bean> </beans>
-
多个别名之间使用逗号、分号或者空格分隔!
1.2 bean的作用范围配置
-
通过
ctx.getBean()
获取的bean是否是单例对象呢?- 直接打印看看:
//此处,通过getBean()获取的bean是单例对象,即多次调用返回的是同一个对象 BookService bookService1 = (BookService)ctx.getBean("bookService_"); BookService bookService2 = (BookService)ctx.getBean("bookService_"); System.out.println(bookService1); System.out.println(bookService2);
- 结果:两次获取的bean实例对象的地址一致,说明是同一个对象。
-
如何创建非单例的bean对象呢?
-
在xml配置文件中,bean的默认scope属性为
singleton
,即单例模式; -
将该属性的值修改为
prototype
即可创建非单例的bean对象;- 如下:
<bean id="bookService_" name="bService bookS BSer" class="com.sea.service.impl.BookServiceImpl" scope="prototype"> ... </bean>
- 运行代码后:
-
-
为什么默认创建bean对象的方式为单例模式呢?
- Spring容器中管理的bean对象实例,都是属于可复用的对象;
哪些bean对象适合交给容器进行管理呢?(单例模式)
- 表现层对象(controller)
- 业务层对象(service)
- 数据层对象(mapper)
- 工具对象(utils)
哪些bean对象不适合交给容器进行管理呢?
- 封装实体的域对象(如domain中的实体类对象)
二、bean实例化过程
2.1 bean的创建
- bean本质上是对象,在Java中对象通常使用构造方法进行创建。
2.2 bean的三种创建方式
方式一:构造方法创建对象
- BookDao接口
/**
* @author: sea
* @date: 2023/6/25 15:24
*/
public interface BookDao {
void save();
}
- BookDaoImpl类
/**
* @author: sea
* @date: 2023/6/25 15:25
*/
public class BookDaoImpl implements BookDao {
private BookDaoImpl() {//此处私有的构造方法也可以找到【反射机制】
System.out.println("BookDao 构造方法 被调用了!");
}
public void save() {
System.out.println("Bookdao saving ... ");
}
}
- 配置文件
<?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.sea.dao.impl.BookDaoImpl"/>
</beans>
- 通过获取Spring容器创建的bean对象,并调用save方法,运行程序后控制台输出如下:
- 我们发现:
- 无论该无参构造方法是
public
还是private
,Spring创建实例化对象时都能够访问到!【用到了反射机制,在xml配置文件中的bean标签的class属性给出了该类的完整路径】 - 若是无参构造方法不存在,则将抛出
BeanCreationException
异常;
- 无论该无参构造方法是
方式二:静态工厂
-
编写静态工厂类OrderDaoFactory
/** * @author: sea * @date: 2023/6/27 14:37 */ public class OrderDaoFactory { /** * 静态工厂方法:getOrderDao * @return OrderDao */ public static OrderDao getOrderDao(){ System.out.println("OrderDao setup ... "); return new OrderDaoImpl(); } }
-
在配置文件中配置该工厂类以及静态工厂方法
- 1.配置bean标签的class属性值为静态工厂方法所在类的全路径;
- 【此时,Spring容器可以创建工厂类的bean对象,但是我们需要的是静态工厂方法创建的Dao对象】
- 2.给bean标签添加属性
factory-method
,属性值为静态方法的名称
<?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.sea.dao.impl.BookDaoImpl"/> <!-- 方式二:通过静态工厂方法创建对象 --> <bean id="orderDao" class="com.sea.factory.OrderDaoFactory" factory-method="getOrderDao"/> </beans>
- 1.配置bean标签的class属性值为静态工厂方法所在类的全路径;
-
通过获取Spring容器创建的工厂类对象,调用静态工厂方法返回的相应的bean对象
- 此处可以发现:
- 在配置文件中配置的bean都通过Spring容器创建了一个单例对象;
- 此处可以发现:
方式三:实例工厂
-
编写实例工厂类
/** * @author: sea * @date: 2023/6/27 14:37 */ public class UserDaoFactory { public UserDao getUserDao(){ return new UserDaoImpl(); } }
-
配置文件中进行配置:
-
1.配置实例工厂类bean对象
-
2.配置相应的Dao类型的bean对象
- 此处,通过bean标签的
factory-bean
属性进行配置工厂类的实例bean对象; - 有了工厂类的实例bean对象后,调用该对象的工厂方法创建Dao类型的bean对象;
- 而在静态工厂中,只需要配置工厂类的bean即可;
- 此处,通过bean标签的
<?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.sea.dao.impl.BookDaoImpl"/> <!-- 方式二:通过静态工厂方法创建对象 --> <bean id="orderDao" class="com.sea.factory.OrderDaoFactory" factory-method="getOrderDao"/> <!-- 方式三:通过实例工厂方法创建对象 --> <bean id="userDaoFactory" class="com.sea.factory.UserDaoFactory"/> <bean id="userDao" factory-bean="userDaoFactory" factory-method="getUserDao"/> </beans>
-
-
获取配置好的bean对象并调用对象的方法
-
存在的问题:
- 1.配置工厂类的bean仅仅是为了配合Dao类型的bean使用,没有其他意义;
- 2.方法名称不固定,每次都需要进行配置;
-
解决:
方式三(改进)
-
编写一个工厂类实现
FactoryBean<T>
接口,并实现接口中定义的方法;- Spring 容器会通过调用 getObject() 方法来获取实际的 bean 实例
/** * @author: sea * @date: 2023/6/27 14:37 */ public class UserDaoFactoryBean implements FactoryBean<UserDao> { //实现了 FactoryBean<T> 接口并实现了接口中定义的方法后, // Spring 容器会通过调用 getObject() 方法来获取实际的 bean 实例。 /** * 代替原始实例工厂中创建对象的方法(例如getUserDao) * @return * @throws Exception */ @Override public UserDao getObject() throws Exception { return new UserDaoImpl(); } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return true;//是否单例模式 } }
-
在配置文件中只需要配置一个bean即可:
<?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="userDaoFactory" class="com.sea.factory.UserDaoFactory"/> <bean id="userDao" factory-bean="userDaoFactory" factory-method="getUserDao"/> <!-- 方式三(改进):通过FactoryBean【这是一个接口】来实例化bean对象 --> <bean id="userDao_fb" class="com.sea.factory.UserDaoFactoryBean"/> </beans>
三、bean的生命周期
3.1 概念
- 生命周期:从创建到消亡的整个过程;
- bean的生命周期:bean从创建到销毁的整体过程;
- bean的生命周期控制:在bean创建后到销毁前的做的事情;
3.2 bean生命周期整体过程
- 初始化容器
- 1.创建对象(内存分配)
- 2.执行构造方法
- 3.执行属性注入
- 4.执行bean初始化方法
- 使用bean
- 1.执行业务操作
- 关闭/销毁容器
- 1.执行bean销毁方法