2011-10-01 31 views
84

Tôi muốn sử dụng bean mẫu được chú thích trong bộ điều khiển của mình. Nhưng mùa xuân đang tạo ra một chiếc đậu đơn thay thế. Dưới đây là mã cho rằng:@Scope ("nguyên mẫu") phạm vi đậu không tạo bean mới

@Component 
@Scope("prototype") 
public class LoginAction { 

    private int counter; 

    public LoginAction(){ 
    System.out.println(" counter is:" + counter); 
    } 
    public String getStr() { 
    return " counter is:"+(++counter); 
    } 
} 

đang điều khiển:

@Controller 
public class HomeController { 
    @Autowired 
    private LoginAction loginAction; 

    @RequestMapping(value="/view", method=RequestMethod.GET) 
    public ModelAndView display(HttpServletRequest req){ 
     ModelAndView mav = new ModelAndView("home"); 
     mav.addObject("loginAction", loginAction); 
     return mav; 
    } 

    public void setLoginAction(LoginAction loginAction) { 
     this.loginAction = loginAction; 
    } 

    public LoginAction getLoginAction() { 
     return loginAction; 
    } 
    } 

Velocity template:

LoginAction counter: ${loginAction.str} 

Xuân config.xml có thành phần quét được kích hoạt:

<context:annotation-config /> 
    <context:component-scan base-package="com.springheat" /> 
    <mvc:annotation-driven /> 

Tôi nhận được số gia tăng mỗi lần. Không thể tìm ra nơi tôi đang đi sai!

Cập nhật

Như suggested by @gkamal, tôi đã HomeControllerwebApplicationContext -aware và nó đã giải quyết được vấn đề.

đang được cập nhật:

@Controller 
public class HomeController { 

    @Autowired 
    private WebApplicationContext context; 

    @RequestMapping(value="/view", method=RequestMethod.GET) 
    public ModelAndView display(HttpServletRequest req){ 
     ModelAndView mav = new ModelAndView("home"); 
     mav.addObject("loginAction", getLoginAction()); 
     return mav; 
    } 

    public LoginAction getLoginAction() { 
     return (LoginAction) context.getBean("loginAction"); 
    } 
} 
+7

Tôi ước gì có thể tăng gấp đôi upvote bạn để thực hiện các câu trả lời đúng trong mã của bạn cho người khác để thấy sự khác biệt thực tế –

Trả lời

104

Phạm vi nguyên mẫu có nghĩa là mỗi khi bạn hỏi mùa xuân (getBean hoặc dependency injection) cho một ví dụ nó sẽ tạo ra một trường hợp mới và đưa ra một tham chiếu đến đó.

Trong ví dụ của bạn, một thể hiện mới của LoginAction được tạo và được đưa vào HomeController của bạn. Nếu bạn có một bộ điều khiển khác mà bạn injectActionAction, bạn sẽ nhận được một cá thể khác.

Nếu bạn muốn một phiên bản khác nhau cho mỗi cuộc gọi - thì bạn cần phải gọi getBean mỗi lần - tiêm vào một hạt đơn sẽ không đạt được điều đó.

+5

Tôi đã thực hiện điều khiển ApplicationContextAware và đã getBean và tôi nhận được đậu tươi mỗi lần. Cảm ơn các bạn!!! – tintin

+0

Làm thế nào để nó hoạt động nếu bean đã có phạm vi 'request' thay vì phạm vi' prototype'. Bạn vẫn cần lấy lại bean với 'context.getBean (..)'? –

+0

Hoặc sử dụng proxy có phạm vi, ví dụ: @Scope (value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) – svenmeier

12

Chỉ vì hạt được tiêm vào bộ điều khiển là nguyên mẫu-phạm vi không có nghĩa là bộ điều khiển!

2

Sử dụng ApplicationContextAware đang buộc bạn vào Mùa xuân (có thể có hoặc không có vấn đề). Tôi khuyên bạn nên chuyển qua số LoginActionFactory, bạn có thể yêu cầu phiên bản mới LoginAction mỗi lần bạn cần.

+1

Có các chú thích cụ thể theo mùa xuân; có vẻ như đó không phải là một mối quan tâm. –

+1

@Dave, Good point. Có những lựa chọn thay thế cho một số công cụ DI (JSR 311), nhưng nó có thể khó khăn hơn để thoát khỏi bản thân mọi thứ mà Spring phụ thuộc trong ví dụ này. Tôi cho rằng tôi thực sự chỉ ủng hộ 'factory-method' ở đây ... –

+1

+1 để tiêm một" LoginActionFactory' đơn vào Bộ điều khiển, nhưng 'factory-method' dường như không giải quyết được vấn đề vì nó chỉ tạo ra một loại đậu mùa xuân khác thông qua nhà máy. Tiêm đậu vào bộ điều khiển Singleton sẽ không giải quyết được vấn đề. –

-6

điều khiển của bạn cũng cần @Scope ("nguyên mẫu") defind

như thế này:

@Controller 
@Scope("prototype") 
public class HomeController { 
..... 
..... 
..... 

} 
+0

tại sao u nghĩ rằng bộ điều khiển cũng cần phải được nguyên mẫu? –

+5

Điều này chỉ đơn giản là sai. –

7

@controller là một đối tượng singleton, và nếu tiêm một bean nguyên mẫu để một lớp singleton sẽ làm cho bean nguyên mẫu cũng như singleton trừ khi u chỉ định sử dụng thuộc tính lookup-method mà thực sự tạo ra một cá thể mới của bean nguyên mẫu cho mọi cuộc gọi bạn thực hiện.

3

sử dụng yêu cầu phạm vi @Scope("request") để có được đậu cho mỗi yêu cầu, hoặc @Scope("session") để có được đậu cho mỗi phiên 'user'

2

Như đã đề cập bởi nicholas.hauschild tiêm bối cảnh mùa xuân không phải là một ý tưởng tốt. Trong trường hợp của bạn, @Scope ("yêu cầu") là đủ để sửa chữa nó. Nhưng hãy nói rằng bạn cần một số trường hợp của LoginAction trong phương pháp điều khiển.Trong trường hợp này, tôi muốn giới thiệu để tạo ra các hạt của Nhà cung cấp (Spring 4 giải pháp):

@Bean 
    public Supplier<LoginAction> loginActionSupplier(LoginAction loginAction){ 
     return() -> loginAction; 
    } 

Sau đó tiêm nó vào điều khiển:

@Controller 
public class HomeController { 
    @Autowired 
    private Supplier<LoginAction> loginActionSupplier; 
Các vấn đề liên quan