/* * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.context.request; import com.alibaba.ttl.TransmittableThreadLocal; import jakarta.faces.context.FacesContext; import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; /** * Holder class to expose the web request in the form of a thread-bound * {@link RequestAttributes} object. The request will be inherited * by any child threads spawned by the current thread if the * {@code inheritable} flag is set to {@code true}. * *
Use {@link RequestContextListener} or
* {@link org.springframework.web.filter.RequestContextFilter} to expose
* the current web request. Note that
* already exposes the current request by default.
*
* 修改 spring 上下文存储方式 将 ThreadLocal 替换为 TransmittableThreadLocal
* 支持线程上下文切换变量传递 异步获取 spring 上下文
*
* @author Juergen Hoeller
* @author Rod Johnson
* @since 2.0
* @see RequestContextListener
* @see org.springframework.web.filter.RequestContextFilter
*/
public abstract class RequestContextHolder {
private static final boolean jsfPresent =
ClassUtils.isPresent("jakarta.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());
// ThreadLocal 替换为 TransmittableThreadLocal
private static final ThreadLocal Exposes the previously bound RequestAttributes instance, if any.
* Falls back to the current JSF FacesContext, if any.
* @return the RequestAttributes currently bound to the thread
* @throws IllegalStateException if no RequestAttributes object
* is bound to the current thread
* @see #setRequestAttributes
* @see ServletRequestAttributes
* @see FacesRequestAttributes
* @see jakarta.faces.context.FacesContext#getCurrentInstance()
*/
public static RequestAttributes currentRequestAttributes() throws IllegalStateException {
RequestAttributes attributes = getRequestAttributes();
if (attributes == null) {
if (jsfPresent) {
attributes = FacesRequestAttributesFactory.getFacesRequestAttributes();
}
if (attributes == null) {
throw new IllegalStateException("No thread-bound request found: " +
"Are you referring to request attributes outside of an actual web request, " +
"or processing a request outside of the originally receiving thread? " +
"If you are actually operating within a web request and still receive this message, " +
"your code is probably running outside of DispatcherServlet: " +
"In this case, use RequestContextListener or RequestContextFilter to expose the current request.");
}
}
return attributes;
}
/**
* Inner class to avoid hard-coded JSF dependency.
*/
private static class FacesRequestAttributesFactory {
@Nullable
public static RequestAttributes getFacesRequestAttributes() {
try {
FacesContext facesContext = FacesContext.getCurrentInstance();
return (facesContext != null ? new FacesRequestAttributes(facesContext) : null);
}
catch (NoClassDefFoundError err) {
// typically for com/sun/faces/util/Util if only the JSF API jar is present
return null;
}
}
}
}