java - 在@bean 工厂方法上使用自定义注解

标签 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。

我不确定这样做是否会违反任何 spring 原则,或者这是否是常规做法。

我的初衷是工作。 但是我现在有另一个问题。 我无法使用我想要的类型 Autowiring 来 self 想要的工厂的 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);
        }

    }

最佳答案

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

关于java - 在@bean 工厂方法上使用自定义注解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34839323/

相关文章:

java - 如何在一个界面中创建2个或多个不同的RMI远程对象?(工厂模式)

java - 将监听器附加到 JTree

java - Spring-MVC 正在向用户输入的 URL 添加额外的 .jsp 扩展名

java - Spring Maven 和 Tomcat 的 Hibernate 问题

java - 通过循环中的模块更改变量(java)

java - SOLR 性能调整

java - Json对象和Spring Controller 客户端发送的请求在语法上不正确(错误的请求)

spring - 找不到 org.apache.solr.client.solrj.embedded.EmbeddedSolrServer 的类文件

spring - 为什么 @Autowired 在 @Configuration 内部时无需 @Component 即可工作

索引处的 Java Streams API 汇总列表