单例模式与Spring作用域引言Spring Framework通过默认单例作用域大大简化了Bean管理但同时也提供了多种作用域以适应不同场景需求。理解Spring Bean的作用域机制对于设计高性能应用至关重要。本文将详细介绍Spring的各种作用域及其使用场景。一、单例作用域1.1 默认行为Component public class UserService { // 默认单例容器中只有一个实例 } // 显式声明 Component Scope(singleton) public class SingletonService { // 明确单例 } Bean Scope(singleton) public SingletonBean singletonBean() { return new SingletonBean(); }1.2 单例模式原理public class DefaultSingletonBeanRegistry { // 一级缓存成品Bean private final MapString, Object singletonObjects new ConcurrentHashMap(); // 二级缓存早期Bean private final MapString, Object earlySingletonObjects new ConcurrentHashMap(); // 三级缓存Bean工厂 private final MapString, ObjectFactory? singletonFactories new ConcurrentHashMap(); public Object getSingleton(String beanName) { Object singleton singletonObjects.get(beanName); if (singleton null) { synchronized (singletonObjects) { singleton singletonObjects.get(beanName); if (singleton null) { ObjectFactory? factory singletonFactories.get(beanName); if (factory ! null) { singleton factory.getObject(); earlySingletonObjects.put(beanName, singleton); singletonFactories.remove(beanName); } } } } return singleton; } }二、 Prototype作用域2.1 基本用法Component Scope(prototype) public class OrderProcessor { // 每次注入创建新实例 } Service public class OrderService { private final OrderProcessor processor; public OrderService(OrderProcessor processor) { // 每次注入都会创建新的processor实例 this.processor processor; } }2.2 生命周期Component Scope(prototype) public class HeavyObject { public HeavyObject() { System.out.println(Creating new HeavyObject); } PreDestroy public void cleanup() { // Prototype Bean不会被Spring管理销毁 System.out.println(Cleanup not called); } }三、Web作用域3.1 Request作用域Component Scope(value WebApplicationContext.SCOPE_REQUEST, proxyMode ScopedProxyMode.TARGET_CLASS) public class RequestContext { private MapString, Object attributes new HashMap(); public void setAttribute(String key, Object value) { attributes.put(key, value); } public Object getAttribute(String key) { return attributes.get(key); } } RestController public class UserController { Autowired private RequestContext requestContext; GetMapping(/test) public String test() { requestContext.setAttribute(test, value); return ok; } }3.2 Session作用域Component Scope(value WebApplicationContext.SCOPE_SESSION, proxyMode ScopedProxyMode.TARGET_CLASS) public class UserSession { private User user; private ListString visitedPages new ArrayList(); public User getUser() { return user; } public void setUser(User user) { this.user user; } public void addVisitedPage(String page) { visitedPages.add(page); } } Service public class AnalyticsService { Autowired private UserSession userSession; public void trackPageVisit(String page) { userSession.addVisitedPage(page); } }3.3 Application作用域Component Scope(value WebApplicationContext.SCOPE_APPLICATION, proxyMode ScopedProxyMode.TARGET_CLASS) public class AppContext { private MapString, Object sharedData new ConcurrentHashMap(); public void put(String key, Object value) { sharedData.put(key, value); } public Object get(String key) { return sharedData.get(key); } }四、自定义作用域4.1 ThreadLocal作用域public class ThreadScope implements Scope { private final ThreadLocalMapString, Object threadScope ThreadLocal.withInitial(HashMap::new); Override public Object get(String name, ObjectFactory? objectFactory) { MapString, Object scope threadScope.get(); Object value scope.get(name); if (value null) { value objectFactory.getObject(); scope.put(name, value); } return value; } Override public Object remove(String name) { MapString, Object scope threadScope.get(); return scope.remove(name); } Override public void registerDestructionCallback(String name, Runnable callback) { // 实现销毁回调 } Override public Object resolveContextualObject(String key) { return null; } Override public String getConversationId() { return Thread.currentThread().getName(); } }4.2 注册自定义作用域Configuration public class ScopeConfig { Bean public static CustomScopeConfigurer customScopeConfigurer() { CustomScopeConfigurer configurer new CustomScopeConfigurer(); configurer.addScope(thread, new ThreadScope()); return configurer; } } Component Scope(thread) public class ThreadScopedBean { // 线程内单例 }五、作用域代理5.1 为什么需要代理// 问题不使用代理 Service public class BadService { Autowired private RequestContext requestContext; // 注入失败 } // 解决使用代理 Service public class GoodService { Autowired Scope(value WebApplicationContext.SCOPE_REQUEST, proxyMode ScopedProxyMode.TARGET_CLASS) private RequestContext requestContext; }5.2 代理类型// 基于接口的代理需要接口 Scope(value SCOPE_REQUEST, proxyMode ScopedProxyMode.INTERFACES) private RequestContext requestContext; // 注入接口代理 // 基于类的代理需要CGLIB Scope(value SCOPE_REQUEST, proxyMode ScopedProxyMode.TARGET_CLASS) private RequestContext requestContext; // 注入CGLIB代理六、作用域组合6.1 单例中的原型BeanService public class SingletonService { private final ObjectFactoryPrototypeBean prototypeFactory; public SingletonService( ObjectFactoryPrototypeBean prototypeFactory) { this.prototypeFactory prototypeFactory; } public void usePrototype() { // 每次获取新实例 PrototypeBean bean prototypeFactory.getObject(); bean.doSomething(); } } Configuration public class BeanConfig { Bean Scope(prototype) public PrototypeBean prototypeBean() { return new PrototypeBean(); } }6.2 MethodFactory注入Component public class ServiceWithProvider { private final ProviderPrototypeBean prototypeProvider; public ServiceWithProvider( ProviderPrototypeBean prototypeProvider) { this.prototypeProvider prototypeProvider; } public void doSomething() { PrototypeBean bean prototypeProvider.get(); bean.execute(); } }七、最佳实践7.1 作用域选择原则无状态Bean使用单例有状态的Bean根据状态范围选择合适作用域原型Bean慎用注意生命周期管理。7.2 性能考虑单例减少对象创建开销但增加内存占用原型Bean每次创建新实例适用于重量级对象。7.3 作用域嵌套Component Scope(value session, proxyMode ScopedProxyMode.TARGET_CLASS) public class ShoppingCart { Autowired private ProductCache productCache; // 单例线程安全 public void addProduct(Product product) { // 业务逻辑 } }总结Spring提供了丰富的Bean作用域支持从单例到自定义作用域应有尽有。理解各种作用域的特性和使用场景选择合适的作用域可以构建既高效又灵活的应用。需要注意原型作用域的销毁回调问题以及单例中注入原型Bean的正确方式。
单例模式与Spring作用域
单例模式与Spring作用域引言Spring Framework通过默认单例作用域大大简化了Bean管理但同时也提供了多种作用域以适应不同场景需求。理解Spring Bean的作用域机制对于设计高性能应用至关重要。本文将详细介绍Spring的各种作用域及其使用场景。一、单例作用域1.1 默认行为Component public class UserService { // 默认单例容器中只有一个实例 } // 显式声明 Component Scope(singleton) public class SingletonService { // 明确单例 } Bean Scope(singleton) public SingletonBean singletonBean() { return new SingletonBean(); }1.2 单例模式原理public class DefaultSingletonBeanRegistry { // 一级缓存成品Bean private final MapString, Object singletonObjects new ConcurrentHashMap(); // 二级缓存早期Bean private final MapString, Object earlySingletonObjects new ConcurrentHashMap(); // 三级缓存Bean工厂 private final MapString, ObjectFactory? singletonFactories new ConcurrentHashMap(); public Object getSingleton(String beanName) { Object singleton singletonObjects.get(beanName); if (singleton null) { synchronized (singletonObjects) { singleton singletonObjects.get(beanName); if (singleton null) { ObjectFactory? factory singletonFactories.get(beanName); if (factory ! null) { singleton factory.getObject(); earlySingletonObjects.put(beanName, singleton); singletonFactories.remove(beanName); } } } } return singleton; } }二、 Prototype作用域2.1 基本用法Component Scope(prototype) public class OrderProcessor { // 每次注入创建新实例 } Service public class OrderService { private final OrderProcessor processor; public OrderService(OrderProcessor processor) { // 每次注入都会创建新的processor实例 this.processor processor; } }2.2 生命周期Component Scope(prototype) public class HeavyObject { public HeavyObject() { System.out.println(Creating new HeavyObject); } PreDestroy public void cleanup() { // Prototype Bean不会被Spring管理销毁 System.out.println(Cleanup not called); } }三、Web作用域3.1 Request作用域Component Scope(value WebApplicationContext.SCOPE_REQUEST, proxyMode ScopedProxyMode.TARGET_CLASS) public class RequestContext { private MapString, Object attributes new HashMap(); public void setAttribute(String key, Object value) { attributes.put(key, value); } public Object getAttribute(String key) { return attributes.get(key); } } RestController public class UserController { Autowired private RequestContext requestContext; GetMapping(/test) public String test() { requestContext.setAttribute(test, value); return ok; } }3.2 Session作用域Component Scope(value WebApplicationContext.SCOPE_SESSION, proxyMode ScopedProxyMode.TARGET_CLASS) public class UserSession { private User user; private ListString visitedPages new ArrayList(); public User getUser() { return user; } public void setUser(User user) { this.user user; } public void addVisitedPage(String page) { visitedPages.add(page); } } Service public class AnalyticsService { Autowired private UserSession userSession; public void trackPageVisit(String page) { userSession.addVisitedPage(page); } }3.3 Application作用域Component Scope(value WebApplicationContext.SCOPE_APPLICATION, proxyMode ScopedProxyMode.TARGET_CLASS) public class AppContext { private MapString, Object sharedData new ConcurrentHashMap(); public void put(String key, Object value) { sharedData.put(key, value); } public Object get(String key) { return sharedData.get(key); } }四、自定义作用域4.1 ThreadLocal作用域public class ThreadScope implements Scope { private final ThreadLocalMapString, Object threadScope ThreadLocal.withInitial(HashMap::new); Override public Object get(String name, ObjectFactory? objectFactory) { MapString, Object scope threadScope.get(); Object value scope.get(name); if (value null) { value objectFactory.getObject(); scope.put(name, value); } return value; } Override public Object remove(String name) { MapString, Object scope threadScope.get(); return scope.remove(name); } Override public void registerDestructionCallback(String name, Runnable callback) { // 实现销毁回调 } Override public Object resolveContextualObject(String key) { return null; } Override public String getConversationId() { return Thread.currentThread().getName(); } }4.2 注册自定义作用域Configuration public class ScopeConfig { Bean public static CustomScopeConfigurer customScopeConfigurer() { CustomScopeConfigurer configurer new CustomScopeConfigurer(); configurer.addScope(thread, new ThreadScope()); return configurer; } } Component Scope(thread) public class ThreadScopedBean { // 线程内单例 }五、作用域代理5.1 为什么需要代理// 问题不使用代理 Service public class BadService { Autowired private RequestContext requestContext; // 注入失败 } // 解决使用代理 Service public class GoodService { Autowired Scope(value WebApplicationContext.SCOPE_REQUEST, proxyMode ScopedProxyMode.TARGET_CLASS) private RequestContext requestContext; }5.2 代理类型// 基于接口的代理需要接口 Scope(value SCOPE_REQUEST, proxyMode ScopedProxyMode.INTERFACES) private RequestContext requestContext; // 注入接口代理 // 基于类的代理需要CGLIB Scope(value SCOPE_REQUEST, proxyMode ScopedProxyMode.TARGET_CLASS) private RequestContext requestContext; // 注入CGLIB代理六、作用域组合6.1 单例中的原型BeanService public class SingletonService { private final ObjectFactoryPrototypeBean prototypeFactory; public SingletonService( ObjectFactoryPrototypeBean prototypeFactory) { this.prototypeFactory prototypeFactory; } public void usePrototype() { // 每次获取新实例 PrototypeBean bean prototypeFactory.getObject(); bean.doSomething(); } } Configuration public class BeanConfig { Bean Scope(prototype) public PrototypeBean prototypeBean() { return new PrototypeBean(); } }6.2 MethodFactory注入Component public class ServiceWithProvider { private final ProviderPrototypeBean prototypeProvider; public ServiceWithProvider( ProviderPrototypeBean prototypeProvider) { this.prototypeProvider prototypeProvider; } public void doSomething() { PrototypeBean bean prototypeProvider.get(); bean.execute(); } }七、最佳实践7.1 作用域选择原则无状态Bean使用单例有状态的Bean根据状态范围选择合适作用域原型Bean慎用注意生命周期管理。7.2 性能考虑单例减少对象创建开销但增加内存占用原型Bean每次创建新实例适用于重量级对象。7.3 作用域嵌套Component Scope(value session, proxyMode ScopedProxyMode.TARGET_CLASS) public class ShoppingCart { Autowired private ProductCache productCache; // 单例线程安全 public void addProduct(Product product) { // 业务逻辑 } }总结Spring提供了丰富的Bean作用域支持从单例到自定义作用域应有尽有。理解各种作用域的特性和使用场景选择合适的作用域可以构建既高效又灵活的应用。需要注意原型作用域的销毁回调问题以及单例中注入原型Bean的正确方式。