תיאוריות מספרות של פונקציות Bean בספרינג

סוגי התיחום של Spring Bean מאפשרים לנו שליטה יותר מדורגת על יצירת מופעי ה-Bean. לעיתים קרובות נרצה ליצור מופע של Bean כיחיד, אך במקרים אחרים עשויים לרצות שהוא ייווצר בכל בקשה או פעם אחת בהתקפה.

סוגי התיחום של Spring Bean

קיימים חמישה סוגי spring bean:

  1. יחיד – ייווצר רק מופע אחד של ה-Bean של Spring עבור מנגנון ה-Spring. זהו התיחום ברירת המחדל של Bean של Spring. בעוד שאנו משתמשים בתיחום זה, יש לוודא שה-Bean אינו מכיל משתני מופע משותפים, אחרת עשוי להוביל לבעיות עם עיוותי נתונים.
  2. פרוטוטייפ – מופע חדש ייווצר בכל פעם שה-Bean מתבקש ממנגנון ה-Spring.
  3. בקשה – זהה לתיחום פרוטוטייפ, אך מיועד לשימוש ביישומי אינטרנט. מופע חדש של ה-Bean ייווצר לכל בקשת HTTP.
  4. הפעלה – Bean חדש ייווצר לכל הפעלת HTTP על ידי המנגנון.
  5. הפעלה גלובלית – נעשה שימוש זה כדי ליצור 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