第三章 Spring bean多实例与动态代理笔记
一、Bean的多例作用域
1、多实例bean的初始化
1)多实例bean在每次获取bean的时候都会触发getBean操作,因此每次获取都是创建了一个新的对象返回,不论是多线程获取或者是同一个线程获取两次,都是返回一个新的实例对象。
2)多例模式情况,如果出现循环依赖,会直接报错
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
//如果是scope 是Prototype的,校验是否有出现循环依赖,如果有则直接报错
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
else if (mbd.isPrototype()) {
// It’s a prototype -> create a new instance.
- Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}finally {
afterPrototypeCreation(beanName);
} //改方法是FactoryBean接口的调用入口* - *bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
2、Bean的作用域
Scope如果是Prototype时,不管是不是同一个线程,只要是getBean就会得到一个新的实例。
Request作用域时,是把实例存储到request对象中
Session作用域时,是把实例存储到session对象中,request和session作用域只会在web环境才会存在(例如Tomcat服务)
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException(“No Scope registered for scope name ‘“ + scopeName + “‘“);
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}finally {
afterPrototypeCreation(beanName);
}
});
//该方法是FactoryBean接口的调用入口
- bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}catch (IllegalStateException ex) {
*throw new BeanCreationException(beanName,
}**"Scope '"** \+ scopeName + **"' is not active for the current thread; consider "** \+
**"defining a scoped proxy for this bean if you intend to refer to it from a singleton"**, ex);
}
/\* Map from scope identifier String to corresponding Scope. */*
private final Map
3、自定义作用域
3.1、要获取BeanFactory对象,必须实现BeanFactoryPostProcessor接口才能获取BeanFactory对象。
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerScope(“hankinScope”,new CustomScope());
}
}
3.2、调用registerScope方法把自定义的scope注册进去
beanFactory.registerScope(“hankinScope”,new CustomScope());
3.3、写一个类实现scope接口
public class CustomScope implements Scope {
private ThreadLocal local = new ThreadLocal();
//这个方法就是自己管理bean
- @Override
public Object get(String name, ObjectFactory<?> objectFactory) {
System.**out*.println(“=============CustomScope========”); if(local.get() != null**) {
} else {**return** **local**.get();
*//这个方法就是掉createbean方法获得一个实例*
- Object object = objectFactory.getObject();
local.set(object);
*return object;
}
}
@Component
@Scope(“hankinScope”)
public class CustomScopeBean {
private String username;
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
}
4、Bean的销毁
在bean创建完成后就会对这个bean注册一个销毁的Adapter对象,代码如下:
// Register bean as disposable.
try {
//注册bean销毁时的类DisposableBeanAdapter
**registerDisposableBeanIfNecessary(beanName, bean, mbd);**
}
registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
这个DisposableBeanAdapter对象就是负责bean销毁的类。在这个类中收集了该bean是否实现了DisposableBean接口,是否配置destroy-method属性,过滤了DestructionAwareBeanPostProcessor类型的接口。
然后**bean是在什么时候被销毁呢,在tomcat关闭的时候就会调用到servlet**中的销毁方法
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
- // work for the given bean: DestructionAwareBeanPostProcessors,*
- // DisposableBean interface, custom destroy method.*
- *registerDisposableBean(beanName,
}else { // A bean with a custom scope…**new** DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
- Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException(“No Scope registered for scope name ‘“ + mbd.getScope() + *”‘“);
}
scope.registerDestructionCallback(beanName,
}**new** DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
在这个方法中就会最终掉用到DisposableBeanAdapter类的,destroy()方法,该方法就会根据前面的收集进行调用。
@Override
public void run() {
destroy();
}
@Override
public void destroy() {
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
processor.postProcessBeforeDestruction(this.bean, this.beanName);
}
}
if (this.invokeDisposableBean) {
if (logger.isTraceEnabled()) {
logger.trace(“Invoking destroy() on bean with name ‘“ + this.beanName + “‘“);
}
try {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedExceptionAction
还没有评论,来说两句吧...