在@bean工厂方法上使用自定义注释

时间:2016-01-17 14:15:41

标签: java spring

我可以直接在类上使用@CustomAnnotation,并使用BeanFactoryPostProcessor将注释bean的bean定义更改为我的需要。

    @CustomAnnotation
    public class MyBean implements IMybean{
    }

    @Configuration
    public class MyConfiguration {

       @Bean
        public MyBean myBean(){
            return new myBean();
        }

    }

我想要做的是将@CustomAnnotation放在配置文件的@Bean方法上,如下所示:

    public class MyBean implements IMybean{
    }

    @Configuration
    public class MyConfiguration {

        @Bean
        @CustomAnnotation
        public MyBean myBean(){
            return new myBean();
        }

     }

从BeanDefinition我可以从beanFactory获得,我知道我可以获得工厂bean和创建myBean的工厂方法,并检查方法上是否有@CustomAnnotation。

我不确定这样做是否会破坏任何弹簧原则,或者这是否是常规事情。

我的初衷是有效的。 但是我现在有另一个问题。 我无法使用我想要的类型自动装配来自我想要的工厂的bean。 解决依赖关系存在问题。 这是我用来尝试解决问题的测试代码。 test code on github

@Configuration
public class MainConfiguration implements BeanDefinitionRegistryPostProcessor, Ordered {

    private SayenBeanDefinitionRegistryPostProcessor sayenBeanDefinitionRegistryPostProcessor = new SayenBeanDefinitionRegistryPostProcessor();

    public int getOrder() {
        return sayenBeanDefinitionRegistryPostProcessor.getOrder();
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        sayenBeanDefinitionRegistryPostProcessor.postProcessBeanFactory(beanFactory);
    }

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        sayenBeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(beanFactory);
    }

    @Bean
    public AutowiredBean autowiredBean() {
        return new AutowiredBean();
    }

    @Bean
    @Transform(type = MegaSuperKarim.class)
    public Karim Karim() {
        return new Karim();
    }

    @Bean
    @Transform(type = SuperGuillaume.class)
    public Guillaume Guillaume() {
        return new Guillaume();
    }

    @Bean
    public Yoann Yoann() {
        return new Yoann();
    }

    @Bean
    public Nicolas Nicolas() {
        return new Nicolas();
    }

    @Bean
    public BeanHolder beanHolder() {
        return new BeanHolder();
    }
}

public class TransformFactoryBean implements FactoryBean<Object> {

    @Autowired
    private AutowiredBean pouet;

    private Class<?> objectType;

    boolean singleton = true;

    @Override
    public Object getObject() throws Exception {
        return objectType.getConstructor().newInstance();
    }

    @Override
    public Class<?> getObjectType() {
        return objectType;
    }

    @Override
    public boolean isSingleton() {
        return singleton;
    }

    public void setObjectType(Class<?> objectType) {
        this.objectType = objectType;
    }

    public AutowiredBean getPouet() {
        return pouet;
    }

    public void setSingleton(boolean singleton) {
        this.singleton = singleton;
    }

}

public class SayenBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor, Ordered {

    private static Logger logger = LoggerFactory.getLogger(MainConfiguration.class);

    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        logger.debug("rien");
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        //DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) beanFactory;

        for (String originalBeanName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition originalBeanDefinition = beanFactory.getBeanDefinition(originalBeanName);
            logger.debug("original beanName=" + originalBeanName + ", " + originalBeanDefinition.toString());
            if (originalBeanDefinition.isAbstract()) {
                continue;
            }

            Transform sayenAnnotation = getMethodAnnotation(beanFactory, originalBeanDefinition);

            /*if (sayenAnnotation == null) {
                Class<?> originalBeanClass = beanFactory.getType(originalBeanName);
                sayenAnnotation = AnnotationUtils.findAnnotation(originalBeanClass, Transform.class);
                */if (sayenAnnotation == null) {
                    continue;
                }/*
            }*/

            Class<? extends Sayan> sayenClass = sayenAnnotation.type();

            RootBeanDefinition sayenFactoryBeanDefinition = new RootBeanDefinition(TransformFactoryBean.class, 3/*Autowire.BY_TYPE.value()*/, true);
            sayenFactoryBeanDefinition.getPropertyValues().add("objectType", sayenClass);
            sayenFactoryBeanDefinition.getPropertyValues().add("singleton", true);

            String factoryBeanName = originalBeanName;

            logger.debug("remove beanName=" + originalBeanName + ", " + originalBeanDefinition.toString());
            beanFactory.removeBeanDefinition(originalBeanName);

            logger.debug("register beanName=" + factoryBeanName + ", " + sayenFactoryBeanDefinition.toString());
            beanFactory.registerBeanDefinition(factoryBeanName, sayenFactoryBeanDefinition);

        }

    }

    private Transform getMethodAnnotation(BeanDefinitionRegistry beanFactory, BeanDefinition originalBeanDefinition) {
        String originalBeanFactoryBeanName = originalBeanDefinition.getFactoryBeanName();
        String originalBeanFactoryMethodName = originalBeanDefinition.getFactoryMethodName();

        if (originalBeanFactoryBeanName == null || originalBeanFactoryMethodName == null) {
            return null;
        }

        Class<?> originalBeanFactoryBeanClass = ClassUtils.getUserClass(((DefaultListableBeanFactory)beanFactory).getType(originalBeanFactoryBeanName));
        try {
            Method method = originalBeanFactoryBeanClass.getMethod(originalBeanFactoryMethodName);
            return AnnotationUtils.getAnnotation(method, Transform.class);
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

    }

1 个答案:

答案 0 :(得分:1)

如果@CustomAnnotation的唯一目的是影响类/ bean的创建方式,那么你采取了正确的方法。在这种情况下,注释的范围应该是在创建时(在@Configuration MyConfiguration中将其移动到的位置)而不是类范围(@Target(ElementType.TYPE))。 你有效地说@CustomAnnotation在创建后没有进一步用于MyBean,你的框架永远不会再需要检查MyBean这个注释。这也意味着@CustomAnnotation可能用于创建其他bean(MyBean2等)。