סוגי התיחום של Spring Bean מאפשרים לנו שליטה יותר מדורגת על יצירת מופעי ה-Bean. לעיתים קרובות נרצה ליצור מופע של Bean כיחיד, אך במקרים אחרים עשויים לרצות שהוא ייווצר בכל בקשה או פעם אחת בהתקפה.
סוגי התיחום של Spring Bean
קיימים חמישה סוגי spring bean:
- יחיד – ייווצר רק מופע אחד של ה-Bean של Spring עבור מנגנון ה-Spring. זהו התיחום ברירת המחדל של Bean של Spring. בעוד שאנו משתמשים בתיחום זה, יש לוודא שה-Bean אינו מכיל משתני מופע משותפים, אחרת עשוי להוביל לבעיות עם עיוותי נתונים.
- פרוטוטייפ – מופע חדש ייווצר בכל פעם שה-Bean מתבקש ממנגנון ה-Spring.
- בקשה – זהה לתיחום פרוטוטייפ, אך מיועד לשימוש ביישומי אינטרנט. מופע חדש של ה-Bean ייווצר לכל בקשת HTTP.
- הפעלה – Bean חדש ייווצר לכל הפעלת HTTP על ידי המנגנון.
- הפעלה גלובלית – נעשה שימוש זה כדי ליצור Bean הפעלה גלובלית עבור יישומי Portlet.
עצם Spring Bean בסקופ של Singleton ו־Prototype
סקופי ה-Spring Bean של Singleton ו־Prototype ניתן לשימוש באפליקציות עצמאיות של Spring. בואו נראה כיצד אנו יכולים להגדיר בקלות את הסקופים הללו באמצעות האנוטציה @Scope
. נניח שיש לנו כיתת גולש Java.
package com.journaldev.spring;
public class MyBean {
public MyBean() {
System.out.println("MyBean instance created");
}
}
נגדיר את מחלקת התצורה של Spring בה נגדיר את השיטה לקבלת מופע MyBean מהמכניס של Spring.
package com.journaldev.spring;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class MyConfiguration {
@Bean
@Scope(value="singleton")
public MyBean myBean() {
return new MyBean();
}
}
שימו לב ש־singleton
הוא הסקופ המוגדר כברירת מחדל, כך שנוכל להסיר את @Scope(value="singleton")
מההגדרה של העצם לעיל. כעת בואו ניצור שיטת Main ונבדוק את הסקופ של Singleton.
package com.journaldev.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MySpringApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(MyConfiguration.class);
ctx.refresh();
MyBean mb1 = ctx.getBean(MyBean.class);
System.out.println(mb1.hashCode());
MyBean mb2 = ctx.getBean(MyBean.class);
System.out.println(mb2.hashCode());
ctx.close();
}
}
כאשר התוכנית לעיל מופעלת, נקבל פלט כמו שמופיע למטה.
MyBean instance created
867988177
867988177
שימו לב ששני המופעים של MyBean מכילים קוד זהה והבנאי נקרא פעם אחת, כלומר קונטיינר Spring מחזיר תמיד את אותו המופע של MyBean. כעת בואו נשנה את הסקופ ל־prototype
.
@Bean
@Scope(value="prototype")
public MyBean myBean() {
return new MyBean();
}
הפעם נקבל פלט הבא כאשר מתבצעת שיטת Main.
MyBean instance created
867988177
MyBean instance created
443934570
זה ברור שמופע MyBean נוצר בכל פעם שהוא מוזמן מקונטיינר Spring. כעת בואו נשנה את הסקופ ל־request
.
@Bean
@Scope(value="request")
public MyBean myBean() {
return new MyBean();
}
במקרה זה, נקבל חריגה הבאה.
Exception in thread "main" java.lang.IllegalStateException: No Scope registered for scope name 'request'
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:347)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:224)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1015)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:339)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:334)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1107)
at com.journaldev.spring.MySpringApp.main(MySpringApp.java:12)
זה בגלל שהתיקוהות request
, session
ו־global-session
אינן זמינות עבור אפליקציות עצמאיות.
תחום בקשת הפרוחה וההפעלה של Spring Bean
עבור דוגמת תחום בקשה ותחום ההפעלה של Spring Bean, ניצור אפליקציית אינטרנט באמצעות Spring Boot. נקים פרוייקט משובח של Spring Boot ונבחר "web" כדי שנוכל להפעיל אותו כאפליקצית אינטרנט. הפרויקט הסופי שלנו ייראה כמו התמונה למטה.
ServletInitializer
ו־SpringBootMvcApplication
הם כיתות Spring Boot שנוצרות אוטומטית. אנו לא צריכים לבצע שינויים שם. הנה קובץ ה־pom.xml שלי, תבדוק את התלותים לאפליקציה שלנו. קובץ ה־pom.xml שלך עשוי להיות מעט שונה בהתאם לגרסת Eclipse שאתה משתמש בה.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev.spring</groupId>
<artifactId>Spring-Boot-MVC</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>Spring-Boot-MVC</name>
<description>Spring Beans Scope MVC</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>10</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
ניצור כמה מרכיבי Spring ונגדיר אותם כחומרי Spring Beans בתוך מיכל ה־Spring עם תחום היהודי כ-request
ו־session
.
תחום הבקשה של Spring Bean
package com.journaldev.spring;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class DataRequestScope {
private String name = "Request Scope";
public DataRequestScope() {
System.out.println("DataRequestScope Constructor Called");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
סוג מסוף ישיבת חוץ
package com.journaldev.spring;
import org.springframework.context.annotation.Scope;
import java.time.LocalDateTime;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class DataSessionScope {
private String name = "Session Scope";
public DataSessionScope() {
System.out.println("DataSessionScope Constructor Called at "+LocalDateTime.now());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
רכיב Spring
עכשיו בואו ניצור רכיב Spring ונשתמש ב־Spring כדי להגדיר את הקפצות הבונים שנזכור.
package com.journaldev.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Customer {
@Autowired
private DataRequestScope dataRequestScope;
@Autowired
private DataSessionScope dataSessionScope;
public DataRequestScope getDataRequestScope() {
return dataRequestScope;
}
public void setDataRequestScope(DataRequestScope dataRequestScope) {
this.dataRequestScope = dataRequestScope;
}
public DataSessionScope getDataSessionScope() {
return dataSessionScope;
}
public void setDataSessionScope(DataSessionScope dataSessionScope) {
this.dataSessionScope = dataSessionScope;
}
}
בקר Spring Rest
לבסוף, בואו ניצור מחלקת RestController ונגדיר כמה נקודות סיום API לצורכי הבדיקה שלנו.
package com.journaldev.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloData {
@Autowired
private Customer customer;
@RequestMapping("/nameRS")
public String helloRS() {
return customer.getDataRequestScope().getName();
}
@RequestMapping("/nameSSUpdated")
public String helloSSUpdated() {
customer.getDataSessionScope().setName("Session Scope Updated");
return customer.getDataSessionScope().getName();
}
@RequestMapping("/nameSS")
public String helloSS() {
return customer.getDataSessionScope().getName();
}
}
הגדרת זמן קצה של ישיבת קצה ב־Spring Boot
לבסוף עלינו להגדיר משתני זמן קצה של הפעלת Spring Boot, להוסיף מאפיינים מתחת למטה ב־src/main/resources/application.properties
.
server.session.cookie.max-age= 1
server.session.timeout= 1
עכשיו הבונים שלנו שטויות עם סשן יושב ייבוט במשך דקה. רק הפעילו את המחלקה SpringBootMvcApplication
כיישום Spring Boot. אתה צריך לראות פלט למטה עבור נקודות הסיום שלנו שנקבעו.
2018-05-23 17:02:25.830 INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameRS]}" onto public java.lang.String com.journaldev.spring.HelloData.helloRS()
2018-05-23 17:02:25.831 INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameSSUpdated]}" onto public java.lang.String com.journaldev.spring.HelloData.helloSSUpdated()
2018-05-23 17:02:25.832 INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameSS]}" onto public java.lang.String com.journaldev.spring.HelloData.helloSS()
בדיקת תחום בקשת חורף של Spring Bean
פתח דפדפן כלשהו ועבור אל כתובת URL https://localhost:8080/nameRS
ובדוק את פלט הקונסולה. אתה אמור לראות את DataRequestScope Constructor Called
מודפס בכל בקשה.
בדיקת תחום הסשן של Spring Bean
עבור ל־https://localhost:8080/nameSS
ותקבל את הפלט הבא. עכשיו עבור ל־
https://localhost:8080/nameSSUpdated
כדי שערך השם של DataSessionScope
יתעדכן ל־Session Scope Updated
. עכשיו שוב עבור ל־
https://localhost:8080/nameSS
ותראה את הערך המעודכן. עד כאן, עליך לראות את
DataSessionScope Constructor Called at XXX
רק פעם אחת בפלט הקונסולה. עכשיו המתן ל־1 דקות כך שהבין עצם המוגדר על פי המשך הפעולה שלנו ייבטל. אז שוב עבור ל־https://localhost:8080/nameSS
ותראה את הפלט המקורי. כמו כן עליך לבדוק את ההודעה בקונסולה ליצירת DataSessionScope שוב על ידי המכולה. זהו הכל למדריך התיאור הסקופ של החפיסות של Spring Beans.
באפשרותך להוריד את פרויקט Spring Beans Scope Spring Boot ממערכת ה־GitHub שלנו.
Source:
https://www.digitalocean.com/community/tutorials/spring-bean-scopes