【问题标题】:Issue with Spring ScopeSpring Scope 的问题
【发布时间】:2015-11-23 22:18:31
【问题描述】:

使用下面的代码,我试图将请求属性“名称”的值设置为对象文本。当请求属性名称 = Test2 时,我引入了 10 秒的延迟。我启动了一个名称 = Test2 的请求。当请求进行时,我启动另一个名称 = Test.对于第二个请求,我看到 name = Test 被打印而不是 Test1 ,因为我猜 bean Text 是一个单例。当我在 Text 类中更新 scope("prototype") 时,我看到 DemoRestController.java 中 Text.getData() 的值为 null。如何将 Text 对象的范围定义为原型并在 DemoRestController 中自动装配?

DemoApplication.java

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
@ComponentScan({"com.example"})
@ImportResource("application-context.xml")
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

DemoRestController.java

package com.example;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoRestController {

    @Autowired
    Text text;
    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @RequestMapping("/greeting")
    public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {

        if(text.getData().equalsIgnoreCase("Test2")){
            System.out.println("Matching!");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        System.out.println(name + " = " + text.getData());
        return new Greeting(counter.incrementAndGet(),
                            String.format(template, name));
    }
}

Greeting.java

package com.example;

public class Greeting {

    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }
}

GreetingInterceptor.java

package com.example;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class GreetingInterceptor extends HandlerInterceptorAdapter{
    @Autowired
    Text text;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // TODO Auto-generated method stub
        System.out.println(" Intecepted :: " + request.getParameter("name"));
        text.setData(request.getParameter("name"));
        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub
        super.afterCompletion(request, response, handler, ex);
    }

    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // TODO Auto-generated method stub
        super.afterConcurrentHandlingStarted(request, response, handler);
    }





}

Text.java

package com.example;

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Component
public class Text {

    private String data;

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }



}

application-context.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"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <!-- <import resource = "classpath:config.xml"/>  -->
    <context:annotation-config/>
    <context:property-placeholder/>
    <!-- <context:component-scan base-package="com.comcast.customer.db" /> -->
    <!-- <context:property-placeholder location="classpath:customer-config.properties" />-->

    <!-- <bean id="billingConnector"
        class="com.comcast.billing.connector.app.BillingConnector"/> -->
    <!-- <bean id="LocationServiceConnector"
        class="com.comcast.cx.LocationServiceConnector.LocationServiceConnector"/> -->
        <mvc:interceptors>
   <mvc:interceptor>
     <mvc:mapping path="/greeting/**" />
     <bean class="com.example.GreetingInterceptor" />
   </mvc:interceptor>
</mvc:interceptors>
</beans>

【问题讨论】:

  • 我看到 DemoRestController.java 中自动装配的 Text 对象的值为 null 你怎么知道?
  • 在 Text.java 中,我添加了 scope("prototype") ,启动了 spring boot 程序并触发了一个休息请求,我看到在这一行打印了一个 nullpointerexception "if(text.getData() .equalsIgnoreCase("Test2")){" 存在于 DemoRestController
  • 你怎么知道 getData() 没有返回 null?请不要使用trainwrecks
  • 我在代码中添加了这两行: System.out.println(" Value of text = " + text); System.out.println(" text.getData() 的值 = " + text.getData());我看到正在打印以下内容: text 的值 = com.example.Text@6fbe2f87 text.getData() 的值 = null
  • 当然,以后会避免火车残骸。谢谢。

标签: java spring spring-boot


【解决方案1】:

正如documentation 关于prototype 范围的状态

bean 部署的非单例原型范围导致 每次请求特定的 bean 时创建一个新的 bean 实例 豆子做好了。即 bean 被注入另一个 bean 或者你 通过容器上的getBean() 方法调用来请求它。

每个@Autowired 都会产生不同的实例。

注入您的GreetingInterceptor 的实例与注入您的DemoRestController 的实例无关。

如果您希望每个请求/响应周期有一个实例,请使用 request 范围。

【讨论】:

  • 感谢 Sotirios 澄清我的理解。有没有一种方法可以建议您在返回响应后将值保留在请求范围内?
  • @PunterVicky 一旦相应请求的处理完成,就没有请求范围。也许你真的想要session 作用域。
  • 感谢 Sotirios,当我按照您的建议使用会话范围时,我确实得到了预期的结果 (@Scope(value="session", proxyMode = ScopedProxyMode.TARGET_CLASS)。我公开的服务是 REST服务,并且我们收到的不同呼叫之间没有关系(没有会话的概念)。在继续这条路线之前我必须分析任何影响吗?再次感谢您的所有帮助。
  • 如果您不维护会话,您将在每个请求上获得一个新实例,相当于 request 范围。
  • 最后一个问题 - 我认为不同之处在于请求对象将丢失,而会话对象在发送响应后不会丢失。我的理解正确吗?当请求对象被销毁时,会话对象不会被杀死吗?
猜你喜欢
  • 1970-01-01
  • 2016-06-06
  • 2016-04-27
  • 2015-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多