Saya ingin menggunakan kacang prototipe beranotasi di controller saya. Tapi musim semi malah membuat kacang singleton. Ini kode untuk itu:
@Component
@Scope("prototype")
public class LoginAction {
private int counter;
public LoginAction(){
System.out.println(" counter is:" + counter);
}
public String getStr() {
return " counter is:"+(++counter);
}
}
Kode pengontrol:
@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;
}
}
Templat kecepatan:
LoginAction counter: ${loginAction.str}
Pegas config.xml
mengaktifkan pemindaian komponen:
<context:annotation-config />
<context:component-scan base-package="com.springheat" />
<mvc:annotation-driven />
Saya mendapatkan hitungan yang bertambah setiap kali. Tidak tahu di mana saya salah!
Memperbarui
Seperti yang disarankan oleh @gkamal , saya membuat HomeController
webApplicationContext
-aware dan itu memecahkan masalah.
kode yang diperbarui:
@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");
}
}
spring
spring-mvc
tintin
sumber
sumber
Jawaban:
Prototipe lingkup berarti bahwa setiap kali Anda meminta pegas (getBean atau injeksi ketergantungan) untuk sebuah instance, ia akan membuat instance baru dan memberikan referensi untuk itu.
Dalam contoh Anda, instance baru LoginAction dibuat dan disuntikkan ke HomeController Anda. Jika Anda memiliki pengontrol lain di mana Anda menyuntikkan LoginAction Anda akan mendapatkan contoh yang berbeda.
Jika Anda menginginkan contoh berbeda untuk setiap panggilan - maka Anda perlu memanggil getBean setiap kali - menyuntikkan kacang singleton tidak akan mencapai itu.
sumber
request
lingkup alih-alihprototype
ruang lingkup. Apakah Anda masih perlu mengambil kacang dengancontext.getBean(..)
?Sejak Spring 2.5 ada cara yang sangat mudah (dan elegan) untuk mencapainya.
Anda hanya dapat mengubah params
proxyMode
danvalue
dari@Scope
penjelasan.Dengan trik ini Anda dapat menghindari menulis kode tambahan atau menyuntikkan ApplicationContext setiap kali Anda memerlukan prototipe di dalam kacang singleton.
Contoh:
Dengan konfigurasi di atas
LoginAction
(di dalamHomeController
) selalu ada prototipe meskipun controllernya adalah singleton .sumber
Hanya karena kacang yang disuntikkan ke pengontrol memiliki cakupan prototipe, bukan berarti pengontrolnya!
sumber
@controller adalah objek singleton, dan jika menyuntikkan kacang prototipe ke kelas singleton akan menjadikan kacang prototipe juga sebagai singleton kecuali jika Anda menentukan menggunakan properti metode pencarian yang benar-benar membuat instance baru kacang prototipe untuk setiap panggilan yang Anda lakukan.
sumber
Seperti yang disebutkan oleh nicholas.hauschild menyuntikkan konteks Musim Semi bukanlah ide yang baik. Dalam kasus Anda, @Scope ("permintaan") sudah cukup untuk memperbaikinya. Tetapi katakanlah Anda memerlukan beberapa contoh
LoginAction
dalam metode controller. Dalam hal ini, saya akan merekomendasikan untuk membuat kacang Pemasok ( solusi Spring 4 ):Kemudian masukkan ke dalam pengontrol:
sumber
ObjectFactory
yang melayani tujuan yang sama dengan pemasok, tetapi dapat didefinisikan sebagai normal@Bean
dengan maksud saya tidak perlu mengembalikan lambda.Menggunakan
ApplicationContextAware
mengikat Anda ke Spring (yang mungkin atau mungkin tidak menjadi masalah). Saya akan merekomendasikan lewatLoginActionFactory
, yang Anda dapat meminta contoh baruLoginAction
setiap kali Anda membutuhkannya.sumber
factory-method
sini ...LoginActionFactory
ke Controller, tetapifactory-method
sepertinya itu tidak akan menyelesaikan masalah karena hanya menciptakan kacang musim semi lain melalui pabrik. Menyuntikkan kacang itu ke Kontroler singleton tidak akan mengatasi masalah.gunakan cakupan permintaan
@Scope("request")
untuk mendapatkan kacang untuk setiap permintaan, atau@Scope("session")
untuk mendapatkan kacang untuk setiap 'pengguna' sesisumber
Kacang protoype yang disuntikkan ke dalam kacang singelton akan berperilaku seperti singelton sampai tiba-tiba dipanggil untuk membuat contoh baru dengan mendapatkan kacang.
sumber
@Komponen
@Scope (value = "prototype")
TennisCoach kelas publik mengimplementasikan Coach {
// beberapa kode
}
sumber
Anda dapat membuat kelas statis di dalam controller Anda seperti ini:
sumber
Cara lain untuk memecahkan masalah adalah metode injeksi dengan penjelasan @Lookup .
Berikut adalah artikel yang bagus tentang masalah ini dengan menyuntikkan kacang prototipe ke dalam contoh tunggal dengan beberapa solusi.
https://www.baeldung.com/spring-inject-prototype-bean-into-singleton
sumber
Pengontrol Anda juga memerlukan
@Scope("prototype")
ditentukanseperti ini:
sumber