Threaded Beans не получает среду @AutoWired к ним весной при использовании провайдера JSR330

Надеюсь, что вопрос не требует пояснений

ClassA.java

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ClassA implements InterB {
    private static int counter=0;

    private int objectid = 0;
    @Autowired
    InterA abcd;

    public ClassA() {
        super();
        this.objectid = ++counter;
    }

    @Override
    public void dododo() {
        System.out.println("instance number "+objectid++);
        abcd.doit();
    }
}

ClassB.java

@Component
@Conditional(OracleDBEngineCondition.class)
public class ClassB extends DummyParent implements InterA {
    @Autowired
    private Environment env;

    @Override
    public void doit() {
        System.out.println("hoo hoo" +" -- "+env.getProperty("DBENGINE"));
    }

}

ClassC.java

@Component("classc")
public class ClassC implements Runnable {

    @Autowired
    Provider<InterB> classAPrototypeobj;

    public void doFromAbove() {
        InterB cls = (InterB) classAPrototypeobj.get();
        InterB cls1 = (InterB) classAPrototypeobj.get();
        cls.dododo();
        cls1.dododo();
        System.out.println(cls);
        System.out.println(cls1);

    }

    @Override
    public void run() {
        this.doFromAbove();
    }
}

ClassConfig.java

@Configuration
@ComponentScan
public class ClassConfig {
}

Основной метод

public static void main(String[] args) {
    ClassC obj;
    try(AbstractApplicationContext appctx = new AnnotationConfigApplicationContext(ClassConfig.class)) {
        obj = (ClassC) appctx.getBean("classc");
    }
    Thread objThread = new Thread(obj);
    objThread.start();
}

Обновлен основной метод (проблема остается той же)

public static void main(String[] args) {
    try(AbstractApplicationContext appctx = new AnnotationConfigApplicationContext(ClassConfig.class)) {
        ClassC obj = (ClassC) appctx.getBean("classc");
        Thread objThread = new Thread(obj);
        objThread.start();
    }
}

Когда выполнено, это вызывает NoSuchBeanDefinitionException для бобов "окружающая среда"

Но когда мы определяем следующее в нашем классе конфигурации, ошибка исчезает без следа. Это обходной путь (но Spring должен автоматически вводить окружение, мы не должны этого делать). Не уверен, сколько таких бобов не вводится /@Autowired

@Bean
public Environment environment(ApplicationContext context) {
    return context.getEnvironment();
}

Я подозреваю, что это ошибка Spring Framework... Не так ли?

Трассировки стека:

Exception in thread "Thread-1" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'classA': Unsatisfied dependency expressed through field 'abcd'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'classB': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'environment' available
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.getObject(DefaultListableBeanFactory.java:1630)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory$Jsr330DependencyProvider.get(DefaultListableBeanFactory.java:1699)
    at tpt.verifypoc.ClassC.doFromAbove(ClassC.java:28)
    at tpt.verifypoc.ClassC.run(ClassC.java:39)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'classB': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'environment' available
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:372)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
    ... 14 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'environment' available
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1207)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$ShortcutDependencyDescriptor.resolveShortcut(AutowiredAnnotationBeanPostProcessor.java:740)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1077)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.resolvedCachedArgument(AutowiredAnnotationBeanPostProcessor.java:548)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.access$200(AutowiredAnnotationBeanPostProcessor.java:117)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:577)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
    ... 25 more

Замечания:

  1. Весна: 4.3.9. РЕЛИЗ
  2. JSR330: версия javax.inject 1

1 ответ

Я бы сказал, что это не ошибка в Spring при просмотре вашего кода, прежде чем вы начнете использовать объекты, которые закрываете ApplicationContext, Или на самом деле блок проб с ресурсами, который у вас есть, делает это.

public static void main(String[] args) {
    ClassC obj;
    try(AbstractApplicationContext appctx = new AnnotationConfigApplicationContext(ClassConfig.class)) {
        obj = (ClassC) appctx.getBean("classc");
    }
    Thread objThread = new Thread(obj);
    objThread.start();
}

В основном так же, как

public static void main(String[] args) {
    ClassC obj;
    AbstractApplicationContext appctx = new AnnotationConfigApplicationContext(ClassConfig.class)) {
        obj = (ClassC) appctx.getBean("classc");

    appctx.close();

    Thread objThread = new Thread(obj);
    objThread.start();
}

Вы закрываете ApplicationContext прежде чем использовать объекты. То, что остается, является экземпляром ClassC с половинным прокси Provided<ClassB> который нуждается в контексте для поиска определенных бобов. Тем не менее, он не может искать эти компоненты, когда вы извлекаете реестр из-под него.

Когда вы закрываете ApplicationContext Вы закрываете свое приложение. Я ожидаю, что ваши объекты, которые все еще живут, теперь недействительны, потому что контейнер, к которому они принадлежат, уничтожен.

Сравните код с кодом JDBC. Вы открываете Connectionзакройте соединение и попробуйте подготовить заявление о закрытом соединении. JDBC не допустит этого, потому что Connection закрыт и, таким образом, недействителен.

Сравните это с Microsoft Excel, вы открываете его, работаете в листе, пишете макрос. Закройте Excel и ожидайте, что макрос еще будет работать.

Другие вопросы по тегам