001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.context.request; 018 019import org.springframework.beans.factory.ObjectFactory; 020import org.springframework.beans.factory.config.Scope; 021import org.springframework.lang.Nullable; 022 023/** 024 * Abstract {@link Scope} implementation that reads from a particular scope 025 * in the current thread-bound {@link RequestAttributes} object. 026 * 027 * <p>Subclasses simply need to implement {@link #getScope()} to instruct 028 * this class which {@link RequestAttributes} scope to read attributes from. 029 * 030 * <p>Subclasses may wish to override the {@link #get} and {@link #remove} 031 * methods to add synchronization around the call back into this super class. 032 * 033 * @author Rod Johnson 034 * @author Juergen Hoeller 035 * @author Rob Harrop 036 * @since 2.0 037 */ 038public abstract class AbstractRequestAttributesScope implements Scope { 039 040 @Override 041 public Object get(String name, ObjectFactory<?> objectFactory) { 042 RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); 043 Object scopedObject = attributes.getAttribute(name, getScope()); 044 if (scopedObject == null) { 045 scopedObject = objectFactory.getObject(); 046 attributes.setAttribute(name, scopedObject, getScope()); 047 // Retrieve object again, registering it for implicit session attribute updates. 048 // As a bonus, we also allow for potential decoration at the getAttribute level. 049 Object retrievedObject = attributes.getAttribute(name, getScope()); 050 if (retrievedObject != null) { 051 // Only proceed with retrieved object if still present (the expected case). 052 // If it disappeared concurrently, we return our locally created instance. 053 scopedObject = retrievedObject; 054 } 055 } 056 return scopedObject; 057 } 058 059 @Override 060 @Nullable 061 public Object remove(String name) { 062 RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); 063 Object scopedObject = attributes.getAttribute(name, getScope()); 064 if (scopedObject != null) { 065 attributes.removeAttribute(name, getScope()); 066 return scopedObject; 067 } 068 else { 069 return null; 070 } 071 } 072 073 @Override 074 public void registerDestructionCallback(String name, Runnable callback) { 075 RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); 076 attributes.registerDestructionCallback(name, callback, getScope()); 077 } 078 079 @Override 080 @Nullable 081 public Object resolveContextualObject(String key) { 082 RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); 083 return attributes.resolveReference(key); 084 } 085 086 087 /** 088 * Template method that determines the actual target scope. 089 * @return the target scope, in the form of an appropriate 090 * {@link RequestAttributes} constant 091 * @see RequestAttributes#SCOPE_REQUEST 092 * @see RequestAttributes#SCOPE_SESSION 093 */ 094 protected abstract int getScope(); 095 096}