Spring Boot 在自定义类中使用组件? [关闭]

Posted

技术标签:

【中文标题】Spring Boot 在自定义类中使用组件? [关闭]【英文标题】:Spring Boot use component in a custom class? [closed] 【发布时间】:2021-10-03 19:02:12 【问题描述】:

我有一个 redis 工具:

@Component
public class RedisUtil 


    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    public StringRedisTemplate getStringRedisTemplate() 
        return this.stringRedisTemplate;
    

我想在我不想成为组件的自定义类中使用它。

public class UserFeature 
    
    public String result;

    public String someMethod()
        var redisUtil = new RedisUtil();
        var stringRedisTemplate = redisUtil.getStringRedisTemplate();
        ...
        this.result = query_result_from_stringRedisTemplate;
    

当我像上面那样使用它时,它会引发一个 bean 错误。 我该怎么办?

【问题讨论】:

你为什么不在UserFeature中注入RedisUtil 你有什么理由让UserFeature 不是一个组件? UserFeature 有其他可以修改的属性 当我更改代码时会引发错误 - 告诉我们错误是什么。 【参考方案1】:

如果您有充分的理由创建不应由 spring 管理的对象,但仍需要使用 spring bean,则可以创建一个工厂组件,将 spring bean 注入到非 spring 对象中。

@Component
class UserFeatureFactory 
private final RedisUtil redisUtil;
  @Autowired
  public UserFeatureFactory(RedisUtil redisUtil)  ... 

  public UserFeature createUserFeature() 
    return new UserFeature(redisUtil);
  


// no spring annotations
class UserFeature 
  ...
  public UserFeature(RedisUtil redisUtil) 
    this.redisUtil = redisUtil
  
  ...

这种方法的一个很好的特点是它使UserFeature 易于测试——您只需向其构造函数传递一个模拟RedisUtil

【讨论】:

有更好的方法吗?这意味着我应该在所有使用 RedisUtil 的工厂函数中添加一个参数 ... 请注意,如果确实有必要,将这种依赖关系表达为Supplier<Foo>Function<String, Foo> 或其他名称通常是个好主意。 这很快就会变得非常乏味,但取决于必须创建的此类类的数量。 @DachuanZhao 我不太清楚你的意思?【参考方案2】:

如果由于某种原因您不能将 UserFeature 转换为组件,一般的方法是使用一个帮助程序 @Component 类,该类提供从非 Spring POJO 对 Spring bean 的访问。

@Component
public class SpringBeansProvider implements ApplicationContextAware 
     
    private static ApplicationContext context;
     
    public static <T> T getBean(String name, Class<T> beanClass) 
        return context.getBean(name, beanClass);
    
     
    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException 
        SpringBeansProvider.context = context;
    

然后您可以向 Spring 容器请求 RedisUtil bean 实例:

public class UserFeature 
    // ...
    public String someMethod() 
        RedisUtil redisUtil = SpringBeansProvider.getBean("redisUtil", RedisUtil.class);
        // ...
    

此方法还允许您通过使用特定于 bean 的 getter 代替 getBean(),轻松限制非 Spring 托管类可以访问哪些 Spring bean。

public static RedisUtil getRedisUtil() 
    return context.getBean("redisUtil", RedisUtil.class);


public String someMethod() 
    RedisUtil redisUtil = SpringBeansProvider.getRedisUtil();
    // ...

【讨论】:

这种方法在各个方面都更糟糕:静态、隐藏的依赖关系以及与 Spring 上下文的紧密语义耦合。 @chrylis-cautiouslyoptimistic- 控制对 private 静态的访问,没有隐藏的依赖项——事实上,在非 Spring 代码为以后访问 Spring bean 的情况下,代码变成了自记录的审查。【参考方案3】:

从 Spring 4.3 开始,类不需要任何 Spring 注释即可进行注入。只需包含一个构造函数。 (Lombok @RequiredArgsConstructor 可以为您做到这一点,它内置在 Groovy 和 Kotlin 中。)

public class MyNotComponent 
  private final MyComponent component;

  public MyNotComponent(MyComponent component) 
    this.component = component;
  

【讨论】:

假设非 Spring 类还没有其他构造函数过于简单。

以上是关于Spring Boot 在自定义类中使用组件? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

面试官:如何在自定义端口上运行 Spring Boot 应用程序?

在自定义组件中获取spring底层组件

如何在自定义反序列化器 Spring Boot 中读取路径变量或 URL 参数

无法在 Spring Boot 的组件类中自动装配推土机 Mapper

spring boot 自动配置

Spring Boot使用@Schedule启动、停止服务