一,背景
Scope注解主要用于配置bean在容器中的生命周期,除了可以配置为singleton和prototype,在Web环境还可以配置为request、session等 值,表示容器会为一次请求或一个会话分配一个bean的实例。如果对bean的生命周期有特殊需求,可以使用自定义的Scope。比如实现一个bean被使用3次后,就获取新的bean实例。
二,实现
下面以Spring boot 进行演示
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
MyBean.java
@Data
public class MyBean {
public MyBean(String id) {
this.id = id;
}
private String id;
}
MyScope.java
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author lwc
*/
public class MyScope implements Scope {
/**
* 记录bean的使用次数
*/
private static ConcurrentHashMap<String, Integer> beanCounts = new ConcurrentHashMap<>();
/**
* 保存实例
*/
private ConcurrentHashMap<String, Object> beans = new ConcurrentHashMap<String, Object>();
@Override
public Object get(String s, ObjectFactory<?> objectFactory) {
beanCounts.putIfAbsent(s, 0);
//第一次使用,放到实例的Map中
Integer beanCount = beanCounts.get(s);
if (beanCount == 0) {
Object newObject = objectFactory.getObject();
beans.put(s, newObject);
}
Object bean = beans.get(s);
//计数器加1
int newBeanCount = beanCount + 1;
if (newBeanCount >= 3) {
newBeanCount = 0;
}
//设置新的次数
beanCounts.put(s, newBeanCount);
return bean;
}
@Override
public Object remove(String s) {
return null;
}
@Override
public void registerDestructionCallback(String s, Runnable runnable) {
}
@Override
public Object resolveContextualObject(String s) {
return null;
}
@Override
public String getConversationId() {
return null;
}
}
MyConfig.java
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.CustomScopeConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import javax.annotation.PostConstruct;
/**
* 配置
*
* @author lwc
*/
@Configuration
public class MyConfig {
@Autowired
BeanFactory factory;
@PostConstruct
public void customScopeConfigurer() {
CustomScopeConfigurer config = new CustomScopeConfigurer();
config.addScope("three", new MyScope());
config.postProcessBeanFactory((ConfigurableListableBeanFactory) factory);
}
@Bean
@Scope(scopeName = "three")
public MyBean bean1() {
return new MyBean("1");
}
}
DemoController.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author lwc
*/
@RestController
public class DemoController {
@Autowired
ApplicationContext ctx;
@RequestMapping(value = "/")
public String index() {
for (int i = 0; i < 5; i++) {
System.out.println(ctx.getBean("bean1"));
}
return "";
}
}
三,测试
com.g7go.springannotation.MyBean@7e05c996
com.g7go.springannotation.MyBean@7e05c996
com.g7go.springannotation.MyBean@7e05c996
com.g7go.springannotation.MyBean@2ef5859d
com.g7go.springannotation.MyBean@2ef5859d
和我们要的相符,当然这里仅仅是一个下例子,更多使用场景还需要大家慢慢发现。