当前位置:   article > 正文

Spring BeanScope

spring beanscope

1. BeanScope

1.1 Singleton

单例,在Bean容器启动初始化后,SingletonBean只会初始化一次;因此对象是唯一的
查看代码org.springframework.beans.factory.support.DefaultSingletonBeanRegistry# registerSingleton

	@Override
	public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
		Assert.notNull(beanName, "Bean name must not be null");
		Assert.notNull(singletonObject, "Singleton object must not be null");
		synchronized (this.singletonObjects) {
			Object oldObject = this.singletonObjects.get(beanName);
			// 可以剔除旧的文档
			if (oldObject != null) {
				throw new IllegalStateException("Could not register object [" + singletonObject +
						"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
			}
			addSingleton(beanName, singletonObject);
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

1.2 Prototype

可以使用@Scope,指定作用scopeName ConfigurableBeanFactory.SCOPE_SINGLETON,ConfigurableBeanFactory.SCOPE_PROTOTYPE,默认情况下使用的是Singleton;在每一次调用的时候都会创建一个新的对象,和Singleton形成明确的对比;

1.3 Singleton和Prototype区别

区别一:
Signleton Bean无论依赖查找还是依赖注入,均为同一对象
Prototype Bean无论依赖查找还是依赖注入,均为新生对象

区别二:
如果依赖注入集合类型的对象,Singleton Bean和Prototype Bean均会存在一个
Prototype Bean 有别于其他的Prototype Bean

区别三:
无论是Singleton Bean 还是Prototype Bean均会执行初始化方法回调
但是只有Singleton Bean会执行销毁方法回调

注重讨论区别三:
Singleton对象会进行初始化和销毁,但是Propototype只会进行初始化
在这里插入图片描述
但是如果想要执行销毁操作,可以通过BeanFactoryPostProcessor操作;

	@Autowired
    private ConfigurableListableBeanFactory beanFactory;  // Resolvable Dependency
     // 在类上实现了DisposableBean接口
     public void destroy() throws Exception {
        System.out.println("当前 BeanScopeDemo正在销毁中 ");
        this.prototypeUser.destroy();
        this.prototypeUser2.destroy();
        // 获取Prototype
        for (Map.Entry<String, User> entry : this.users.entrySet()) {
            String beanName = entry.getKey();
            // 获取到BeanDefinition,对Bean的Singleton属性进行判断,如果需要销毁,直接.destroy()即可;
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            if (!beanDefinition.isSingleton()) {
                entry.getValue().destroy();
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

扩展

可以通过BeanPostProcesser解决,但是一般都不使用此方法,仅作参考学习;实现BeanPostProcessor中的postProcessAfterInitialization方法,在初始化后对Bean进行操作,如果取消return bean操作,这个Bean在初始化后就会消失;

		// 添加生命周期管理
        beanContext.addBeanFactoryPostProcessor(beanFactory -> {
            beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
                @Override
                public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                    System.out.printf("%s Bean名称:%s 在初始化后回调。。。%n", bean.getClass().getName(), beanName);
                    return bean;
                }
            });
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

1.4 自定义Scope

实现一个线程级别的Scope,每次新的线程调用的时候,都会创建一个实例

  1. 实现Spring的Scope接口
package edu.ahau.thinking.in.spring.ioc.scope;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.core.NamedThreadLocal;

import java.util.HashMap;
import java.util.Map;

/**
 * ThreadLocal 级别 Scope
 *
 * @author zhangxuna
 * @date 2021-10-24 21:14
 */
public class ThreadLocalScope implements Scope {
	// 定义一个域名
    public static final String SCOPE_NAME = "thread-local";
	// 定义个线程Bean,里面是beanName和bean
    private final NamedThreadLocal<Map<String, Object>> threadLocal = new NamedThreadLocal("thread-local-scope") {
    	// 防止空指针
        @Override
        protected Map<String, Object> initialValue() {
            return new HashMap<String, Object>();
        }
    };
    /* 获取 */
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> context = getContext();
        Object object = context.get(name);

        if (object == null) {
            object = objectFactory.getObject();
            context.put(name, object);
        }
        return object;
    }

    private Map<String, Object> getContext() {
        return threadLocal.get();
    }

    /* 删除 */
    @Override
    public Object remove(String name) {
        Map<String, Object> context = getContext();
        return context.remove(name);
    }

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

    }

    @Override
    public Object resolveContextualObject(String key) {
        Map<String, Object> context = getContext();
        return context.get(key);
    }

    @Override
    public String getConversationId() {
        Thread thread = Thread.currentThread();

        return String.valueOf(thread.getId());
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  1. 使用addBeanFactoryPostProcessor注册这个Scope
    2.1 单线程下使用:
annotationConfigApplicationContext.addBeanFactoryPostProcessor(beanFactory -> {
                // 注册自定义Scope
                beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
            });
  • 1
  • 2
  • 3
  • 4
public class ThreadLocalScopeDemo {

    @Bean
    @Scope(ThreadLocalScope.SCOPE_NAME)
    public User user() {
        User user = new User();
        user.setAge((int) Thread.currentThread().getId());
        return user;
    }

    public static void main(String[] args) {
        try (AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext()) {
            annotationConfigApplicationContext.register(ThreadLocalScopeDemo.class);
            annotationConfigApplicationContext.addBeanFactoryPostProcessor(beanFactory -> {
                // 注册自定义Scope
                beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
            });
            annotationConfigApplicationContext.refresh();
//            for (int i = 0; i < 5; i++) {
//                new Thread(()->{
//                    System.out.println(annotationConfigApplicationContext.getBean(User.class).hashCode());
//                }).start();
//            }
            System.out.println(annotationConfigApplicationContext.getBean(User.class).hashCode());
            System.out.println(annotationConfigApplicationContext.getBean(User.class).hashCode());

        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

20952182
20952182

2.2 多线程下使用

	public static void main(String[] args) {
        try (AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext()) {
            annotationConfigApplicationContext.register(ThreadLocalScopeDemo.class);
            annotationConfigApplicationContext.addBeanFactoryPostProcessor(beanFactory -> {
                // 注册自定义Scope
                beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
            });
            annotationConfigApplicationContext.refresh();
            for (int i = 0; i < 5; i++) {
                new Thread(()->{
                    System.out.println("线程号:"+Thread.currentThread().getId()+"--->"+annotationConfigApplicationContext.getBean(User.class).hashCode());
                }).start();
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

线程号:23—>21028764
线程号:24—>21032245
线程号:22—>21025283
线程号:21—>21021802
线程号:25—>21035726

1.5 改善SimpleDateFormat

SimpleDateFormat是多线程不安全的;

public class SimpleDateFormatScope {
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private final static ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 60, TimeUnit.MINUTES, new LinkedBlockingQueue<>(100000));

    public static void main(String[] args) {
        while (true) {
            executor.execute(() -> {
                String format = simpleDateFormat.format(new Date());
                Date parseDate = null;
                try {
                        parseDate = simpleDateFormat.parse(format);

                } catch (ParseException e) {
                    e.printStackTrace();
                }
                String dateString2 = simpleDateFormat.format(parseDate);
                System.out.println(format.equals(dateString2));
            });
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

改造以后:

  • 自定义一个Scope
public class SimpleDateFormatScope implements Scope {
    public static final String SCOPE_NAME = "simpleDateFormatScope";

    private static final NamedThreadLocal<Map<String, Object>> simpleDateFormatObject = new NamedThreadLocal<Map<String, Object>>("SimpleDateFormatScope") {
        @Override
        protected Map<String, Object> initialValue() {
            Map<String, Object> map = new HashMap<>();
            map.put("simpleDateFormat", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") );
            return map;
        }
    };


    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> context = getContext();
        Object object = context.get(name);
        if (object == null) {
            context.put("simpleDateFormat", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") );
        }
        return object;
    }

    private Map<String, Object> getContext() {
        return simpleDateFormatObject.get();
    }

    @Override
    public Object remove(String name) {
        return null;
    }

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

    }

    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }

    @Override
    public String getConversationId() {
        return null;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 创建测试类
public class SimpleDateFormateTest {
   @Bean("simpleDateFormat")
   @Scope(SimpleDateFormatScope.SCOPE_NAME)
   public SimpleDateFormat getSimpleDateFormat() {
       return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   }
   public static void main(String[] args) {
       try (AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext()) {
         annotationConfigApplicationContext.register(SimpleDateFormateTest.class);
         annotationConfigApplicationContext.addBeanFactoryPostProcessor(beanFactory -> beanFactory.registerScope(SimpleDateFormatScope.SCOPE_NAME, new SimpleDateFormatScope()));
         annotationConfigApplicationContext.refresh();
           for (int i = 0; i < 500; i++) {
               new Thread(()->{
                   SimpleDateFormat simpleDateFormat = annotationConfigApplicationContext.getBean(SimpleDateFormat.class);
                   String format = simpleDateFormat.format(new Date());
                   Date parseDate = null;
                   try {
                       parseDate = simpleDateFormat.parse(format);
                   } catch (ParseException e) {
                       e.printStackTrace();
                   }
                   String dateString2 = simpleDateFormat.format(parseDate);
                   System.out.println(format.equals(dateString2));
               }).start();
           }
       }
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

结果全是true,证明线程安全;

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/540209
推荐阅读
相关标签
  

闽ICP备14008679号