官方文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-scopes-custom
| Scope | Description |
| signleton | 默认Spring Bean作用域,一个BeanFactory有且仅有一个实例;换而言之,java里面一些静态字段由一个ClassLoader加载的,因为Class由ClassLoader加载的 |
| prototype | 原型作用域,每次依赖查找和依赖注入生成新Bean对象;脱离Spring容器管理,prototype没有完整的生命周期,如destroy不会执行,可以实现DisposableBean接口来调对象的Bean处理 |
| request | ServletRequest上下文中 |
| session | HttpSession会话中 |
| application | ServletContext上下文中 |
| websocket | websocket连接会话中 |
| custom | 自定义scope |
@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Scope {.../*** Specifies whether a component should be configured as a scoped proxy* and if so, whether the proxy should be interface-based or subclass-based.* <p>Defaults to {@link ScopedProxyMode#DEFAULT}, which typically indicates* that no scoped proxy should be created unless a different default* has been configured at the component-scan instruction level.* <p>Analogous to {@code <aop:scoped-proxy/>} support in Spring XML.* @see ScopedProxyMode*/// INTERFACES jdk动态代理// TARGET_CLASS CGLIB动态代理ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;}
ConfigurationClassPostProcessor
AnnotatedBeanDefinitionReader#register(Class<?>)
案例:实现一个Thread直接共享的Bean实例的Scope
/*** 自定义ThreadLocal Scope注解** @author zli* @create 2020-06-17 11:11**/@Target({ ElementType.TYPE, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documented@Scope(com.zli.spring.ioc.bean.scope.ThreadLocalScope.SCOPE_NAME)public @interface ThreadLocalScope {}
/*** 自定义ThreadLocal Scope实现** @author zli* @create 2020-06-17 10:34**/public class ThreadLocalScope implements Scope, BeanFactoryPostProcessor {public static final String SCOPE_NAME = "thread-local";private final NamedThreadLocal<Map<String, Object>> threadLocal = new NamedThreadLocal("thread-local-scope") {@Overrideprotected Map<String, Object> initialValue() {return new HashMap<>();}};@Overridepublic Object get(String name, ObjectFactory<?> objectFactory) {Map<String, Object> contextMap = getContext();Object object = contextMap.get(name);if (object == null) {object = objectFactory.getObject();contextMap.put(name, object);}return object;}private Map<String, Object> getContext() {return threadLocal.get();}@Overridepublic Object remove(String name) {Map<String, Object> contextMap = getContext();return contextMap.remove(name);}@Overridepublic void registerDestructionCallback(String name, Runnable callback) {// TODO}@Overridepublic Object resolveContextualObject(String key) {Map<String, Object> contextMap = getContext();return contextMap.get(key);}@Overridepublic String getConversationId() {Thread thread = Thread.currentThread();return String.valueOf(thread.getId());}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {beanFactory.registerScope(SCOPE_NAME, this);}}
配置ThreadLocalScope,有以下三种方式:
通过xml配置
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"><property name="scopes"><map><entry key="thread-local"><bean class="com.zli.spring.ioc.bean.scope.ThreadLocalScope"/></entry></map></property></bean>
通过@Bean注解配置
@Beanpublic CustomScopeConfigurer customScopeConfigurer() {CustomScopeConfigurer customScopeConfigurer = new CustomScopeConfigurer();customScopeConfigurer.addScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());return customScopeConfigurer;}
通过实现BeanFactoryPostProcessor接口注册自定义Scope
/*** 自定义ThreadLocal Scope实现** @author zli* @create 2020-06-17 10:34**/public class ThreadLocalScope implements Scope, BeanFactoryPostProcessor {public static final String SCOPE_NAME = "thread-local";...@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 通过BeanFactoryPostProcessor#postProcessBeanFactory注册自定义scopebeanFactory.registerScope(SCOPE_NAME, this);}}/***** @author zli* @create 2020-06-17 10:34**/public class CustomTheadLocalScopeDemo {...public static void main(String[] args) {...// 通过API方式注册自定义ScopeapplicationContext.addBeanFactoryPostProcessor(new ThreadLocalScope());...}...}
通过API(硬编码)注册自定义Scope实现
// 实际就是CustomScopeConfigurer的简化版,通过lambda表达式applicationContext.addBeanFactoryPostProcessor(beanFactory -> {beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());});
/***** @author zli* @create 2020-06-17 10:34**/public class CustomTheadLocalScopeDemo {@Autowiredprivate User user;@Bean//@Scope(value = ThreadLocalScope.SCOPE_NAME)@com.zli.spring.ioc.bean.scope.annotaion.ThreadLocalScopepublic User user() {User user = new User();user.setId(System.nanoTime());return user;}public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();// 注册Configuration ClassapplicationContext.register(CustomTheadLocalScopeDemo.class);// 通过API方式注册自定义Scope/*applicationContext.addBeanFactoryPostProcessor(beanFactory -> {beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());});*/// 刷新上下文applicationContext.refresh();// 单线程获取实例singletonThread(applicationContext);// 多线程获取实例multiThread(applicationContext);// 关闭上下文applicationContext.close();}private static void singletonThread(ApplicationContext applicationContext) {for (int i = 0; i < 3; i++) {System.out.println("singleton thread bean:" + applicationContext.getBean("user", User.class));}}private static void multiThread(AnnotationConfigApplicationContext applicationContext) {for (int i = 0; i < 3; i++) {new Thread(() -> System.out.println(Thread.currentThread().getId() + " multi thread bean:" + applicationContext.getBean("user", User.class))).start();}}@Beanpublic CustomScopeConfigurer customScopeConfigurer() {CustomScopeConfigurer customScopeConfigurer = new CustomScopeConfigurer();customScopeConfigurer.addScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());return customScopeConfigurer;}}
Spring Cloud RefreshCode是如何控制Bean的动态刷新 ?
Spring Cloud RefreshCode通过自动装配实例化
修改Properties资源内容,通过jconsole(RefreshScope被JMX管理)调用refresh、refreshAll方法来动态刷新Bean
@Target({ ElementType.TYPE, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Scope("refresh")@Documentedpublic @interface RefreshScope {/*** @see Scope#proxyMode()* @return proxy mode*/// 默认使用CGLIB动态代理,即被@RefreshScope标记的类是使用CGLIB动态代理ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;}
/*** @author Dave Syer* @since 3.1*/@ManagedResourcepublic class RefreshScope extends GenericScope implements ApplicationContextAware,ApplicationListener<ContextRefreshedEvent>, Ordered {...@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)throws BeansException {this.registry = registry;// 调用GenericScope父类方法完成BeanDefinition初始化super.postProcessBeanDefinitionRegistry(registry);}// 监听刷新scope事件@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {// 这里主要获取BeanDefinition,判断对应scope来依赖查找start(event);}...// JMX管理方法,可以通过jconsole来调用refresh,需要指定对应bean的名称@ManagedOperation(description = "Dispose of the current instance of bean name "+ "provided and force a refresh on next method execution.")public boolean refresh(String name) {// 如果没有拼接aop代理前缀,则拼接(scopedTarget.)if (!name.startsWith(SCOPED_TARGET_PREFIX)) {// User wants to refresh the bean with this name but that isn't the one in the// cache...name = SCOPED_TARGET_PREFIX + name;}// 调用父类destroy方法销毁bean实例// Ensure lifecycle is finished if bean was disposableif (super.destroy(name)) {// 发布刷新scope事件this.context.publishEvent(new RefreshScopeRefreshedEvent(name));return true;}return false;}// JMX管理方法,可以通过jconsole来调用refreshAll方法,刷新所有被@RefreshScope注解的Bean@ManagedOperation(description = "Dispose of the current instance of all beans "+ "in this scope and force a refresh on next method execution.")public void refreshAll() {super.destroy();this.context.publishEvent(new RefreshScopeRefreshedEvent());}...}
public class ScopedProxyFactoryBean extends ProxyConfig implements FactoryBean<Object>, BeanFactoryAware, AopInfrastructureBean {private final SimpleBeanTargetSource scopedTargetSource = new SimpleBeanTargetSource();@Nullableprivate String targetBeanName;@Nullableprivate Object proxy;public ScopedProxyFactoryBean() {this.setProxyTargetClass(true);}public void setTargetBeanName(String targetBeanName) {this.targetBeanName = targetBeanName;this.scopedTargetSource.setTargetBeanName(targetBeanName);}public void setBeanFactory(BeanFactory beanFactory) {if (!(beanFactory instanceof ConfigurableBeanFactory)) {throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);} else {ConfigurableBeanFactory cbf = (ConfigurableBeanFactory)beanFactory;this.scopedTargetSource.setBeanFactory(beanFactory);ProxyFactory pf = new ProxyFactory();pf.copyFrom(this);pf.setTargetSource(this.scopedTargetSource);Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");Class<?> beanType = beanFactory.getType(this.targetBeanName);if (beanType == null) {throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName + "': Target type could not be determined at the time of proxy creation.");} else {if (!this.isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));}ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));pf.addInterface(AopInfrastructureBean.class);this.proxy = pf.getProxy(cbf.getBeanClassLoader());}}}public Object getObject() {if (this.proxy == null) {throw new FactoryBeanNotInitializedException();} else {return this.proxy;}}public Class<?> getObjectType() {return this.proxy != null ? this.proxy.getClass() : this.scopedTargetSource.getTargetClass();}public boolean isSingleton() {return true;}}
文章转载自帽爹的技术轮子,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




