2

Spring でリクエストスコープの Bean をシングルトン Bean に注入できることはわかっているので、私がやろうとしていることはうまくいくと思います。余分な不要なクラスをあまり使わずに、より簡潔に表現する方法があるかどうか疑問に思っています。定義。Spring アノテーションは初めてなので、知らないアノテーションがあるかもしれません。

アプリケーションで異なるシングルトンSpring Beanとしておそらく100回拡張される抽象クラスがあります。例として、次のクラス定義を取り上げます。

/** The abstract class with a field that needs to be request-specific **/
public abstract class AbstractSingletonBean {

    private SampleState state;
    public SampleState getState() { return state; }
    public void setState(SampleState state) { this.state = state; }

    // Other fields that are just singleton here
}

そして、Bean 定義の 1 つがどのように見えるかの例:

@Component
public class SampleSingletonBean extends AbstractSingletonBean {

    @Resource(name="sampleState")
    public void setState(SampleState state) { super.setState(state); }
}

もちろん、 という Bean が必要sampleStateです。そのため、フィールドを定義する基本クラスSampleStateと、リクエスト スコープの Bean 定義の 2 つのクラスを作成する必要があります。これは、各拡張機能がAbstractSingletonBean状態フィールドの独自のリクエスト スコープのインスタンスを必要とするためです。

ここに基本クラスがあります:

public class SampleState {
    private String fieldOne;
    public String getFieldOne() { return fieldOne }
    public void setFieldOne() { this.fieldOne = fieldOne }
}

そして、これがこのばかげた Bean の定義です。

@Component ("sampleState")
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SampleStateBean extends SampleState {}

気になるのは、 の拡張機能が 100 個ある場合、リクエスト スコープにするためのボイラープレート コードだけAbstractSingletonBeanで の拡張機能が 100 個必要になることです。拡張機能をSampleStateBeanオーバーライドして、その場で新しいリクエスト スコープ Bean を作成し、ここに注入する必要があることを示す方法はありますか? だから私は次のようになります:setState()AbstractSingletonBeanSampleSingletonBean

@Component
public class SampleSingletonBean extends AbstractSingletonBean {

    @Resource
    @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public void setState(SampleState state) { super.setState(state); }
}

もちろん@Resource、既に存在する Bean を参照する必要があるため、これは機能しません。SampleStateすべての Beanに新しいクラスを作成せずにこれを達成するための別の注釈はありますか?

4

3 に答える 3

1

これはすぐに利用できるようには見えないので、必要なフィールドに配置する @AnonymousRequest というアノテーションと、Bean を作成する作業を行う BeanDefinitionRegistryPostProcessor を作成しました。基本的には次のようになります。

for each bean in the BeanFactory
  if bean class has AnonymousRequest annotation
    create request scoped bean from field class
    create singleton bean to be request scoped bean wrapper
    set the annotated property value to the singleton wrapper

Spring がリクエスト スコープ Bean を登録する方法を理解するには、多くの作業が必要でした。必要な Bean 定義をリクエスト スコープ Bean として作成します。次に、リクエスト スコープ Bean のラッパーとして機能するタイプ RootBeanDefinition のシングルトン Bean を作成し、「targetBeanName」という名前のラッパーのプロパティを、リクエスト スコープ Bean の名前 (「scopedTarget.」 + 慣例によるシングルトン Bean 名) に設定します。 )。

したがって、これはおそらく実際にこのことを知っている誰かによって改善される可能性がありますが、ここに私が思いついたものがあります:

  public void createRequestBeanFromSetterMethod(String containingBeanName, BeanDefinition containingBean, Method method, BeanDefinitionRegistry registry)
  {
    String fieldName = ReflectionUtil.getFieldNameFromSetter(method.getName());
    String singletonBeanName = containingBeanName+"_"+fieldName;
    String requestBeanName = "scopedTarget."+singletonBeanName;

    BeanDefinition requestBean = createAnonymousRequestBean(ReflectionUtil.getFieldTypeFromSetter(method), containingBean);

    RootBeanDefinition singletonBean = new RootBeanDefinition();
    singletonBean.setBeanClass(ScopedProxyFactoryBean.class);
    singletonBean.getPropertyValues().addPropertyValue("targetBeanName", requestBeanName);

    registry.registerBeanDefinition(singletonBeanName, singletonBean);
    registry.registerBeanDefinition(requestBeanName, requestBean);

    beanDefinition.getPropertyValues().addPropertyValue(fieldName, new RuntimeBeanReference(singletonBeanName));

  }

  private BeanDefinition createAnonymousRequestBean(Class<?> beanType, BeanDefinition parentBean)
  {
    BeanDefinition newBean = null;
    if (parentBean != null)
    {
      newBean = new GenericBeanDefinition(parentBean);
    }
    else
    {
      newBean = new GenericBeanDefinition();
    }

    if (beanType != null)
    {
      newBean.setBeanClassName(beanType.getName());
    }

    newBean.setScope("request");
    newBean.setAutowireCandidate(false);

    // This would have come from the Proxy annotation...could add support for different values
    String proxyValue = "org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass";
    BeanMetadataAttribute attr = new BeanMetadataAttribute(proxyValue, true);
    newBean.setAttribute(proxyValue, attr);

    return newBean;
  }

効きそうです!これで、Bean を含むこの Bean にローカライズされたコンテキスト初期化の直前に作成された、リクエスト スコープの Bean が効果的に作成されました。これは多かれ少なかれ、リクエスト スコープのプロパティです。

于 2013-07-19T18:43:48.897 に答える
0

単一の SampleState リクエスト スコープ Bean を定義してから、Spring のルックアップ メソッドを使用して、この Bean を必要な場所に注入できます。これは、プロトタイプ スコープ Bean でうまく機能します。フィンガーズクロスは、リクエストスコープでも機能します。

私の知る限り、今のところルックアップメソッドの注釈サポートはありません。そのため、xml を使用するか、ここで javax.inject.Provider関連する質問を見てください。

于 2013-07-04T01:11:11.060 に答える