Usually this request attribute is set for all sub-classes of
AbstractUrlHandlerMapping and therefore whenever
AnnotationMethodHandlerAdapter is used. However, having a
default value to fall back on in AnnotationMethodHandlerAdapter
is still appropriate in general and also considering the Javadoc
of HandlerMapping.INTROSPECT_TYPE_LEVEL_MAPPING.
Issue: SPR-9629
Backport-Issue: SPR-9633
Before this change the StringHttpMessageConverter used a fixed charset "ISO-8859-1" if the requested content type did not specify one. This change adds a defaultCharset field and a constructor to configure it in StringHttpMessageConverter.
Issue: SPR-9487
Prior to this change, PropertySourcesPropertyResolver (and therefore
all AbstractEnvironment) implementations failed to resolve nested
placeholders as in the following example:
p1=v1
p2=v2
p3=${v1}:{$v2}
Calls to PropertySource#getProperty for keys 'p1' and 'v1' would
successfully return their respective values, but for 'p3' the return
value would be the unresolved placeholders. This behavior is
inconsistent with that of PropertyPlaceholderConfigurer.
PropertySourcesPropertyResolver #getProperty variants now resolve any
nested placeholders recursively, throwing IllegalArgumentException for
any unresolvable placeholders (as is the default behavior for
PropertyPlaceholderConfigurer). See SPR-9569 for an enhancement that
will intoduce an 'ignoreUnresolvablePlaceholders' switch to make this
behavior configurable.
This commit also improves error output in
PropertyPlaceholderHelper#parseStringValue by including the original
string in which an unresolvable placeholder was found.
Issue: SPR-9473, SPR-9569
Prior to this change, by-type lookups using DLBF#getBeanNamesForType
required traversal of all bean definitions within the bean factory
in order to inspect their bean class for assignability to the target
type. These operations are comparatively expensive and when there are a
large number of beans registered within the container coupled with a
large number of by-type lookups at runtime, the performance impact can
be severe. The test introduced here demonstrates such a scenario clearly.
This performance problem is likely to manifest in large Spring-based
applications using non-singleton beans, particularly request-scoped
beans that may be created and wired many thousands of times per second.
This commit introduces a simple ConcurrentHashMap-based caching strategy
for by-type lookups; container-wide assignability checks happen only
once on the first by-type lookup and are afterwards cached by type
with the values in the map being an array of all bean names assignable
to that type. This means that at runtime when creating and autowiring
non-singleton beans, the cost of by-type lookups is reduced to that of
ConcurrentHashMap#get.
Issue: SPR-9448
Backport-Issue: SPR-6870
Backport-Commit: 4c7a1c0a54
ClassPathResource.getDescription() now returns consistent, meaningful
results for all variants of ClassPathResource's constructors.
Issue: SPR-9415
Backport-Issue: SPR-9413
Backport-Commit: b50f6e19a6
Prior to this change, request-scoped components having
@Resource-injected dependencies caused a memory leak in
DefaultListableBeanFactory#dependenciesForBeanMap.
Consider the following example:
@Component
@Scope(value="request", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class MyComponent {
@Resource
private HttpServletRequest request;
// ...
}
The bean name for "MyComponent" will end up being
'scopedTarget.myComponent', which will become a key in
the #dependenciesForBeanMap structure.
On the first request, the injected HttpServletRequest bean will be a
proxy and will internally have a bean name of the form
"$Proxy10@1a3a2a52". This name will be added to the Set value associated
with the 'scopedTarget.myComponent' entry in #dependenciesForBeanMap.
On the second request, the process will repeat, but the injected
HttpServletRequest will be a different proxy instance, thus having a
different identity hex string, e.g. "$Proxy10@5eba06ff". This name will
also be added to the Set value associated with the
'scopedTarget.myComponent' entry in #dependenciesForBeanMap, and this
is the source of the leak: a new entry is added to the set on each
request but should be added only once.
This commit fixes the leak by introducing caching to
CommonAnnotationBeanPostProcessor#ResourceElement similar to that already
present in AutowiredAnnotationBeanPostProcessor#AutowiredFieldElement
and #AutowiredMethodElement. Essentially, each ResourceElement instance
now tracks whether it has been created, caches the ultimate value to be
injected and returns it eagerly if necessary. Besides solving the memory
leak, this has the side effect of avoiding unnecessary proxy creation.
This fix also explains clearly why injection into request-scoped
components using @Autowired never suffered this memory leak: because the
correct caching was already in place. Because @Resource is considerably
less-frequently used than @Autowired, and given that this particular
injection arrangement is relatively infrequent, it becomes
understandable how this bug has been present without being reported
since the introduction of @Resource support in Spring 2.5: developers
were unlikely to encounter it in the first place; and if they did, the
leak was minor enough (adding strings to a Set), that it could
potentially go unnoticed indefinitely depending on request volumes and
available memory.
Issue: SPR-9363
Backport-Issue: SPR-9176
Backport-Commit: f779c199ea
Commit 3f387eb9cf refactored and
deprecated TransactionAspectUtils, moving its #qualifiedBeanOfType
and related methods into BeanFactoryUtils. This created a package cycle
between beans.factory and beans.factory.annotation due to use of the
beans.factory.annotation.Qualifier annotation in these methods.
This commit breaks the package cycle by introducing
beans.factory.annotation.BeanFactoryAnnotationUtils and moving these
@Qualifier-related methods to it. It is intentionally similar in name
and style to the familiar BeanFactoryUtils class for purposes of
discoverability.
There are no backward-compatibilty concerns associated with this change
as the cycle was introduced, caught and now fixed before a release.
Issue: SPR-9443
Backport-Issue: SPR-6847
Backport-Commit: a4b00c732b
Prior to this change, Spring's @Async annotation support was tied to a
single AsyncTaskExecutor bean, meaning that all methods marked with
@Async were forced to use the same executor. This is an undesirable
limitation, given that certain methods may have different priorities,
etc. This leads to the need to (optionally) qualify which executor
should handle each method.
This is similar to the way that Spring's @Transactional annotation was
originally tied to a single PlatformTransactionManager, but in Spring
3.0 was enhanced to allow for a qualifier via the #value attribute, e.g.
@Transactional(ptm1)
public void m() { ... }
where ptm1 is either the name of a PlatformTransactionManager bean or
a qualifier value associated with a PlatformTransactionManager bean,
e.g. via the <qualifier> element in XML or the @Qualifier annotation.
This commit introduces the same approach to @Async and its relationship
to underlying executor beans. As always, the following syntax remains
supported
@Async
public void m() { ... }
indicating that calls to #m will be delegated to the default executor,
i.e. the executor provided to
<task:annotation-driven executor=.../>
or the executor specified when authoring a @Configuration class that
implements AsyncConfigurer and its #getAsyncExecutor method.
However, it now also possible to qualify which executor should be used
on a method-by-method basis, e.g.
@Async(e1)
public void m() { ... }
indicating that calls to #m will be delegated to the executor bean
named or otherwise qualified as e1. Unlike the default executor
which is specified up front at configuration time as described above,
the e1 executor bean is looked up within the container on the first
execution of #m and then cached in association with that method for the
lifetime of the container.
Class-level use of Async#value behaves as expected, indicating that all
methods within the annotated class should be executed with the named
executor. In the case of both method- and class-level annotations, any
method-level #value overrides any class level #value.
This commit introduces the following major changes:
- Add @Async#value attribute for executor qualification
- Introduce AsyncExecutionAspectSupport as a common base class for
both MethodInterceptor- and AspectJ-based async aspects. This base
class provides common structure for specifying the default executor
(#setExecutor) as well as logic for determining (and caching) which
executor should execute a given method (#determineAsyncExecutor) and
an abstract method to allow subclasses to provide specific strategies
for executor qualification (#getExecutorQualifier).
- Introduce AnnotationAsyncExecutionInterceptor as a specialization of
the existing AsyncExecutionInterceptor to allow for introspection of
the @Async annotation and its #value attribute for a given method.
Note that this new subclass was necessary for packaging reasons -
the original AsyncExecutionInterceptor lives in
org.springframework.aop and therefore does not have visibility to
the @Async annotation in org.springframework.scheduling.annotation.
This new subclass replaces usage of AsyncExecutionInterceptor
throughout the framework, though the latter remains usable and
undeprecated for compatibility with any existing third-party
extensions.
- Add documentation to spring-task-3.2.xsd and reference manual
explaining @Async executor qualification
- Add tests covering all new functionality
Note that the public API of all affected components remains backward-
compatible.
Issue: SPR-9443
Backport-Issue: SPR-6847
Backport-Commit: ed0576c181