skip to Main Content

I have a redis util :

@Component
public class RedisUtil {


    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    public StringRedisTemplate getStringRedisTemplate() {
        return this.stringRedisTemplate;
    }
}

I want to use it in my custom class which I don’t want to be a component .

public class UserFeature {
    
    public String result;

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

When I use it like above , it raises a bean error .
What should I do ?

3

Answers


  1. If you have a good reason for creating objects which shouldn’t be spring-managed, but still need to use spring beans, you can create a factory component which does the injection of spring beans into your non-spring object.

    @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
      }
      ...
    }
    

    One nice feature of this approach is that it makes UserFeature easy to test — you can just pass its constructor a mock RedisUtil.

    Login or Signup to reply.
  2. If for some reason you can’t turn UserFeature into a component, a general approach is to have a helper @Component class that provides access to Spring beans from non-Spring POJOs.

    @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;
        }
    }
    

    Then you can ask the Spring container for the RedisUtil bean instance as:

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

    This approach also lets you easily restrict which Spring beans can be accessed by non-Spring managed classes by having bean-specific getters in place of getBean().

    public static RedisUtil getRedisUtil() {
        return context.getBean("redisUtil", RedisUtil.class);
    }
    
    public String someMethod() {
        RedisUtil redisUtil = SpringBeansProvider.getRedisUtil();
        // ...
    }
    
    Login or Signup to reply.
  3. As of Spring 4.3, classes don’t need to have any Spring annotations whatsoever to be eligible for injection. Simply include a single constructor. (Lombok @RequiredArgsConstructor can do this for you, and it’s built into Groovy and Kotlin.)

    public class MyNotComponent {
      private final MyComponent component;
    
      public MyNotComponent(MyComponent component) {
        this.component = component;
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search