Factory Bean
Spring的FactoryBean是一个特殊的Bean,用于创建其他Bean实例。FactoryBean接口定义了一个工厂Bean,该Bean可以用来生成其他Bean的实例。通过实现FactoryBean接口,开发人员可以自定义Bean的创建逻辑,实现更灵活的Bean实例化过程。
FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
//返回由FactoryBean创建的Bean实例。
@Nullable
T getObject() throws Exception;
//返回由FactoryBean创建的Bean实例的类型。
@Nullable
Class<?> getObjectType();
//返回由FactoryBean创建的Bean实例是否是单例的。
default boolean isSingleton() {
return true;
}
}
通过实现FactoryBean接口,开发人员可以自定义Bean的创建过程,实现一些复杂的逻辑,例如对象的缓存、对象的代理等。在Spring中,FactoryBean常用于定制化Bean的创建过程,提供更灵活的Bean管理方式。
案例演示
我们的案例演示将使用上一讲的Spring的bean的生命周期的实例,在我们已经创建好的实例上进行相关处理。
实体类
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
public User() {
System.out.println("生命周期:1、创建对象");
}
public User(Integer id, String username, String password, Integer age) {
this.id = id;
this.username = username;
this.password = password;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
System.out.println("生命周期:2、依赖注入");
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void initMethod(){
System.out.println("生命周期:3、初始化");
}
public void destroyMethod(){
System.out.println("生命周期:5、销毁");
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
'}';
}
}
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">
<!-- 使用init-method属性指定初始化方法 -->
<!-- 使用destroy-method属性指定销毁方法 -->
<bean id="userFactory" class="com.miaow.spring.bean.User" init-method="initMethod" destroy-method="destroyMethod">
<property name="id" value="257258"></property>
<property name="age" value="25"></property>
<property name="password" value="wwafheda"></property>
<property name="username" value="张老三"></property>
</bean>
<bean id="myBeanProcessor" class="com.miaow.spring.process.MyBeanProcessor"></bean>
<!-- 配置bean FactoryBeam-->
<bean id="userFactoryBean" class="com.miaow.spring.factory.UserFactoryBean"></bean>
</beans>
UserFactoryBean
/**
* @author HWZ
* @date 2024年05月11日 10:36
* @description FactoryBean 是Spring提供的一种整合第三方框架的常用机制,和普通bean不同,配置一个FactoryBean类型的bean,
* Spring会调用FactoryBean的getObject()方法来获取一个实例,而不是直接new一个对象。
* FactoryBean的getObject()方法返回的是一个实例,而不是一个类。
* FactoryBean的getObjectType()方法返回的是一个类,而不是一个实例
*/
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
后置处理器
public class MyBeanProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("☆☆☆" + beanName + " = " + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("★★★" + beanName + " = " + bean);
return bean;
}
}
测试
//factorty测试
@Test
public void FactoryTest(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-factory.xml");
User user = (User) context.getBean("userFactory");
System.out.println(user);
System.out.println("生命周期:4、通过IOC容器获取bean并使用");
context.close();
}
基于XML的自动装配
Spring的自动装配是一种通过Spring容器自动连接应用程序中的Bean的方式。当Bean定义了依赖关系时,Spring容器可以自动识别这些依赖关系,并自动将相应的Bean注入到目标Bean中,从而实现Bean之间的自动连接。
目前Spring中提供自动装配的方式分为如下三种:
- 根据类型自动装配:Spring 容器会自动匹配Bean的类型,将符合类型要求的Bean注入到目标Bean中。
- 根据名称自动装配:Spring 容器会自动匹配Bean的名称,将符合名称要求的Bean注入到目标Bean中。
- 构造函数自动装配:Spring 容器会自动识别目标Bean的构造函数,并自动将依赖的Bean注入到构造函数当中。
模拟实现
我们通过一个实例来看一下Spring 的自动装配方式,首先我们创建一个我们常用的开发层。
创建一个控制层
public class UserController {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void saveUser(){
userService.saveUser();
}
}
创建接口UserService
public interface UserService {
void saveUser();
}
创建Service接口实现层
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void saveUser() {
userDao.saveUser();
}
}
创建dao层接口
public interface UserDao {
void saveUser();
}
创建类dao层实现层
public class UserDaoImpl implements UserDao {
@Override
public void saveUser() {
System.out.println("保存成功");
}
}
根据类型自动装配(byType)
<?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">
<!-- spring IOC的自动装配 根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类
自动装配方式:byType
byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值
若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null
若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionException
自动装配方式:byName
byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值
-->
<bean id="userController" class="com.miaow.spring.controller.UserController" autowire="byType"></bean>
<!-- 配置 service层-->
<bean id="userService" class="com.miaow.spring.service.impl.UserServiceImpl" autowire="byType"></bean>
<!-- 配置dao层-->
<bean id="userDao" class="com.miaow.spring.dao.impl.UserDaoImpl"></bean>
</beans>
//自动装配 通过注解的方式ByType 和 ByName装配
@Test
public void AutoWireTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-user.xml");
UserController user = (UserController) context.getBean(UserController.class);
user.saveUser();
}
根据名称注入(byName)
<bean id="userController" class="com.miaow.spring.controller.UserController" autowire="byName"></bean>
<bean id="userService" class="com.miaow.spring.service.impl.UserServiceImpl" autowire="byName"></bean>
构造器注入
我们需要创建一个实体类,用来存储我们在XML配置文件中通过构造器注入的相关值。
在Java类中定义相应的构造函数,Spring容器会根据XML配置文件中的<constructor-arg>
元素来自动注入参数值。
public class MyBean {
private int number;
private AnotherBean anotherBean;
public MyBean(int number, AnotherBean anotherBean) {
this.number = number;
this.anotherBean = anotherBean;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public AnotherBean getAnotherBean() {
return anotherBean;
}
public void setAnotherBean(AnotherBean anotherBean) {
this.anotherBean = anotherBean;
}
@Override
public String toString() {
return "MyBean{" +
"number=" + number +
", anotherBean=" + anotherBean +
'}';
}
}
public class AnotherBean {
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public String toString() {
return "AnotherBean{" +
"number=" + number +
'}';
}
}
<!-- 构造方法注入 -->
<bean id="myBean" class="com.miaow.spring.bean.MyBean">
<constructor-arg value="123" type="int"/>
<constructor-arg ref="anotherBean"/>
</bean>
<bean id="anotherBean" class="com.miaow.spring.bean.AnotherBean"/>
public void AutoWireTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-user.xml");
MyBean myBean = (MyBean) context.getBean("myBean");
System.out.println(myBean);