Using Spring IoC to set up enum values

后端 未结 13 2008
名媛妹妹
名媛妹妹 2020-11-30 06:06

Is there a way to set up such enum values via Spring IoC at construction time?

What I would like to do is to inject, at class load time, values that are hard-coded i

13条回答
  •  悲&欢浪女
    2020-11-30 06:21

    OK, it's quite fiddly, but it CAN be done.

    It's true that Spring cannot instantiate enums. But that's not a problem - Spring can also use factory methods.

    This is the key component:

    public class EnumAutowiringBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
        private final List> enumClasses = new ArrayList<>();
    
        public EnumAutowiringBeanFactoryPostProcessor(Class... enumClasses) {
            Collections.addAll(this.enumClasses, enumClasses);
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            for (Class enumClass : enumClasses) {
                for (Enum enumVal : enumClass.getEnumConstants()) {
                    BeanDefinition def = new AnnotatedGenericBeanDefinition(enumClass);
                    def.setBeanClassName(enumClass.getName());
                    def.setFactoryMethodName("valueOf");
                    def.getConstructorArgumentValues().addGenericArgumentValue(enumVal.name());
                    ((BeanDefinitionRegistry) beanFactory).registerBeanDefinition(enumClass.getName() + "." + enumVal.name(), def);
                }
            }
        }
    }
    

    Then the following test class shows that it works:

    @Test
    public class AutowiringEnumTest {
    
        public void shouldAutowireEnum() {
            new AnnotationConfigApplicationContext(MyConig.class);
    
            assertEquals(AutowiredEnum.ONE.myClass.field, "fooBar");
            assertEquals(AutowiredEnum.TWO.myClass.field, "fooBar");
            assertEquals(AutowiredEnum.THREE.myClass.field, "fooBar");
        }
    
        @Configuration
        public static class MyConig {
    
            @Bean
            public MyClass myObject() {
                return new MyClass("fooBar");
            }
    
            @Bean
            public BeanFactoryPostProcessor postProcessor() {
                return new EnumAutowiringBeanFactoryPostProcessor(AutowiredEnum.class);
            }
        }
    
        public enum AutowiredEnum {
            ONE,
            TWO,
            THREE;
    
            @Resource
            private MyClass myClass;
    
        }
    
        public static class MyClass {
    
            private final String field;
    
            public MyClass(String field) {
                this.field = field;
            }
       }
    
    }
    

提交回复
热议问题