赞
踩
单例,在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);
}
}
可以使用@Scope
,指定作用scopeName ConfigurableBeanFactory.SCOPE_SINGLETON,ConfigurableBeanFactory.SCOPE_PROTOTYPE,默认情况下使用的是Singleton;在每一次调用的时候都会创建一个新的对象,和Singleton形成明确的对比;
区别一:
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(); } } }
可以通过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;
}
});
});
实现一个线程级别的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()); } }
annotationConfigApplicationContext.addBeanFactoryPostProcessor(beanFactory -> {
// 注册自定义Scope
beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
});
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()); } } }
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();
}
}
}
线程号:23—>21028764
线程号:24—>21032245
线程号:22—>21025283
线程号:21—>21021802
线程号:25—>21035726
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)); }); } } }
改造以后:
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; } }
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(); } } } }
结果全是true,证明线程安全;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。