【问题标题】:How to disable Spring autowiring for a certain bean?如何禁用某个 bean 的 Spring 自动装配?
【发布时间】:2017-01-26 18:15:00
【问题描述】:

jar(外部库)中有一些类在内部使用 Spring。 所以库类的结构如下:

@Component
public class TestBean {

    @Autowired
    private TestDependency dependency;

    ...
}

并且库提供了构造对象的API:

public class Library {

    public static TestBean createBean() {
        ApplicationContext context = new AnnotationConfigApplicationContext(springConfigs);
        return context.getBean(TestBean);
    }
}

在我的应用程序中,我有配置:

@Configuration
public class TestConfig {

    @Bean
    public TestBean bean() {
        return Library.createBean();
    }
}

抛出异常:Field dependency in TestBean required a bean of type TestDependency that could not be found.

但是 Spring 不应该尝试注入一些东西,因为 bean 已经配置好了。

我可以为某个 bean 禁用 Spring 自动装配吗?

【问题讨论】:

  • 你怎么知道bean已经配置好?
  • 既然Library.createBean() 正在创建你的对象,你为什么要把@Autowired 放在TestDependency 上面
  • 不是我。这是一个库源代码。
  • @randominstanceOfLivingThing,因为Library.createBean 内部使用了 Spring。
  • 可能是组件扫描类路径中找不到TestDependency?

标签: java spring spring-boot


【解决方案1】:

根据@Juan 的回答,创建了一个帮助器来包装不自动装配的 bean:

public static <T> FactoryBean<T> preventAutowire(T bean) {
    return new FactoryBean<T>() {
        public T getObject() throws Exception {
            return bean;
        }

        public Class<?> getObjectType() {
            return bean.getClass();
        }

        public boolean isSingleton() {
            return true;
        }
    };
}

...

@Bean
static FactoryBean<MyBean> myBean() {
    return preventAutowire(new MyBean());
}

【讨论】:

  • 诀窍奏效。但请注意,bean 不会被代理包装,即启用 @Validated@Transactional 的效果
【解决方案2】:

这对我有用:

import org.springframework.beans.factory.FactoryBean;  
...  
@Configuration
public class TestConfig {

    @Bean
    public FactoryBean<TestBean> bean() {
        TestBean bean = Library.createBean();

        return new FactoryBean<TestBean>()
        {
            @Override
            public TestBean getObject() throws Exception
            {
                return bean;
            }

            @Override
            public Class<?> getObjectType()
            {
                return TestBean.class;
            }

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

【讨论】:

    【解决方案3】:

    似乎无法禁用特定 bean 的自动装配。

    所以有一些解决方法。 我们可以为目标 bean 制作包装器并使用它来代替原始 bean:

    public class TestBeanWrapper {
    
        private final TestBean bean;
    
        public TestBeanWrapper(TestBean bean) {
            this.bean = bean;
        }
    
        public TestBean bean() {
            return bean;
        }
    }
    
    @Configuration
    public class TestConfig {
    
        @Bean
        public TestBeanWrapper bean() {
            return new TestBeanWrapper(Library.createBean());
        }
    }
    
    @RestController
    public class TestController {
    
        @Autowired
        private TestBeanWrapper bean;
    
        ...
    }
    

    【讨论】:

      【解决方案4】:

      不完全是,但您可以在自动装配注释中添加 required=false (@Autowired(required=false))。但要小心,这可能会让你出现 NullPointer 异常

      【讨论】:

      • 我不能。 TestBean 这是一个来自库源代码的类。
      • 恐怕你必须通过 XML 方法为 TestDependency 创建 bean 并将其标记为 autowire-candidate=false 然后它不会考虑自动装配
      • 如果我标记@Autowired(require = false) 那么它会一直为空还是会尝试自动连接它,如果失败就继续?
      • @jDub9:查看asg的评论IMO - problem is spring context created by TestConfig and Library, both are different. Also if you wanna load third party components into your system, best way is to configure it xml files instead of loading using component-scan.你需要在你的库的扫描包xml文件中导入
      猜你喜欢
      • 2012-08-11
      • 1970-01-01
      • 2014-11-18
      • 2016-09-27
      • 1970-01-01
      • 1970-01-01
      • 2012-12-30
      • 2022-08-20
      • 1970-01-01
      相关资源
      最近更新 更多