怎么“访问”Spring容器管理的bean?

一、前言

二、使用场景

1、场景demo

public interface IModel {
    String acquireModelName();

    void sayHello();
}

@Component
public class GeminiModel implements IModel {
    @Override
    public String acquireModelName() {
        return ModelEnum.GEMINI.name();
    }

    @Override
    public void sayHello() {
        System.out.println("Hello, I am GeminiModel");
    }
}

@Component
public class GptModel implements IModel {
    @Override
    public String acquireModelName() {
        return ModelEnum.GPT.name();
    }

    @Override
    public void sayHello() {
        System.out.println("Hello, I am GptModel");
    }
}

@Component
public class ModelManager {
    @Autowired
    private List<IModel> models;

    public IModel acquireModel(String modelName) {
        if (CollectionUtils.isNotEmpty(models)) {
            return models.stream()
                    .filter(model -> StringUtils.equals(modelName, model.acquireModelName()))
                    .findFirst()
                    .orElseThrow(() -> new RuntimeException("no model"));
        } else {
            throw new RuntimeException("no model");
        }
    }
}

public enum ModelEnum {
    GPT, GEMINI;
}

@ComponentScan
public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Application.class);
        ModelManager modelManager = applicationContext.getBean(ModelManager.class);
        IModel model = modelManager.acquireModel(ModelEnum.GPT.name());
        model.sayHello();
    }
}

2、在上述场景demo中,直接注入依赖并不是最佳实践

  • 我实际需要的是:
Map<String, IModel> modelMap;

key: modelName
  • 虽然Spring可以注入Map,但是,key为bean的默认名字。【详见:正确使用@Autowired
  • 因此,我更好的做法是:先从Spring容器中获取IModel的实现类的bean,然后,建立modelMap。
  • 代码:
@Component
public class ModelManager implements ApplicationContextAware {
    private static final Map<String, IModel> MODEL_MAP = new HashMap<>();
    private ApplicationContext applicationContext;

    @PostConstruct
    private void buildModelMap() {
        Map<String, IModel> beansOfType = applicationContext.getBeansOfType(IModel.class);
        beansOfType.forEach((k, v) -> MODEL_MAP.put(v.acquireModelName(), v));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public IModel acquireModel(String modelName) {
        return Optional.ofNullable(MODEL_MAP.get(modelName))
                .orElseThrow(() -> new RuntimeException("no model"));
    }
}

三、获取Spring容器的方法

1、覆写ApplicationContextAware的setApplicationContext方法

  • 如上文所述,通过该方法可以获取到Spring容器(applicationContext)
  • 但有个难受的问题:
setApplicationContext方法必须是public。覆写方法,访问修饰符不能变“小”。
接口定义的setApplicationContext方法的访问修饰符是public,那么覆写时,只能用public。

这就意味着,使用modelManager时,可以把applicationContext设置为null。
虽然对上文没影响(因为获取modelManager时,applicationContext已经被使用过了,后续不会再用了),但是,一旦后续还会使用,那么就会有npe风险。

public IModel acquireModel(String modelName) {
	System.out.println(applicationContext.getDisplayName()); // 这里会npe
	...
}
@PostConstruct注解就很香,作用的方法[buildModelMap()]的访问修饰符可以是private

2、直接通过@Autowired注入ApplicationContext

@Component
public class ModelManager {
    private static final Map<String, IModel> MODEL_MAP = new HashMap<>();

    @Autowired
    private ApplicationContext applicationContext;

    @PostConstruct
    private void buildModelMap() {
        Map<String, IModel> beansOfType = applicationContext.getBeansOfType(IModel.class);
        beansOfType.forEach((k, v) -> MODEL_MAP.put(v.acquireModelName(), v));
    }

    public IModel acquireModel(String modelName) {
        return Optional.ofNullable(MODEL_MAP.get(modelName))
                .orElseThrow(() -> new RuntimeException("no model"));
    }
}

相关推荐

  1. 怎么访问Spring容器管理bean

    2024-04-12 09:34:03       19 阅读
  2. 关于Spring Bean容器理解

    2024-04-12 09:34:03       34 阅读
  3. spring基于xmlbean管理总结

    2024-04-12 09:34:03       46 阅读
  4. 关于Spring管理Bean杂谈

    2024-04-12 09:34:03       31 阅读
  5. spring管理bean

    2024-04-12 09:34:03       11 阅读
  6. 使用SpringContextHolder获取 Spring 容器 Bean

    2024-04-12 09:34:03       25 阅读
  7. Spring框架-Spring Bean管理

    2024-04-12 09:34:03       30 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-12 09:34:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-12 09:34:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-12 09:34:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-12 09:34:03       20 阅读

热门阅读

  1. 深入理解Vue 3中的自定义Hooks

    2024-04-12 09:34:03       57 阅读
  2. 弱者忍受孤独,强者享受孤独

    2024-04-12 09:34:03       18 阅读
  3. linux磁盘知识学习

    2024-04-12 09:34:03       18 阅读
  4. 简站WordPress主题:简洁、实用、无插件、更安全

    2024-04-12 09:34:03       18 阅读
  5. Web刷题记录——不翼而飞的余额

    2024-04-12 09:34:03       18 阅读
  6. 【CSS】三个DIV在同一行平分宽度的五种实现方法

    2024-04-12 09:34:03       17 阅读
  7. vue2和vue3 全选

    2024-04-12 09:34:03       14 阅读
  8. HarmonyOs开发之———页签切换、组件状态管理

    2024-04-12 09:34:03       16 阅读
  9. 如何保证数据库、缓存的双写一致?

    2024-04-12 09:34:03       16 阅读
  10. python实现OCR

    2024-04-12 09:34:03       17 阅读