Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/selenium/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 单例bean中的请求范围字段_Java_Spring_Annotations_Singleton - Fatal编程技术网

Java 单例bean中的请求范围字段

Java 单例bean中的请求范围字段,java,spring,annotations,singleton,Java,Spring,Annotations,Singleton,我知道在Spring中将请求范围的bean注入到单例bean中是可能的,所以我知道我正在尝试做的事情会起作用,我只是想知道是否有一种方法可以更简洁地表达它,而不需要太多不必要的类定义。我不熟悉Spring注释,所以可能有一个注释我不知道 我有一个抽象类,它在我的应用程序中将作为不同的单例Springbean扩展100倍。以此类定义为例: /** The abstract class with a field that needs to be request-specific **/ public

我知道在Spring中将请求范围的bean注入到单例bean中是可能的,所以我知道我正在尝试做的事情会起作用,我只是想知道是否有一种方法可以更简洁地表达它,而不需要太多不必要的类定义。我不熟悉Spring注释,所以可能有一个注释我不知道

我有一个抽象类,它在我的应用程序中将作为不同的单例Springbean扩展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定义的示例:

@Component
public class SampleSingletonBean extends AbstractSingletonBean {

    @Resource(name="sampleState")
    public void setState(SampleState state) { super.setState(state); }
}
现在我们当然需要一个名为
sampleState
的bean。因此我必须创建两个类:一个基类来定义
SampleState
中的字段,然后是请求范围的bean定义。这是因为
AbstractSingletonBean
的每个扩展都需要自己的请求范围内的state字段实例

下面可能是基类:

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
扩展,只需使用样板代码就可以使其限定请求范围。有没有一种方法可以直接覆盖
AbstractSingletonBean
扩展中的
setState()
,并向spring指示它应该动态创建一个新的请求范围的bean并将其注入到这里?因此,我的
SampleSingletonBean
可以如下所示:

@Component
public class SampleSingletonBean extends AbstractSingletonBean {

    @Resource
    @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public void setState(SampleState state) { super.setState(state); }
}
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

当然,这不起作用,因为
@Resource
需要引用已经存在的bean。是否有另一个注释可以在不为每个
SampleState
bean创建新类的情况下完成此操作?

您可以尝试定义单个SampleState请求范围bean,然后使用spring的查找方法在任何您想插入此bean的地方注入它。这对于prototype范围bean来说都很好。它也可以用于请求范围

顺便说一句,目前还没有对lookup方法的注释支持,所以要么使用xml-vis-a-vis
或者看看javax.inject.Provider

Spring也可以注入抽象类。因此,如果每个
AbstractSingletonBean
子代只需要一个
SampleState
(如您的示例所示),您可以将
SampleState
的注入移动到抽象类中。

这看起来不是现成的,所以我创建了一个注释,我称之为@AnonymousRequest,并将其放在我想要的字段上,和一个BeanDefinitionRegistryPostProcessor来完成创建bean的工作。基本上是这样的:

@Component
public class SampleSingletonBean extends AbstractSingletonBean {

    @Resource
    @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public void setState(SampleState state) { super.setState(state); }
}
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定义。然后创建一个类型为RootBeanDefinition的单例bean,它充当请求范围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;
  }
public void createRequestBeanFromSetterMethod(字符串包含BeanName,BeanDefinition包含Bean,方法方法,BeanDefinitionRegistry)
{
String fieldName=ReflectionUtil.getFieldNameFromSetter(方法.getName());
字符串singletonBeanName=包含BeanName+“”+字段名;
String requestBeanName=“scopedTarget.”+singletonBeanName;
BeanDefinition requestBean=createAnonymousRequestBean(ReflectionUtil.getFieldTypeFromSetter(方法),包含Bean);
RootBeanDefinition singletonBean=新的RootBeanDefinition();
setBeanClass(ScopedProxyFactoryBean.class);
singletonBean.GetPropertyValue().addPropertyValue(“targetBeanName”,requestBeanName);
registry.registerBeanDefinition(singletonBeanName,singletonBean);
registry.registerBeanDefinition(requestBeanName,requestBean);
beanDefinition.GetPropertyValue().addPropertyValue(字段名,新运行时BeanReference(singletonBeanName));
}
私有BeanDefinition createAnonymousRequestBean(类beanType,BeanDefinition parentBean)
{
BeanDefinition newBean=null;
if(parentBean!=null)
{
newBean=新的GenericBean定义(parentBean);
}
其他的
{
newBean=新的GenericBeanDefinition();
}
if(beanType!=null)
{
newBean.setBeanClassName(beanType.getName());
}
newBean.设置范围(“请求”);
newBean.setAutowire候选(false);
//这将来自代理注释…可以添加对不同值的支持
String proxyValue=“org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass”;
BeanMetadataAttribute attr=新的BeanMetadataAttribute(proxyValue,true);
setAttribute(proxyValue,attr);
返回纽贝;
}

它似乎起作用了!实际上,我现在已经在上下文初始化之前创建了一个请求范围的bean,该bean被本地化为这个包含bean的bean。它或多或少是一个请求范围的属性。

我确信每次注入都会得到对同一个bean的引用。原型bean就是这样工作的,因为根据定义,每个注入都是一个新的引用。是的,但是每个AbstractSingletonBean实例都需要自己的SampleState实例,而不是到处引用同一个SampleState请求范围的bean。对于请求范围的bean,将为每个请求创建并注入一个不同的
SampleState
bean实例。我需要为每个请求和AbstractSingletonBean的每个实例创建一个不同的SampleState实例。因此,在一个请求中,如果我使用从AbstractSingletonBean扩展而来的10个bean,那么该请求将需要10个不同的SampleState实例。