前言
前两天分析了一波@ComponentScan注解各属性作用,通过源码看到根据类上的@Scope注解为BeanDefinition设置了ScopedProxyMode属性,并对BeanDefinition进行代理操作。大概就是如果这个BeanDefinition有@Scope,就会new一个BeanDefinition将原先的BeanDefition替换,具体看上篇文吧。注意新创建的BeanDefinition的beanClass是ScopedProxyFactoryBean,是一个FactoryBean相关代码如下
// 创建一个新的BeanDefition来作为代理的beanDefition,把原先的对象作为成员设置进去
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
Scope常见的在Web应用中有session、request、application,还有cloud里边的@RefreshScope等。
一个一个来吧,以后碰到哪个分析完再接到这篇上。
@SessionScope和@RequestScope
每个Session或每个Request创建一个对象
先来看获取Bean对象的代码
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
// 不相关代码都删了
if (mbd.isSingleton()) {
// 获取单例bean实例
}
else if (mbd.isPrototype()) {
// 获取原型模式实例
}
else {
// 获取BeanDefinition的scope,即session\request
String scopeName = mbd.getScope();
// 这个集合中保存了这个字符串“session”对应的哪个Scope对象,用这个Scope对象来进行创建操作
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
// 获取被代理过的BeanDefition对应的FactoryBean对象
// 先进去看看对应Scope对象的get操作是什么
// createBean方法不用看了,就是根据bean定义创建实例,以前看过,这里不是目标就略过,知道这当作一个参数传进scope.get就可以了
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
// FactoryBean.getObject来获取真正的bean实例
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
// 报异常
}
beanFactory中的this.scopes集合怎么来的呢
在AbstractApplicationContext的refresh方法的postProcessBeanFactory()这一步添加的,AbstractApplicationContext这里只是模板方法,具体实现在Web容器的实现类AnnotationConfigServletWebServerApplicationContext#postProcessBeanFactory
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.postProcessBeanFactory(beanFactory);
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
if (!this.annotatedClasses.isEmpty()) {
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
}
父类方法org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#postProcessBeanFactory
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
registerWebApplicationScopes();
}
private void registerWebApplicationScopes() {
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());
WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
existingScopes.restore();
}
// 直接跟到WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
@Nullable ServletContext sc) {
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
}
那此时beanFactory有了session和request的Scope对象,来看SessionScope的get方法
org.springframework.web.context.request.SessionScope#get
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex();
synchronized (mutex) {
return super.get(name, objectFactory);
}
}
// 进父类
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
// 从ThreadLocal变量中获取当前request的属性对象
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
// 从属性中根据bean名获取bean对象
Object scopedObject = attributes.getAttribute(name, getScope());
if (scopedObject == null) {
// 如果没有会调用CreateBean方法新建一个,并设置到当前请求上下文属性中
scopedObject = objectFactory.getObject();
attributes.setAttribute(name, scopedObject, getScope());
// Retrieve object again, registering it for implicit session attribute updates.
// As a bonus, we also allow for potential decoration at the getAttribute level.
Object retrievedObject = attributes.getAttribute(name, getScope());
if (retrievedObject != null) {
// Only proceed with retrieved object if still present (the expected case).
// If it disappeared concurrently, we return our locally created instance.
scopedObject = retrievedObject;
}
}
return scopedObject;
}
跟进去再看看RequestAttributes这个请求属性对象哪来的
public abstract class RequestContextHolder {
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<>("Request attributes");
private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
new NamedInheritableThreadLocal<>("Request context");
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = requestAttributesHolder.get();
if (attributes == null) {
attributes = inheritableRequestAttributesHolder.get();
}
return attributes;
}
}
从请求对象RequestAttribute中根据beanName获取实例代码
@Override
public Object getAttribute(String name, int scope) {
// scope是request
if (scope == SCOPE_REQUEST) {
// 如果请求已经处理完毕,判断了一个boolean值,下边有介绍
if (!isRequestActive()) {
throw new IllegalStateException(
"Cannot ask for request attribute - request is not active anymore!");
}
return this.request.getAttribute(name);
}
else {
HttpSession session = getSession(false);
if (session != null) {
try {
Object value = session.getAttribute(name);
if (value != null) {
this.sessionAttributesToUpdate.put(name, value);
}
return value;
}
catch (IllegalStateException ex) {
// Session invalidated - shouldn't usually happen.
}
}
return null;
}
}
好家伙,又来新知识了,这个RequestAttribute对象很关键,从线程ThreadLocal变量获取的,这可以理解,一个请求一个线程来处理嘛,那这个对象啥时候被设置进去的呢。思考了下,估计是DispatchServlet接受请求分发的时候处理,我们继续跟代码
DispatchServlet那肯定先看service(),先走爷爷类HttpServlet#service,这里没有,再看父类FrameworkServlet#service,有了
org.springframework.web.servlet.FrameworkServlet#service
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
// 这里
processRequest(request, response);
}
else {
super.service(request, response);
}
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 忽略了无关代码
// 获取原先的RequestAttribute
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
// new一个新的
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
// 设置到RequestContextHolder的ThreadLocal中
initContextHolders(request, localeContext, requestAttributes);
// diService()执行
try {
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
// 重新设置回原来的
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
// 请求处理完毕,把刚才new的那个requestAttributes请求标志置为完成
// 上边判断请求是否存活isRequestActive(),就是跟这个有关
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
protected ServletRequestAttributes buildRequestAttributes(HttpServletRequest request,
@Nullable HttpServletResponse response, @Nullable RequestAttributes previousAttributes) {
if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {
// 实际上RequestAttributes对象是一个ServletRequestAttributes对象
// 绑定了request和response
return new ServletRequestAttributes(request, response);
}
else {
return null; // preserve the pre-bound RequestAttributes instance
}
}
// 把ServletRequestAttributes 设置到当前的ThreadLocal变量中
private void initContextHolders(HttpServletRequest request,
@Nullable LocaleContext localeContext, @Nullable RequestAttributes requestAttributes) {
if (localeContext != null) {
LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
}
if (requestAttributes != null) {
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
}
}
看到这,这个BeanDefinition对应的bean实例化出来了,那开篇说过,有@Scope注解的beanDefinition是被狸猫换太子的,是一个FactoryBean(ScopedProxyFactoryBean),还得继续看ScopedProxyFactoryBean.getObject()
ScopedProxyFactoryBean实现了BeanFactoryAware,setBeanFactory方法执行的时候创建的代理对象,getObject返回代理对象。
怎么代理的就先不管了,单写一篇学习代理。代理对象的方法拦截器DynamicAdvisedInterceptor中会再getBean()从beanFactory获取最初的beanDefinition的对象进行invoke,最初的beanDefinition也是个scope类型,跟上边的ScopedProxyFactoryBean实例化走一个路子。
public class ScopedProxyFactoryBean extends ProxyConfig
implements FactoryBean<Object>, BeanFactoryAware, AopInfrastructureBean {
@Override
public void setBeanFactory(BeanFactory beanFactory) {
if (!(beanFactory instanceof ConfigurableBeanFactory)) {
throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
}
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.");
}
if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
}
// Add an introduction that implements only the methods on ScopedObject.
ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));
// Add the AopInfrastructureBean marker to indicate that the scoped proxy
// itself is not subject to auto-proxying! Only its target bean is.
pf.addInterface(AopInfrastructureBean.class);
this.proxy = pf.getProxy(cbf.getBeanClassLoader());
}
@Override
public Object getObject() {
if (this.proxy == null) {
throw new FactoryBeanNotInitializedException();
}
return this.proxy;
}
}
到这基本就完事了,总结:
1、每次请求上来将新建一个ServletRequestAttribute对象绑定request和response,并注册到RequestContextHolder类中的ThreadLocal变量上
2、在Web容器refresh方法,ServletWebServerApplicationContext#postProcessBeanFactory中注册工具类SessionScope和RequestScope用来实例化bean时调用
3、解析beanDefinition时,@SessionScope或@RequestScope注解的beanDefinition的Scope属性设置为request或session,并且原先的beanDefinition已经被替换(ScopedProxyFactoryBean)
4、doGetBean获取Scope属性为request或session类型的bean类实例时使用SessionScope.get(beanName, ObjectFactory)或RequestScope.get(beanName, ObjectFactory)来获取,先获取这个ServletRequestAttribute对象,如果这对象中对应的HttpServletRequest或request对应的Session没有这个bean实例,再调用ObjectFactory.getObject()方法创建,getObject()具体工作是由AbstractBeanFactory#createBean来创建
5、上一步创建的东西只是ScopedProxyFactoryBean,FactoryBean.getObject() 获取代理对象,代理对象拦截器方法中再getBean()获取真正的bean对象执行操作