Spring 实例化bean有几种方式?

Spring 实例化 Bean 是 IoC 容器的核心能力之一,主要有 6 种常见方式,我会从新手易懂的角度,由基础到进阶逐一讲解,并配合代码示例,让你清晰理解每种方式的使用场景和实现逻辑。

一、核心实例化方式(附代码示例)

1. 构造器实例化(最常用)

这是 Spring 默认的实例化方式,IoC 容器通过调用 Bean 的无参构造器创建实例(如果有参构造器,需通过配置指定参数)。

  • 适用场景:绝大多数普通业务 Bean(如 Service、Controller)。

  • 代码示例:

    复制代码
    // 1. 定义普通类(无参构造器默认存在,无需显式写)
    public class UserService {
        public UserService() {
            System.out.println("UserService 无参构造器执行");
        }
        
        public void sayHello() {
            System.out.println("Hello, Spring!");
        }
    }
    
    // 2. Spring 配置(XML 方式)
    <!-- applicationContext.xml -->
    <bean id="userService" class="com.example.UserService"/>
    
    // 3. 测试代码
    public class Test {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserService userService = (UserService) context.getBean("userService");
            userService.sayHello(); // 输出:UserService 无参构造器执行 + Hello, Spring!
        }
    }

    如果是有参构造器,XML 配置需指定参数:

    xml

    复制代码
    <!-- 有参构造器实例化 -->
    <bean id="userService" class="com.example.UserService">
        <constructor-arg value="张三"/> <!-- 对应构造器的参数 -->
    </bean>
2. 静态工厂方法实例化

通过调用静态方法返回 Bean 实例,适用于需要统一控制实例创建逻辑的场景(如工具类、单例对象)。

  • 适用场景:第三方类库、自定义单例工厂。

  • 代码示例:

    复制代码
    // 1. 定义工厂类(包含静态方法)
    public class UserServiceFactory {
        // 静态工厂方法,返回 UserService 实例
        public static UserService createUserService() {
            return new UserService();
        }
    }
    
    // 2. Spring 配置
    <bean id="userService" class="com.example.UserServiceFactory" 
          factory-method="createUserService"/> <!-- 指定静态工厂方法 -->
    
    // 3. 测试(和构造器方式一致,Spring 会调用 createUserService() 创建实例)
3. 实例工厂方法实例化

通过调用非静态方法(即先创建工厂 Bean 实例,再调用其方法)返回 Bean 实例,适用于工厂类需要维护状态的场景。

  • 适用场景:工厂类需要依赖其他 Bean、或需要多实例工厂。

  • 代码示例:

    复制代码
    // 1. 定义实例工厂类(非静态方法)
    public class UserServiceInstanceFactory {
        public UserService createUserService() {
            return new UserService();
        }
    }
    
    // 2. Spring 配置(先定义工厂 Bean,再通过工厂 Bean 调用方法)
    <bean id="userServiceFactory" class="com.example.UserServiceInstanceFactory"/>
    <bean id="userService" factory-bean="userServiceFactory" 
          factory-method="createUserService"/>
4. FactoryBean 接口实例化(进阶)

这是 Spring 提供的专用工厂接口(注意和上面的 "工厂方法" 区分),实现该接口可以自定义 Bean 的创建逻辑,还能控制 Bean 的初始化、销毁。

  • 核心方法:

    • getObject():返回 Bean 实例;
    • getObjectType():返回 Bean 的类型;
    • isSingleton():是否单例(默认 true)。
  • 适用场景:复杂对象创建(如数据源、MyBatis 的 SqlSessionFactory)。

  • 代码示例:

    复制代码
    // 1. 实现 FactoryBean 接口
    public class UserServiceFactoryBean implements FactoryBean<UserService> {
        @Override
        public UserService getObject() throws Exception {
            return new UserService(); // 自定义创建逻辑
        }
    
        @Override
        public Class<?> getObjectType() {
            return UserService.class;
        }
    
        // 可选:指定是否单例(默认 true)
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    
    // 2. Spring 配置
    <bean id="userService" class="com.example.UserServiceFactoryBean"/>
    
    // 3. 测试(Spring 会自动调用 getObject() 获取实例)
5. 注解驱动实例化(主流)

基于注解的方式是现代 Spring 开发的主流,替代 XML 配置,核心注解包括:

  • @Component:通用注解(标注普通 Bean);

  • @Service:标注业务层 Bean;

  • @Controller:标注控制层 Bean;

  • @Repository:标注数据访问层 Bean;

  • @Configuration + @Bean:标注配置类,通过方法返回 Bean 实例。

  • 代码示例(@Component 方式):

    复制代码
    // 1. 标注注解
    @Service // 等同于在 XML 中定义 Bean
    public class UserService {
        public void sayHello() {
            System.out.println("Hello, Annotation!");
        }
    }
    
    // 2. 开启注解扫描(XML 或配置类)
    <!-- XML 方式开启扫描 -->
    <context:component-scan base-package="com.example"/>
    
    // 或配置类方式(推荐)
    @Configuration
    @ComponentScan("com.example") // 扫描指定包下的注解 Bean
    public class SpringConfig {}
    
    // 3. 测试
    public class Test {
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
            UserService userService = context.getBean(UserService.class);
            userService.sayHello(); // 输出:Hello, Annotation!
        }
    }
  • 代码示例(@Configuration + @Bean 方式):

    复制代码
    // 1. 配置类中定义 Bean
    @Configuration
    public class SpringConfig {
        // 方法返回值即为 Bean 实例,方法名默认是 Bean 的 id
        @Bean
        public UserService userService() {
            return new UserService();
        }
    }
    
    // 2. 测试(直接获取 Bean)
6. 通过 BeanDefinition 手动实例化(底层)

这是最底层的方式,直接操作 Spring 的 BeanDefinition(Bean 的定义元数据),通过编程式方式向容器注册 Bean,适用于框架开发或动态创建 Bean。

  • 适用场景:自定义 Spring 扩展、动态生成 Bean。

  • 代码示例:

    复制代码
    public class Test {
        public static void main(String[] args) {
            // 1. 创建 BeanFactory 容器
            DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
            
            // 2. 构建 BeanDefinition(定义 Bean 的元数据)
            BeanDefinition beanDefinition = BeanDefinitionBuilder
                    .genericBeanDefinition(UserService.class)
                    .getBeanDefinition();
            
            // 3. 注册 BeanDefinition 到容器
            beanFactory.registerBeanDefinition("userService", beanDefinition);
            
            // 4. 获取 Bean 实例
            UserService userService = beanFactory.getBean("userService", UserService.class);
            userService.sayHello();
        }
    }

二、不同方式的使用场景总结

表格

实例化方式 核心特点 适用场景
构造器实例化 简单、默认支持 普通业务 Bean(无复杂创建逻辑)
静态工厂方法 统一控制实例创建 第三方类库、单例对象
实例工厂方法 工厂可维护状态、依赖其他 Bean 需多实例工厂、工厂依赖注入
FactoryBean 接口 自定义创建逻辑、控制初始化 复杂对象(数据源、SqlSessionFactory)
注解驱动实例化 简洁、主流 现代 Spring 项目(Spring Boot)
BeanDefinition 手动 底层、灵活 框架开发、动态创建 Bean

总结

  1. 日常开发优先用注解@Service/@Controller/@Bean 是 Spring Boot 主流,简洁高效;
  2. 基础方式是构造器:Spring 默认通过无参构造器实例化 Bean,是所有方式的基础;
  3. 复杂场景用工厂FactoryBean 适合复杂对象创建,静态 / 实例工厂适合统一控制实例逻辑。

核心记住:Spring 实例化 Bean 的本质是 IoC 容器根据 Bean 的定义(XML / 注解 / BeanDefinition),调用对应的创建逻辑(构造器 / 工厂方法)生成实例,最终将实例存入容器供使用。

相关推荐
大鸡腿同学10 小时前
从 CoT 思维链到 ReAct:智能 Agent 到底是怎么 “思考” 的?
后端
IT_陈寒11 小时前
Vite的静态资源打包让我熬夜到三点,这坑千万别跳
前端·人工智能·后端
小bo波12 小时前
使用Thread子类创建线程 VS 使用Runnable接口创建线程的区别
java·多线程·thread·并发编程·runnable
SamDeepThinking12 小时前
高并发场景下,CompletableFuture与ForkJoinPool该如何取舍?
java·后端·面试
Asize13 小时前
多模态生图:从 Vite 工程化到前端调用 Qwen Image
javascript·人工智能·后端
java小白小13 小时前
SpringBoot(09):缓存实战——穿透、雪崩、击穿的解决方案
后端
java小白小13 小时前
SpringBoot(08):Redis 集成——5 分钟给你的项目加上缓存
后端
LiuMingXin13 小时前
意图与代码之间:AI编程范式全景解读
前端·后端·面试
用户342323237631714 小时前
边缘计算与云边协同——当采集不再只是“上传“
后端
壹方秘境14 小时前
ApiCatcher支持抓包HTTP传输大文件的实现原理分享
前端·后端·客户端