简识Spring创建Bean方式和设计模式
- 互联网
- 2025-08-28 00:03:02

一、理论解释:
Spring在创建Bean时主要有四种方式,这些方式分别涉及到了不同的设计模式。以下是具体的创建方式及对应的设计模式:
通过反射调用构造方法创建Bean: 方式:在Spring的配置文件中,使用<bean>标签的class属性指定要创建的Bean的完整类名。Spring容器内部会自动调用该类型的无参构造方法(或带参数的构造方法,此时需要配合<constructor-arg>标签指定参数)来创建Bean对象,并将其放在容器中以供使用。设计模式:这种方式主要使用了简单工厂模式的思想,即通过一个工厂类(在这里是Spring容器)来创建对象,但不需要显式地编写工厂类代码。不过,严格来说,由于Spring容器本身是一个复杂的框架,其内部实现可能涉及到了更多的设计模式,但在此处我们主要关注其对外提供的创建Bean的方式。 通过静态工厂方法创建Bean: 方式:首先编写一个包含静态方法的工厂类,该方法返回要创建的Bean对象。然后在Spring的配置文件中,使用<bean>标签的class属性指定工厂类的完整类名,并使用factory-method属性指定静态工厂方法名。Spring容器会自动调用该静态方法来获取Bean对象。设计模式:这种方式明确使用了静态工厂模式。静态工厂模式是一种创建型设计模式,它通过一个包含静态方法的类来创建对象,而不需要将对象作为类的成员。 通过实例工厂方法创建Bean: 方式:首先编写一个普通的工厂类(非静态),该类包含一个返回要创建的Bean对象的方法。然后在Spring的配置文件中,先使用<bean>标签创建一个工厂类的实例(即工厂Bean),再使用另一个<bean>标签的factory-bean属性指定工厂Bean的ID,并使用factory-method属性指定工厂方法名。Spring容器会先创建工厂Bean实例,然后调用其方法来获取Bean对象。设计模式:这种方式使用了工厂方法模式。工厂方法模式是一种创建型设计模式,它通过一个工厂类的方法来创建对象,但工厂类本身是一个普通类(非静态类)。 通过FactoryBean创建Bean: 方式:编写一个实现FactoryBean接口的类,该接口包含三个方法:getObject()用于返回要创建的Bean对象,getObjectType()用于返回Bean对象的类型,isSingleton()用于指定Bean对象是否为单例。然后在Spring的配置文件中,使用<bean>标签的class属性指定FactoryBean实现类的完整类名。Spring容器会自动调用FactoryBean的getObject()方法来获取Bean对象。设计模式:这种方式虽然表面上看起来与普通的Bean创建方式类似,但实际上它利用了FactoryBean接口的特殊性质来实现了一种更灵活的Bean创建方式。这种方式可以看作是对工厂方法模式的一种扩展或变种,因为它允许在创建Bean对象时进行更多的自定义操作(如延迟加载、代理创建等)。不过,从更广泛的角度来看,它也可以被视为一种代理模式的应用,因为FactoryBean实际上是在为真正的Bean对象创建一个代理或包装器。综上所述,Spring在创建Bean时主要使用了简单工厂模式(通过反射调用构造方法)、静态工厂模式、工厂方法模式和代理模式(通过FactoryBean)等设计模式。这些模式的应用使得Spring能够灵活地创建和管理Bean对象,从而满足了复杂应用程序的需求。
------分界线--------------------------------------------------------------------------------------------------------------
二、示例代码解释当然,下面我将根据上面提到的几种创建Bean的方式和对应的设计模式,给出具体的示例代码,并简要说明每个示例以及需要注意的事项。
1. 通过反射调用构造方法创建Bean示例代码:
// 定义一个简单的Bean类 public class MyBean { private String name; // 无参构造方法 public MyBean() { } // 带参数的构造方法(虽然在这个例子中未使用,但Spring支持) public MyBean(String name) { this.name = name; } // Getter和Setter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } } // Spring配置文件(applicationContext.xml) <bean id="myBean" class="com.example.MyBean"/>说明:
在Spring配置文件中,通过<bean>标签的class属性指定了要创建的Bean类。Spring容器会调用该类的无参构造方法来创建Bean实例。注意事项:
确保Bean类有一个可访问的无参构造方法。如果需要注入依赖,可以使用<property>或<constructor-arg>标签。 2. 通过静态工厂方法创建Bean示例代码:
// 静态工厂类 public class MyBeanFactory { // 静态工厂方法 public static MyBean createMyBean() { return new MyBean(); } } // Spring配置文件(applicationContext.xml) <bean id="myBean" class="com.example.MyBeanFactory" factory-method="createMyBean"/>说明:
在Spring配置文件中,通过<bean>标签的class属性指定了工厂类,并通过factory-method属性指定了静态工厂方法。Spring容器会调用该静态方法来创建Bean实例。注意事项:
确保工厂方法是静态的。工厂方法返回的对象类型应与配置文件中声明的Bean类型一致。 3. 通过实例工厂方法创建Bean示例代码:
// 实例工厂类 public class MyInstanceFactory { // 实例工厂方法 public MyBean createMyBean() { return new MyBean(); } } // Spring配置文件(applicationContext.xml) <!-- 首先创建工厂Bean实例 --> <bean id="myInstanceFactory" class="com.example.MyInstanceFactory"/> <!-- 然后通过工厂Bean实例创建目标Bean --> <bean id="myBean" factory-bean="myInstanceFactory" factory-method="createMyBean"/>说明:
在Spring配置文件中,首先通过<bean>标签创建了一个工厂Bean实例。然后通过另一个<bean>标签的factory-bean属性指定了工厂Bean的ID,并通过factory-method属性指定了工厂方法。Spring容器会先创建工厂Bean实例,然后调用其方法来创建目标Bean实例。注意事项:
确保工厂方法是实例方法(非静态)。工厂Bean实例和目标Bean实例的生命周期是独立的。 4. 通过FactoryBean创建Bean示例代码:
// 实现FactoryBean接口的类 public class MyFactoryBean implements FactoryBean<MyBean> { @Override public MyBean getObject() throws Exception { // 这里可以执行一些自定义逻辑,如创建代理、延迟加载等 return new MyBean(); } @Override public Class<?> getObjectType() { return MyBean.class; } @Override public boolean isSingleton() { // 指定Bean是否为单例 return true; } } // Spring配置文件(applicationContext.xml) <bean id="myFactoryBean" class="com.example.MyFactoryBean"/> // 注意:这里实际上获取的是FactoryBean的getObject()方法返回的对象,而不是FactoryBean本身 // 因此,在获取Bean时,不需要指定FactoryBean的ID,而是直接获取目标Bean的ID(尽管这里我们没有直接定义目标Bean的ID) // 但由于我们使用了FactoryBean,我们通常不会这样做。在实际应用中,我们可能会通过其他方式(如依赖注入)来使用这个Bean。 // 如果确实需要通过ID获取,可以这样做(但这不是FactoryBean的典型用法): // <bean id="myBean" factory-bean="myFactoryBean" factory-method="getObject"/> // 但通常,我们只需要配置FactoryBean,然后在需要MyBean的地方让Spring自动注入即可。注意:上面的配置文件中关于myBean的声明是不典型的,因为当你配置了一个FactoryBean后,你通常不会再去显式地通过factory-bean和factory-method去获取它产生的对象。相反,Spring会在你需要注入MyBean类型的地方自动使用MyFactoryBean来产生对象。因此,在实际应用中,你可能不会看到像上面那样的myBean声明。
典型用法:
在需要使用MyBean的地方,你只需声明一个依赖,Spring会自动使用MyFactoryBean来提供这个依赖。例如:
@Component public class SomeService { // Spring会自动注入MyFactoryBean产生的MyBean实例 private final MyBean myBean; @Autowired public SomeService(MyBean myBean) { this.myBean = myBean; } // ... 使用myBean的方法 ... }在这个例子中,SomeService类依赖于MyBean类型,而Spring会自动使用MyFactoryBean来创建并注入这个依赖。
说明:
FactoryBean接口允许你自定义Bean的创建逻辑。getObject()方法返回实际要注入的Bean实例。getObjectType()方法返回Bean实例的类型。isSingleton()方法指定Bean是否为单例。注意事项:
FactoryBean通常用于创建复杂的Bean实例,如代理对象、延迟加载对象等。确保getObject()方法返回的对象类型与FactoryBean接口中声明的泛型类型一致。当使用FactoryBean时,通常不需要在配置文件中显式地声明目标Bean的ID,因为Spring会自动处理这部分逻辑。------分界线--------------------------------------------------------------------------------------------------------------
三、饿汉模式、饱汉模式在您之前提到的Spring Bean创建方式中,并没有直接包含饿汉模式(Eager Initialization)和饱汉模式(Lazy Initialization)这两种单例模式的实现。饿汉模式和饱汉模式是单例模式在Java中的两种常见实现方式,它们主要用于确保一个类只有一个实例,并提供一个全局访问点来获取该实例。
1、饿汉模式(Eager Initialization)饿汉模式在类加载时就完成了实例的创建。因此,它是线程安全的,因为JVM在加载类时只会创建一个类实例。但是,如果实例从未被使用过,那么这种提前创建实例的方式可能会浪费资源。
示例代码:
public class EagerSingleton { // 在类加载时就创建实例 private static final EagerSingleton INSTANCE = new EagerSingleton(); // 私有构造方法防止外部实例化 private EagerSingleton() {} // 提供全局访问点 public static EagerSingleton getInstance() { return INSTANCE; } } 2、饱汉模式(Lazy Initialization)饱汉模式在第一次调用getInstance()方法时才创建实例。这种方式节省了资源,但如果多个线程同时调用该方法,则可能会导致多个实例被创建(即不是线程安全的)。为了解决这个问题,通常需要使用同步机制。
示例代码(非线程安全版本):
public class LazySingleton { // 声明实例变量但不立即初始化 private static LazySingleton instance; // 私有构造方法防止外部实例化 private LazySingleton() {} // 提供全局访问点(非线程安全) public static LazySingleton getInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; } }示例代码(线程安全版本,使用同步方法):
public class ThreadSafeLazySingleton { // 声明实例变量但不立即初始化 private static ThreadSafeLazySingleton instance; // 私有构造方法防止外部实例化 private ThreadSafeLazySingleton() {} // 提供全局访问点(线程安全,使用同步方法) public static synchronized ThreadSafeLazySingleton getInstance() { if (instance == null) { instance = new ThreadSafeLazySingleton(); } return instance; } }或者,使用双重检查锁定(Double-Checked Locking)来优化性能:
public class DoubleCheckedLockingSingleton { // 使用volatile关键字确保instance变量的可见性 private static volatile DoubleCheckedLockingSingleton instance; // 私有构造方法防止外部实例化 private DoubleCheckedLockingSingleton() {} // 提供全局访问点(线程安全,使用双重检查锁定) public static DoubleCheckedLockingSingleton getInstance() { if (instance == null) { synchronized (DoubleCheckedLockingSingleton.class) { if (instance == null) { instance = new DoubleCheckedLockingSingleton(); } } } return instance; } }3、异同点
相同点: 两者都是单例模式的实现方式。都提供了全局访问点来获取类的唯一实例。 不同点: 实例创建时机:饿汉模式在类加载时就创建实例,而饱汉模式在第一次调用getInstance()方法时才创建实例。资源消耗:饿汉模式可能会浪费资源(如果实例从未被使用过),而饱汉模式节省了资源。线程安全性:饿汉模式是线程安全的(因为实例在类加载时就创建了),而未经同步处理的饱汉模式不是线程安全的(可能会导致多个实例被创建)。但是,通过添加同步机制或使用双重检查锁定,可以使饱汉模式变得线程安全。在Spring框架中,单例Bean的创建通常是由Spring容器管理的,而不是通过饿汉模式或饱汉模式来实现的。Spring容器负责确保每个单例Bean在容器中只有一个实例,并提供依赖注入机制来访问这些Bean。然而,Spring也支持懒加载(Lazy Initialization),这类似于饱汉模式中的延迟创建实例的概念,但它是通过Spring的配置来实现的,而不是通过单例模式本身的实现方式。
(抱歉,最近在面试,粗糙了些。)
(望各位潘安、各位子健/各位彦祖、于晏不吝赐教!多多指正!🙏)
简识Spring创建Bean方式和设计模式由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“简识Spring创建Bean方式和设计模式”