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 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;
public void destroy() throws Exception {
System.out.println("当前 BeanScopeDemo正在销毁中 ");
this.prototypeUser.destroy();
this.prototypeUser2.destroy();
for (Map.Entry<String, User> entry : this.users.entrySet()) {
String beanName = entry.getKey();
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;
}
});
});
1.4 自定义Scope
实现一个线程级别的Scope,每次新的线程调用的时候,都会创建一个实例
- 实现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;
public class ThreadLocalScope implements Scope {
public static final String SCOPE_NAME = "thread-local";
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());
}
}
- 使用addBeanFactoryPostProcessor注册这个Scope
2.1 单线程下使用:
annotationConfigApplicationContext.addBeanFactoryPostProcessor(beanFactory -> {
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 -> {
beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
});
annotationConfigApplicationContext.refresh();
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 -> {
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
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));
});
}
}
}
改造以后:
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,证明线程安全;
|