8

その場合、どの構成が必要ですか? これはお勧めできませんか?

注釈付きクラス:

package com.springbug.beanfactorydependencyissue;

import javax.annotation.Resource;
import org.springframework.stereotype.Component;

@Component
public class DependantBean {

    @Resource
    DependencyBean dependencyBean; // Isn't initialized correctly

    public DependencyBean getDependencyBean() {
        return dependencyBean;
    }
}

失敗する依存関係 Bean:

package com.springbug.beanfactorydependencyissue;

import org.springframework.stereotype.Component;

@Component
public class DependencyBean {

}

テストケース:

package com.springbug.beanfactorydependencyissue;

import static org.fest.assertions.Assertions.assertThat;

import javax.annotation.Resource;

import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;

import com.springbug.beanfactorydependencyissue.DependantBean;

@ContextConfiguration(locations = "/applicationContext.xml")
public class AppTest extends AbstractTestNGSpringContextTests {

    @Resource
    private DependantBean annotatedBean;

    @Test
    public void testThatDependencyIsInjected() {
        // Fails as dependency injection of annotatedBean.dependencyBean does not work
        assertThat(annotatedBean.getDependencyBean()).isNotNull();
    }
}

「障害のある」依存関係を持つカスタム BeanFactoryPostProcessor:

package com.springbug.beanfactorydependencyissue;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanFactoryPostProcessorConfiguration {

    /**
     * The {@link DependantBean} here causes the bug, can
     * {@link BeanFactoryPostProcessor} have regular beans as dependencies?
     */
    @Bean
    public static BeanFactoryPostProcessor beanFactoryPostProcessor(
            DependantBean dependantBean) {
        return new BeanFactoryPostProcessor() {

            public void postProcessBeanFactory(
                    ConfigurableListableBeanFactory beanFactory)
                    throws BeansException {

            }
        };
    }
}

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.springbug.beanfactorydependencyissue" />
</beans>

なぜBeanFactoryPostProcessorConfiguration参照できないのDependantBeanですか?

の結果のDependantBeanインスタンスAppTestは null ではありません。つまり、Spring によって作成されますが、その依存関係 ( DependencyBean) は null です。Spring がまったく文句を言わないという事実は、これが Spring 内のバグであると私に信じさせます。このユースケースをサポートする必要がありますか?

ところで、私は spring-*-3.1.1.RELEASE.jar を使用しています ところで 2: バグを再現するコードもここにあります。

4

4 に答える 4

7

多分もっと単純でわかりやすい答え:

はい、@ComponentBean をBeanFactoryPostProcessor依存関係として使用することは可能です。

ただし、 のすべての依存関係は、いずれかがアクティブBeanFactoryPostProcessorになる前にインスタンス化されます。BeanPostProcessorこれらには次のものが含まれます。

  • CommonAnnotationBeanPostProcessor- @PostConstruct@Resourceおよびその他の注釈を担当
  • AutowiredAnnotationBeanPostProcessor- 責任@Autowired@Value注釈
  • ...などなど...

だからあなたはそれを要約します:

はい、@ComponentBean をBeanFactoryPostProcessor依存関係として使用することは可能ですが、注釈ベースの注入 ( @Autowired@Resource@WebServiceRef、...) およびBeanPostProcessors によって提供されるその他の機能を使用することはできません。


ApplicationContextあなたの例の回避策は、あなたが提案したように階層を作成することです:

  • 各コンテキストは、独自のポスト プロセッサインフラストラクチャを初期化して適用します。ここでは、親コンテキストから依存関係を引き続き参照できます。

他のアプローチは次のとおりです(私が好む):

  • BeanFactoryAwareBean でインターフェースを使用し@Component、依存関係を自分でプルします (Spring はそれを注入しないため)。
  • BeanFactoryPostProcessorコンテキスト構成XMLまたは内で s に接続された Bean を定義します@Configuration(つまり、これらの Bean には使用しない@Componentでください)。
于 2013-05-28T18:18:59.443 に答える
3

Springのいくつかの深刻なデバッグのおかげで、DependantBeanパラメーター toBeanFactoryPostProcessorConfigurationが他の (シームレスに無関係な) Bean の熱心な初期化を引き起こすことがわかりました。しかし、春がBeanFactoryPostProcessor舞台にBeanPostProcessorsあったので、準備ができていませんでした。

BeanFactoryPostProcessorの javadoc を読むと(これを指摘してくれた @Pavel に感謝します)、問題が正確に説明されています。

BeanFactoryPostProcessor は、Bean 定義と対話して変更することはできますが、Bean インスタンスは決して変更できません。これを行うと、Bean のインスタンス化が時期尚早になり、コンテナーに違反して、意図しない副作用が発生する可能性があります。Bean インスタンスの相互作用が必要な場合は、代わりに {@link BeanPostProcessor} の実装を検討してください。

ソリューション:

わずかに変更されたapplicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:component-scan base-package="com.stackoverflow.springbug.beanfactorydependencyissue.other" />
</beans>

新しいbootstrapContext.xml: (パッケージのみが異なることに注意してください)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.stackoverflow.springbug.beanfactorydependencyissue.bootstrap" />
</beans>

新しいContexts.java: (ブートストラップは、通常の applicationContext の親コンテキストであることに注意してください)

package com.stackoverflow.springbug.beanfactorydependencyissue;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;

public final class Contexts
{
    private static Supplier<ApplicationContext> bootstrap = Suppliers.memoize(new Supplier<ApplicationContext>(){
        public ApplicationContext get()
        {
            return new ClassPathXmlApplicationContext("/bootstrapContext.xml");
        }
    });

    /**
    * Context for beans that are needed before initializing of other beans.
    */
    public static ApplicationContext bootstrap()
    {
        return bootstrap.get();
    }

    private static Supplier<ApplicationContext> applicationContext = Suppliers.memoize(new Supplier<ApplicationContext>(){
        public ApplicationContext get()
        {
            return new ClassPathXmlApplicationContext(new String[]{"/applicationContext.xml"}, bootstrap());
        }
    });

    public static ApplicationContext applicationContext()
    {
        return applicationContext.get();
    }
}

パラメータとしてBeanFactoryPostProcessorConfigurationなし:DependantBean

package com.stackoverflow.springbug.beanfactorydependencyissue.other;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.stackoverflow.springbug.beanfactorydependencyissue.Contexts;
import com.stackoverflow.springbug.beanfactorydependencyissue.bootstrap.DependantBean;

@Configuration
public class BeanFactoryPostProcessorConfiguration
{

    /**
    * The {@link DependantBean} here caused the bug, {@link Contexts#bootstrap()} is used as a
    * workaround.
    */
    @Bean
    public static BeanFactoryPostProcessor beanFactoryPostProcessor()
    {
        final DependantBean dependantBean = Contexts.bootstrap().getBean(DependantBean.class);
        System.out.println(dependantBean.getDependencyBean());
        return new BeanFactoryPostProcessor(){
            public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
            {

            }
        };
    }
}

それを機能させる最後のことは、パッケージに移動することDependantBeanでしたDependencyBean。データベースからプロパティbootstrapを読み取るという目標は達成されました。@ValueBean の古い定義を再利用しながら、Bean を複製することはありません。

于 2013-05-20T10:30:15.543 に答える
0

このようにコンポーネントにIDを与える必要があります

 @Component("myClass")
 public class MyClass implements MyInterface
  {
   @Resource
   private MyDependency myDependency; //Isn't initialized correctly when listOfMyClassBeans references myClass

   //Implementation skipped for brevity's sake...
  }

次に、参照を使用します

 <ref bean="myClass">
于 2013-05-15T15:30:31.843 に答える
0

Spring Util 名前空間を使用して、value-type を指定してみてください。この質問を参照してください

于 2013-05-15T19:07:14.927 に答える