自定义 Bean 作用域

2021-02-23

Spring 实现自定义的 bean 作用域

  • 实现 Scope 接口
  • 调用 AbstractBeanFactory#registerScope 方法
  • bean 配置的地方指定作用域,如 <bean scope=""> 或 @Scope("")

 

以下实现一个线程级别的 bean 的作用域

先看 Scope 接口的实现

/**
 * 线程级别 scope
 * 
 * @author ConstXiong
 */
public class ThreadLocalScope implements Scope {
	
	public static final String SCOPE_NAME = "thread-local";
	
	private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL = new ThreadLocal<Map<String, Object>>() {
		@Override
		protected Map<String, Object> initialValue() {
	        return new HashMap<>();
	    }
	}; 

	@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
		Map<String, Object> map = THREAD_LOCAL.get();
		Object object = map.get(name);
		if (object == null) {
			object = objectFactory.getObject();
			map.put(name, object);
		}
		return object;
	}

	@Override
	public Object remove(String name) {
		return THREAD_LOCAL.get().remove(name);
	}

	@Override
	public void registerDestructionCallback(String name, Runnable callback) {
	}

	@Override
	public Object resolveContextualObject(String key) {
		return THREAD_LOCAL.get().remove(key);
	}

	@Override
	public String getConversationId() {
		return String.valueOf(Thread.currentThread().getId());
	}

}

 

使用 ApplicationContextAware 接口获取 ApplicationContext,在其 BeanFactory 中注册 ThreadLocalScope

/**
 * 注册 ThreadLocalScope
 * 
 * @author ConstXiong
 */
@Component
public class ScopeRegister implements ApplicationContextAware {

	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		WebApplicationContext context = (WebApplicationContext)applicationContext;
		DefaultListableBeanFactory beanFactory = ((DefaultListableBeanFactory)context.getAutowireCapableBeanFactory());
		beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
	}

}

 

bean 配置与 controller

/**
 * controller
 * 
 * @author ConstXiong
 */
@Controller
public class IndexController {
	
	@Autowired
	private ApplicationContext context;
	
	@RequestMapping("thread")
	@ResponseBody
	public String thread() {
		User user = context.getBean("user", User.class);
		return String.format("thread:%s, user:%s", Thread.currentThread().getId(), user);
	}
	
	@Bean
	@Scope(ThreadLocalScope.SCOPE_NAME)
	private static User user() {
		return new User();
	}
	
}

 

ConstXiong 备案号:苏ICP备16009629号-3