spring的bean范围_Spring Bean范围

spring的bean范围

Spring Bean Scopes allows us to have more granular control of the bean instances creation. Sometimes we want to create bean instance as singleton but in some other cases we might want it to be created on every request or once in a session.

Spring Bean Scopes使我们可以更精细地控制Bean实例的创建。 有时我们想将bean实例创建为单例,但在另一些情况下,我们可能希望在每个请求或一次会话中创建它。

Spring Bean范围 (Spring Bean Scopes)

There are five types of spring bean scopes:

Spring bean范围有五种类型:

  1. singleton – only one instance of the spring bean will be created for the spring container. This is the default spring bean scope. While using this scope, make sure bean doesn’t have shared instance variables otherwise it might lead to data inconsistency issues.

    单例 –仅为弹簧容器创建一个弹簧豆实例。 这是默认的Spring bean作用域。 使用此范围时,请确保bean没有共享的实例变量,否则可能导致数据不一致问题。
  2. prototype – A new instance will be created every time the bean is requested from the spring container.

    prototype –每次从spring容器请求bean时,都会创建一个新实例。
  3. request – This is same as prototype scope, however it’s meant to be used for web applications. A new instance of the bean will be created for each HTTP request.

    请求 –与原型范围相同,但是它打算用于Web应用程序。 将为每个HTTP请求创建一个新的bean实例。
  4. session – A new bean will be created for each HTTP session by the container.

    session –容器将为每个HTTP会话创建一个新bean。
  5. global-session – This is used to create global session beans for Portlet applications.

    global-session –用于为Portlet应用程序创建全局会话Bean。

Spring Bean Singleton和原型范围 (Spring Bean Singleton and Prototype Scope)

Spring bean singleton and prototype scopes can be used in standalone spring apps. Let’s see how we can easily configure these scopes using @Scope annotation.

Spring bean单例和原型范围可以在独立的spring应用程序中使用。 让我们看看如何使用@Scope批注轻松配置这些范围。

Let’s say we have a java bean class.

假设我们有一个Java bean类。

package com.journaldev.spring;

public class MyBean {

	public MyBean() {
		System.out.println("MyBean instance created");
	}

}

Let’s define the spring configuration class where we will define the method to get MyBean instance from spring container.

让我们定义spring配置类,在其中定义要从spring容器中获取MyBean实例的方法。

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();
	}
	
}

Note that singleton is default scope, so we can remove @Scope(value="singleton") from above bean definition.

请注意, singleton是默认范围,因此我们可以从上述bean定义中删除@Scope(value="singleton")

Now let’s create a main method and test the singleton scope.

现在,让我们创建一个main方法并测试单例范围。

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();
	}

}

When above program is executed, we will get output like below.

当执行上面的程序时,我们将得到如下输出。

MyBean instance created
867988177
867988177

Notice that both MyBean instances have same hashcode and the constructor is called once once, it means that spring container is returning the same instance of MyBean always.

注意,两个MyBean实例具有相同的哈希码,并且构造函数被调用一次,这意味着spring容器始终返回相同的MyBean实例。

Now let’s change the scope to prototype.

现在让我们将范围更改为prototype

@Bean
@Scope(value="prototype")
public MyBean myBean() {
	return new MyBean();
}

This time we will get following output when main method is executed.

这次,当执行main方法时,我们将获得以下输出。

MyBean instance created
867988177
MyBean instance created
443934570

It’s clear that MyBean instance is created every time it’s requested from spring container.

显然,每次从Spring容器请求MyBean实例时都会创建它。

Now let’s change the scope to request.

现在让我们将范围更改为request

@Bean
@Scope(value="request")
public MyBean myBean() {
	return new MyBean();
}

In this case, we will get following exception.

在这种情况下,我们将得到以下异常。

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)

It’s because request, session and global-session scopes are not available for standalone applications.

这是因为requestsessionglobal-session作用域不适用于独立的应用程序。

Spring Bean请求和会话范围 (Spring Bean Request and Session Scope)

For spring bean request and session scope example, we will create Spring Boot web application. Create a spring boot starter project and choose “web” so that we can run it as a web application.

对于spring bean请求和会话作用域示例,我们将创建Spring Boot Web应用程序。 创建一个spring boot starter项目并选择“ web”,以便我们可以将其作为Web应用程序运行。

Our final project will look like below image.

我们的最终项目将如下图所示。

ServletInitializer and SpringBootMvcApplication are auto generated spring boot classes. We don’t need to make any changes there.

ServletInitializerSpringBootMvcApplication是自动生成的Spring Boot类。 我们不需要在那里进行任何更改。

Here is my pom.xml file, have a look at the dependencies for our application. Your pom.xml file might be slightly different based on the Eclipse version you are using.

这是我的pom.xml文件,看看我们应用程序的依赖关系。 根据您使用的Eclipse版本,您的pom.xml文件可能会略有不同。

<?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>

Let’s create some spring components and configure them as spring beans in the spring container with scope as request and session.

让我们创建一些spring组件,并将它们配置为spring容器中的spring bean,作用域为requestsession

Spring Bean请求范围 (Spring Bean Request Scope)

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;
	}
}

Spring Bean会话范围 (Spring Bean Session Scope)

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 Component)

Now let’s create a spring component and use spring to auto configure above beans.

现在,让我们创建一个spring组件,并使用spring来自动配置上述bean。

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 Controller)

Finally, let’s create a RestController class and configure some API end points for our testing purposes.

最后,让我们创建一个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 Session Timeout Configuration)

Finally we have to configure spring boot session timeout variables, add below properties in src/main/resources/application.properties.

最后,我们必须配置spring boot session超时变量,在src/main/resources/application.properties添加以下属性。

server.session.cookie.max-age= 1
server.session.timeout= 1

Now our spring beans with session scope will be invalidated in one minute.

现在,具有会话范围的spring bean将在一分钟内失效。

Just run the SpringBootMvcApplication class as spring boot application. You should see below output for our endpoints being configured.

只需将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请求范围测试 (Spring Bean Request Scope Test)

Open any browser and go to URL https://localhost:8080/nameRS and check the console output. You should see DataRequestScope Constructor Called getting printed on each request.

打开任何浏览器,然后转到URL https://localhost:8080/nameRS并检查控制台输出。 您应该看到在每个请求上都打印出了DataRequestScope Constructor Called

Spring Bean会话范围测试 (Spring Bean Session Scope Test)

Go to https://localhost:8080/nameSS and you would get following output.

转到https://localhost:8080/nameSS ,您将获得以下输出。

Now go to https://localhost:8080/nameSSUpdated so that DataSessionScope name value is updated to Session Scope Updated.

现在转到https://localhost:8080/nameSSUpdated以便将DataSessionScope名称值更新为Session Scope Updated

Now again go to https://localhost:8080/nameSS and you should see the updated value.

现在再次转到https://localhost:8080/nameSS ,您应该看到更新后的值。

By this time, you should see DataSessionScope Constructor Called at XXX only once in the console output.

此时,您应该在控制台输出中仅看到一次在DataSessionScope Constructor Called at XXX

Now wait for 1 minute so that our session scoped bean is invalidated. Then again go to https://localhost:8080/nameSS and you should see the original output. Also you should check console message for creation of DataSessionScope again by the container.

现在等待1分钟,以使我们的会话作用域bean无效。 然后再次转到https://localhost:8080/nameSS ,您应该看到原始输出。 另外,您还应该检查控制台消息以再次由容器创建DataSessionScope。

That’s all for spring beans scope tutorial.

这就是Spring bean范围教程的全部内容。

GitHub Repository. GitHub Repository下载Spring Beans Scope Spring Boot项目。

翻译自: https://www.journaldev.com/21039/spring-bean-scopes

spring的bean范围

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值