You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring如何基于URL参数动态创建运行时Bean并自动注入Access类

解决方案

首先明确核心前提:Spring默认的单例Bean依赖注入是容器启动阶段完成的,你当前写法的问题在于Access如果是默认单例Bean,启动时就会尝试注入Student实例,此时还没有用户请求生成参数,必然会注入失败,且单例Bean的依赖注入完成后不会自动更新。你可以按照以下步骤实现需求:


步骤1:在控制器中动态注册Student Bean

先改造FunRestController,注入Spring上下文,拿到请求参数后手动创建Student实例并注册到IoC容器:

@RestController
public class FunRestController {
    // 注入Spring上下文
    @Autowired
    private ApplicationContext context;

    @GetMapping("/{id}/{name}")
    public String welcomeToBoot(@PathVariable int id, @PathVariable String name) {
        // 1. 用请求参数创建Student实例
        Student student = new Student(id, name);
        // 2. 获取BeanFactory用于动态注册Bean
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getAutowireCapableBeanFactory();
        // 3. 若已存在同名Bean先移除,避免重复注册报错
        if (beanFactory.containsBean("student")) {
            beanFactory.removeBeanDefinition("student");
        }
        // 4. 注册Student为单例Bean
        beanFactory.registerSingleton("student", student);
        return "Welcome " + name;
    }
}

步骤2:改造Access类适配动态Bean

有两种可选方案,根据你的业务场景选择:

方案A:将Access改为请求作用域(推荐无并发冲突场景)

每次请求生成新的Access实例,注入当前请求对应的Student:

// 加@Component交给Spring管理,加@RequestScope设置为请求作用域
@Component
@RequestScope
public class Access {
    @Autowired
    Student s;
    
    void print() {
        System.out.println(s.name);
    }
}

方案B:动态从容器中获取Student(推荐Access需要保持单例的场景)

不提前注入Student,每次调用方法时实时从容器拉取最新实例:

@Component
public class Access {
    @Autowired
    private ApplicationContext context;
    
    void print() {
        // 实时获取最新的Student实例
        Student s = context.getBean(Student.class);
        System.out.println(s.name);
    }
}

并发场景优化建议

如果是多用户同时访问的场景,直接注册单例Student会出现后请求的参数覆盖前一个的问题,此时更推荐直接将Student声明为请求作用域Bean,不需要手动动态注册:

@Component
@RequestScope
public class Student {
    public int id;
    public String name;
    // 补充无参构造和setter方法
    public Student() {}
    public void setId(int id) {this.id = id;}
    public void setName(String name) {this.name = name;}
}

在控制器中直接注入Student赋值即可:

@RestController
public class FunRestController {
    @Autowired
    private Student student;

    @GetMapping("/{id}/{name}")
    public String welcomeToBoot(@PathVariable int id, @PathVariable String name) {
        student.setId(id);
        student.setName(name);
        return "Welcome " + name;
    }
}

内容的提问来源于stack exchange,提问作者Ramu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 10:24:05