目录
一、Bean组件的周期与作用域
二、FactoryBean接口
一、Bean组件的周期与作用域
1.1 Bean组件的生命周期
什么是Bean的周期方法
- 我们可以在组件类中定义方法,然后当IoC容器实例化和销毁组件对象的时候进行调用!这两个方法我们成为生命周期方法!
- 类似于Servlet的init/ service/destroy方法,我们可以在周期方法完成初始化和释放资源等工作。
- Bean只有两种周期,init与destory,即初始化和销毁。
1.2 Bean生命周期的代码实现
创建组件类:
package com.alphamilk.Ioc5;
public class JavaBean {
/*
注意:使用周期方法时候,对应的方法必须满足以下几点
1.无参
2.返回值类型为void
*/
public void init(){
System.out.println("javaBean被初始化");
}
public void destory(){
System.out.println("JavaBean被正常销毁");
}
}
创建对应的配置文件xml
<?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.init-method 初始化组件方法
2.destroy-method 销毁组件方法
-->
<bean id="javaBean" class="com.alphamilk.Ioc5.JavaBean" init-method="init" destroy-method="destory"/>
</beans>
测试:
package com.alphamilk.Ioc;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class newTest {
@Test
public void test(){
// 创建容器对象
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("springioc-5.xml");
/*
注意,如果没有使用close函数,则会出现destroy方法无法调用的情况
因为没有close下,ioc容器会意外死亡,就不会调用destroy方法
*/
// 正常销毁组件对象
applicationContext.close();
}
}
2.1 Bean标签的作用域
什么是Bean标签的作用域
一般情况下Bean的作用域对应两种形式,单例和多例模式,以下具体讲解单例与多例。
- 单例:一般创建Bean中默认为单例模式singleton,其意思是在测试类中getBean的时候如果只有一个对应Bean标签,那么哪怕进行多次getBean返回,返回对象都是同一个。
- 多例:指的是在测试类中getBean的时候,在使用getBean方法的时候,虽然只有一个标签,但是每一次调用都会产生一个新的Bean组件对象。
具体创建多少个Bean的实例对象,由Bean的作用域Scope属性指定!一般都推荐用单例模式
2.2 Scope作用域可选值
取值 | 含义 | 创建对象的时机 | 默认值 |
---|---|---|---|
singleton | 在 IOC 容器中,这个 bean 的对象始终为单实例 | IOC 容器初始化时 | 是 |
prototype | 这个 bean 在 IOC 容器中有多个实例 | 获取 bean 时 | 否 |
在WebApplicationContext中较为特殊,其scope多了两个取值
取值 | 含义 | 创建对象的时机 | 默认值 |
---|---|---|---|
request | 请求范围内有效的实例 | 每次请求 | 否 |
session | 会话范围内有效的实例 | 每次会话 | 否 |
2.3 案例代码
创建组件类对象
package com.alphamilk.Ioc5;
public class JavaBeanScope {
public void doWork(){
System.out.println("JavaBean is Working");
}
}
配置对应单例与多例情况下
在默认情况下不需要配置scpoe
测试代码:
package com.alphamilk.Ioc;
import com.alphamilk.Ioc5.JavaBeanScope;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class newTest {
@Test
public void test(){
// 创建Ioc容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springioc-5.xml");
// 通过容器获取Bean对象
JavaBeanScope bean = applicationContext.getBean(JavaBeanScope.class);
JavaBeanScope bean2 = applicationContext.getBean(JavaBeanScope.class);
// 结果为False,因为采用多例模式下,每一次getBean,Ioc都会new一个新的JavaBeanScope对象
System.out.println(bean==bean2);
}
}
二、FactoryBean接口
1.1 什么是FactoryBean
- 在我们前面文章中提到,实现SpringIoc有两个接口,四个实现类。Factory就是两个接口中的父接口。
- 虽然Ioc容器会自动new一个对象,但是并不是所有的组件都是可以随便就new出来的,比如Mybatis。其最终是要构造Session操作数据库对象,而获取该对象需要先获取配置信息getResource(配置文件),然后构造SessionFactoryBuilder,再调用SessionFactoryBuilder函数Builder,最后获取到的SessionFactory还需要调用方法openSession。这种复杂的创建对象的过程一般的Ioc容器就无法实现。所以我们直接从其根源FactoryBean来设置该如何实例化对象。
修改复杂实例化思路:
1.2 FactoryBean接口的常用方法
方法名 | 方法描述 |
---|---|
T getObject() | 返回由工厂创建的对象实例。该返回值将被存储到IoC容器中。 |
boolean isSingleton() | 如果此 FactoryBean 返回单例对象,则返回 true ,否则返回 false 。默认实现返回 true (注意,使用lombok插件可能会影响效果)。 |
Class<?> getObjectType() | 返回 getObject() 方法返回的对象类型。如果在创建之前不知道对象类型,则返回 null 。 |
1.3 实现FactoryBean案例代码
1.创建JavaBean需要实例化的子类
package com.alphamilk.Ioc6;
public class JavaBean {
private String name;
private int age;
// 组件方法
public void PrintInfo(){
System.out.println(name+"的年龄是"+age);
}
}
2.创建JavaBean需要实例化的工厂类
package com.alphamilk.Ioc6;
import org.springframework.beans.factory.FactoryBean;
//泛型内容<>内填写返回的类型
public class JavaBeanFactory implements FactoryBean<JavaBean> {
// 如果子例对象需要DI(依赖注入)则需要进行桥梁连接
private String name;
public void setName(String name) {
this.name = name;
}
private int age;
public void setAge(int age) {
this.age = age;
}
// 覆写如何实现实例化子类过程
@Override
public JavaBean getObject() throws Exception {
JavaBean javaBean = new JavaBean();
javaBean.setAge(age);
javaBean.setName(name);
return javaBean;
}
// 设置返回的类全定符
@Override
public Class<?> getObjectType() {
return JavaBean.class;
}
}
3.配置XML
<?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="javaBeanFactory" class="com.alphamilk.Ioc6.JavaBeanFactory">
<!-- 由于是setter注入,所以用对应的注入方法-->
<property name="name" value="黄飞宏"/>
<property name="age" value="99"/>
</bean>
</beans>
4.测试代码
package com.alphamilk.Ioc;
import com.alphamilk.Ioc5.JavaBeanScope;
import com.alphamilk.Ioc6.JavaBean;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class newTest {
@Test
public void test(){
// 创建Ioc容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springioc-6.xml");
// 获取组件Bean
JavaBean bean = (JavaBean) context.getBean("javaBeanFactory");
// 调用Bean方法测试是否有效
bean.PrintInfo();
}
}
总结一下FactoryBean的使用场景:
- 代理类的创建
- 第三方框架整合
- 复杂对象实例化等
容易混淆--面试题 FactoryBean和BeanFactory区别
- **FactoryBean **是 Spring 中一种特殊的 bean,可以在 getObject() 工厂方法自定义的逻辑创建Bean!是一种能够生产其他 Bean 的 Bean。FactoryBean 在容器启动时被创建,而在实际使用时则是通过调用 getObject() 方法来得到其所生产的 Bean。因此,FactoryBean 可以自定义任何所需的初始化逻辑,生产出一些定制化的 bean。
- 一般情况下,整合第三方框架,都是通过定义FactoryBean实现!!!
- BeanFactory 是 Spring 框架的基础,其作为一个顶级接口定义了容器的基本行为,例如管理 bean 的生命周期、配置文件的加载和解析、bean 的装配和依赖注入等。BeanFactory 接口提供了访问 bean 的方式,例如 getBean() 方法获取指定的 bean 实例。它可以从不同的来源(例如 Mysql 数据库、XML 文件、Java 配置类等)获取 bean 定义,并将其转换为 bean 实例。同时,BeanFactory 还包含很多子类(例如,ApplicationContext 接口)提供了额外的强大功能。
- 总的来说,FactoryBean 和 BeanFactory 的区别主要在于前者是用于创建 bean 的接口,它提供了更加灵活的初始化定制功能,而后者是用于管理 bean 的框架基础接口,提供了基本的容器功能和 bean 生命周期管理。