Accessing spring beans in static method

前端 未结 8 585
清酒与你
清酒与你 2020-12-23 16:17

I have a Util class with static methods. Inside my Util class, I want to use spring beans so I included them in my util class. As far as I know it\'s not a good practice to

8条回答
  •  隐瞒了意图╮
    2020-12-23 17:03

    Generic Solution

    You can create a class that will allow access to any Bean from a static context. Most other answers here only show how to access a single class statically.

    The Proxy in the code below was added in case someone calls the getBean() method before the ApplicationContext is autowired (as this would result in a nullpointer). None of the other solutions posted here handle that nullpointer.

    Details on my blog: https://tomcools.be/post/apr-2020-static-spring-bean/

    Usage

    UserRepository userRepo = StaticContextAccessor.getBean(UserRespository.class)
    

    Full code of the StaticContextAccessor:

    @Component
    public class StaticContextAccessor {
    
        private static final Map classHandlers = new HashMap<>();
        private static ApplicationContext context;
    
        @Autowired
        public StaticContextAccessor(ApplicationContext applicationContext) {
            context = applicationContext;
        }
    
        public static  T getBean(Class clazz) {
            if (context == null) {
                return getProxy(clazz);
            }
            return context.getBean(clazz);
        }
    
        private static  T getProxy(Class clazz) {
            DynamicInvocationhandler invocationhandler = new DynamicInvocationhandler<>();
            classHandlers.put(clazz, invocationhandler);
            return (T) Proxy.newProxyInstance(
                    clazz.getClassLoader(),
                    new Class[]{clazz},
                    invocationhandler
            );
        }
    
        //Use the context to get the actual beans and feed them to the invocationhandlers
        @PostConstruct
        private void init() {
            classHandlers.forEach((clazz, invocationHandler) -> {
                Object bean = context.getBean(clazz);
                invocationHandler.setActualBean(bean);
            });
        }
    
        static class DynamicInvocationhandler implements InvocationHandler {
    
            private T actualBean;
    
            public void setActualBean(T actualBean) {
                this.actualBean = actualBean;
            }
    
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (actualBean == null) {
                    throw new RuntimeException("Not initialized yet! :(");
                }
                return method.invoke(actualBean, args);
            }
        }
    }
    

提交回复
热议问题