Prior to this change, @EnableTransactionManagement (via the
ProxyTransactionManagementConfiguration class) did not properly
register its auto-proxy creator through the usual AopConfigUtils
methods. It was trying to register the APC as a normal @Bean method,
but this causes issues (SPR-8494) with the logic in
AopConfigUtils#registerOrEscalateApcAsRequired, which expects the APC
bean definition to have a beanClassName property. When the APC is
registered via a @Bean definition, it is actually a
factoryBean/factoryMethod situation with no directly resolvable
beanClass/beanClassName.
To solve this problem, ImportSelector#selectImports has been refactored
to accept an ImportSelector.Context instance. This object contains the
AnnotationMetadata of the importing class as well as the enclosing
BeanDefinitionRegistry to allow for the kind of conditional bean
registration necessary here. In this case, the bean definition that
must be registered conditionally is that of the auto-proxy creator.
It should only be registered if AdviceMode == PROXY, and thus the
ImportSelector is an appropriate place to make this happen. It must
happen as a BeanDefinition (rather than a @Bean method) for
compatibility with AopConfigUtils, and working with the
BeanDefinitionRegistry API allows for that. This change does mean that
in certain cases like this one, #selectImports has container modifying
side effects. Documentation has been updated to reflect.
Issue: SPR-8411, SPR-8494
For the particular use case detailed in SPR-8514, with this change we
now attempt to determine the object type of a FactoryBean through its
generic type parameter if possible.
For (a contrived) example:
@Configuration
public MyConfig {
@Bean
public FactoryBean<String> fb() {
return new StringFactoryBean("foo");
}
}
The implementation will now look at the <String> generic parameter
instead of attempting to instantiate the FactoryBean in order to call
its #getObjectType() method.
This is important in order to avoid the autowiring lifecycle issues
detailed in SPR-8514. For example, prior to this change, the following
code would fail:
@Configuration
public MyConfig {
@Autowired Foo foo;
@Bean
public FactoryBean<String> fb() {
Assert.notNull(foo);
return new StringFactoryBean("foo");
}
}
The reason for this failure is that in order to perform autowiring,
the container must first determine the object type of all configured
FactoryBeans. Clearly a chicken-and-egg issue, now fixed by this
change.
And lest this be thought of as an obscure bug, keep in mind the use case
of our own JPA support: in order to configure and return a
LocalContainerEntityManagerFactoryBean from a @Bean method, one will
need access to a DataSource, etc -- resources that are likely to
be @Autowired across @Configuration classes for modularity purposes.
Note that while the examples above feature methods with return
types dealing directly with the FactoryBean interface, of course
the implementation deals with subclasses/subinterfaces of FactoryBean
equally as well. See ConfigurationWithFactoryBeanAndAutowiringTests
for complete examples.
There is at least a slight risk here, in that the signature of a
FactoryBean-returing @Bean method may advertise a generic type for the
FactoryBean less specific than the actual object returned (or than
advertised by #getObjectType for that matter). This could mean that an
autowiring target may be missed, that we end up with a kind of
autowiring 'false negative' where FactoryBeans are concerned. This is
probably a less common scenario than the need to work with an autowired
field within a FactoryBean-returning @Bean method, and also has a clear
workaround of making the generic return type more specific.
Issue: SPR-8514
isCglibProxy* methods in AopUtils are useful in lower-level modules,
i.e. those that cannot depend on .aop. Therefore copied these methods
to ClassUtils; deprecated the existing ones in AopUtils and now
delegating to the new location; switched all usage of
AopUtils#isCglibProxy* within the framework to use
ClassUtils#isCglibProxy* instead.
Even after applying @Ignore to these tests at the class level, they
still run (and fail) under ant when the jmxremote_optional jar is not
present. See the issues mentioned below for information on how these
tests will be re-enabled.
Issue: SPR-8089, SPR-8093, SPR-8458
Prior to this change, JndiPropertySource worked directly against a JNDI
Context instance as its 'source' object. This works well enough, but is
not nearly as fully-featured as Spring's existing JndiLocatorDelegate.
This change refactors JndiPropertySource from relying on an underlying
Context to relying on an underlying JndiLocatorDelegate. By default,
the delegate's "resourceRef" property is set to true, meaning that the
implementation will always try to prepand a given name with
"java:comp/env/" before looking up the name, and upon failure will drop
back to the given name sans prefix.
See JndiPropertySource Javadoc for complete details.
Issue: SPR-8490
Move JNDI_PROPERTY_SOURCE_ENABLED_FLAG from JndiPropertySource to
StandardServletEnvironment, as this is the only context in which the
constant makes sense.
Prior to this change, @Autowired injection against an instance of a
subclass having different visibility than its superclass would fail
if the @Autowired method is declared only in the superclass. This is due
to an apparent change in the rules around bridge method generation
between Java 5 and Java 6, and possibly even varying across compiler
vendors.
Now, BridgeMethodResolver is used consistently when detecting
@Autowired, @Inject and @Resource metadata to bypass these bridge
methods if they exist.
Issue: SPR-7900
Prior to this change, AbstractAutowireCapableBeanFactory did not support
a default ParameterNameDiscoverer. This meant that attempting to use
<constructor-arg name=".."> syntax would fail (with a fairly obscure
exception) as that feature depends on a ParameterNameDiscoverer to
introspect the constructor arguments.
This lack of a default was originally intended to avoid a dependency on
ASM, but now that (a) .asm is a built-in module and (b) .beans has a
non-optional compile-time dependency on .asm, there is no reason not to
provide this default.
The net effect is that in a number of locations throughout the
framework, namely in GenericApplicationContext and
AbstractRefreshableApplicationContext, it is no longer necessary to
explicitly call AACBF#setParameterNameDiscoverer. This also means that
using a naked BeanFactory (likely for testing scenarios) is that much
easier.
Issue: SPR-8184
As of SPR-8093, jmxremote_optional.jar is present on the build
server in jre/lib/ext, but it is not by default present on local
developer / user machines, meaning that the build ends up broken
by default.
Issue: SPR-8089, SPR-8093, SPR-8458
+ remove generic signature on key generator (as the type is not used anywhere)
+ add a small improvement to CacheAspect to nicely handle the cases where the aspect is pulled in but not configured
ContextLoader and FrameworkServlet now use
AnnotationAwareOrderComparator to support @Order usage; previously
supported only implementation of the Ordered interface.
Calls to AbstractApplicationContext#setParent delegate the parent
context environment to the child.
This ensures that any property sources added to the parent are available
to the child as well as ensuring that any profiles activated are
activated everywhere.
Child contexts may still choose to replace their environment (through an
ApplicationContextInitializer, for example). In any case, however, in
the root/child web application context relationship established by
ContextLoader + DispatcherServlet, the child is guaranteed to have
already been given the parent environment by the time it is delegated
to any ACIs.
See AbstractApplicationContext#setParent for implementation
See FrameworkServlet#createWebApplicationContext for order in which
setParent then initializeWebApplicationContext are called.
Issue: SPR-8185
AnnotationConfigApplicationContext and
AnnotationConfigWebApplicationContext both expose #register and #scan
methods as of the completion of SPR-8320. This change introduces a new
interface that declares each of these methods and refactors ACAC and
ACWAC to implement it.
Beyond information value, this is useful for implementors of the
ApplicationContextInitializer interface, in that users may create an ACI
that works consistently across ACAC and ACWAC for standalone (e.g.
testing, batch) or web (e.g. production) use.
Issue: SPR-8365,SPR-8320
FrameworkServlet now has support equivalent to ContextLoader and its
"contextInitializerClasses" context-param introduced in 3.1 M1.
This allows users to specify ApplicationContextInitializers at the root
(ContextLoader) level and/or at the DispatcherServlet level.
Issue: SPR-8366
The following is now possible:
@Configuration
public class AppConfig {
@Inject DataSource dataSource;
@Bean
public MyBean myBean() {
return new MyBean(dataSource);
}
@Configuration
static class DatabaseConfig {
@Bean
DataSource dataSource() {
return new EmbeddedDatabaseBuilder().build();
}
}
}
public static void main(String... args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
ctx.getBean(MyBean.class); // works
ctx.getBean(DataSource.class); // works
}
Notice that the @Import annotation was not used and that only AppConfig
was registered against the context. By virtue of the fact that
DatabaseConfig is a member class of AppConfig, it is automatically
registered when AppConfig is registered. This avoids an awkward and
redundant @Import annotation when the relationship is already implicitly
clear.
See @Configuration Javadoc for details.
Issue: SPR-8186
- removed generics from Cache/CacheManager (they add no value since it's an SPI not API)
+ update docs and tests
+ renamed ConcurrentCacheFactoryBean to ConcurrentMapCacheFactoryBean
Revert signature of
ConfigurationClassPostProcessor#processConfigBeanDefinitions to its form
found in the 3.0.x line. Refactorings made during 3.1 development
caused otherwise package-private types such as
ConfigurationClassBeanDefinitionReader to escape through this public
method, causing issues for STS as well as being a general design issue.
Upon review, the refactorings could easily be backed out in favor of a
simpler approach, and this has been done.
This also means that ConfigurationClassBeanDefinitionReader can return
to package-private visibility, and this change has been made as well.
Issue: SPR-8200
A subtle issue existed with the way we relied on isCurrentlyInCreation
to determine whether a @Bean method is being called by the container
or by user code. This worked in most cases, but in the particular
scenario laid out by SPR-8080, this approach was no longer sufficient.
This change introduces a ThreadLocal that contains the factory method
currently being invoked by the container, such that enhanced @Bean
methods can check against it to see if they are being called by the
container or not. If so, that is the cue that the user-defined @Bean
method implementation should be invoked in order to actually create
the bean for the first time. If not, then the cached instance of
the already-created bean should be looked up and returned.
See ConfigurationClassPostConstructAndAutowiringTests for
reproduction cases and more detail.
Issue: SPR-8080
If the enclosing environment does not implement ConfigurableEnvironment,
then @PropertySource annotations are ignored because there is no way to
add them to the Environment. Now checking first to see if there are any
@PropertySource annotations present before issuing the warning.
Issue: SPR-8314
Allows a convenient mechanism for contributing a PropertySource to the
enclosing Spring Environment. See @PropertySource Javadoc for
complete details and PropertySourceAnnotationTests for examples.
Issue: SPR-8314
Users may now call #setRequiredProperties(String...) against the
Environment (via its ConfigurablePropertyResolver interface) in order
to indicate which properties must be present.
Environment#validateRequiredProperties() is invoked by
AbstractApplicationContext during the refresh() lifecycle to perform
the actual check and a MissingRequiredPropertiesException is thrown
if the precondition is not satisfied.
Issue: SPR-8323
Declaring @Bean methods as 'static' is now permitted, whereas previously
it raised an exception at @Configuration class validation time.
A static @Bean method can be called by the container without requiring
the instantiation of its declaring @Configuration class. This is
particularly useful when dealing with BeanFactoryPostProcessor beans,
as they can interfere with the standard post-processing lifecycle
necessary to handle @Autowired, @Inject, @Value, @PostConstruct and
other annotations.
static @Bean methods cannot recieve CGLIB enhancement for scoping and
AOP concerns. This is acceptable in BFPP cases as they rarely if ever
need it, and should not in typical cases ever be called by another
@Bean method. Once invoked by the container, the resulting bean will
be cached as usual, but multiple invocations of the static @Bean method
will result in creation of multiple instances of the bean.
static @Bean methods may not, for obvious reasons, refer to normal
instance @Bean methods, but again this is not likely a concern for BFPP
types. In the rare case that they do need a bean reference, parameter
injection into the static @Bean method is technically an option, but
should be avoided as it will potentially cause premature instantiation
of more beans that the user may have intended.
Note particularly that a WARN-level log message is now issued for any
non-static @Bean method with a return type assignable to BFPP. This
serves as a strong recommendation to users that they always mark BFPP
@Bean methods as static.
See @Bean Javadoc for complete details.
Issue: SPR-8257, SPR-8269
Prior to this change, @ComponentScan annotations were only processed at
the first level of depth. Now, the set of bean definitions resulting
from each declaration of @ComponentScan is checked for configuration
classes that declare @ComponentScan, and recursion is performed as
necessary.
Cycles between @ComponentScan declarations are detected as well. See
CircularComponentScanException.
Issue: SPR-8307
Introduce @EnableAsync#order
AsyncAnnotationBeanPostProcessor's 'order' property is now mutable;
@EnableAsync's 'order()' attribute allows for setting it, but must
have a default value, thus uses the new Ordered#NOT_ORDERED
constant - a reserved negative number very unlikely to be otherwise
used that may be interpreted as 'not ordered', useful in annotation
defaulting scenarios where null is not an option.
Introduce first working cut of AsyncConfiguration
Remove AsyncCapability
This change is in support of certain polymorphism cases in
@Configuration class inheritance hierarchies. Consider the following
scenario:
@Configuration
public abstract class AbstractConfig {
public abstract Object bean();
}
@Configuration
public class ConcreteConfig {
@Override
@Bean
public BeanPostProcessor bean() { ... }
}
ConcreteConfig overrides AbstractConfig's #bean() method with a
covariant return type, in this case returning an object of type
BeanPostProcessor. It is critically important that the container
is able to detect the return type of ConcreteConfig#bean() in order
to instantiate the BPP at the right point in the lifecycle.
Prior to this change, the container could not do this.
AbstractAutowireCapableBeanFactory#getTypeForFactoryMethod called
ReflectionUtils#getAllDeclaredMethods, which returned Method objects
for both the Object and BeanPostProcessor signatures of the #bean()
method. This confused the implementation sufficiently as not to
choose a type for the factory method at all. This means that the
BPP never gets detected as a BPP.
The new method being introduced here, #getUniqueDeclaredMethods, takes
covariant return types into account, and filters out duplicates,
favoring the most specific / narrow return type.
Additionally, it filters out any CGLIB 'rewritten' methods, which
is important in the case of @Configuration classes, which are
enhanced by CGLIB. See the implementation for further details.
Consolidating internal bean name and aspect class name constats within
AnnotationConfigUtils to allow access from both the context.config
and context.annotation packages without creating a relationship between
the two of them (they are unrelated leaf nodes in the packaging
currently).
The .transaction module does not have a similar utils class and already
has a relationship from transaction.config -> transaction.annotation,
so placing the constants in .annotation.TransactionManagementCapability
to be referenced by .config.AnnotationDrivenBeanDefinitionParser
Allows @Enable* a layer of indirection for deciding which @Configuration
class(es) to @Import.
The @Import annotation may now accept @Configuration class literals
and/or ImportSelector class literals.
@Configuration classes may implement ImportAware in order to be injected
with the AnnotationMetadata of their @Import'ing class.
Includes the introduction of a new PriorityOrdered
ImportAwareBeanPostProcessor that handles injection of the
importing class metadata.
Includes the introduction of AnnotationUtils#findAllAnnotationAttributes
to support iterating through all annotations declared on a given type
and interrogating each for the presence of a meta-annotation. See tests
for details.
Feature-related support such as @Feature, @FeatureConfiguration,
and FeatureSpecification types will be replaced by framework-provided
@Configuration classes and convenience annotations such as
@ComponentScan (already exists), @EnableAsync, @EnableScheduling,
@EnableTransactionManagement and others.
Issue: SPR-8012,SPR-8034,SPR-8039,SPR-8188,SPR-8206,SPR-8223,
SPR-8225,SPR-8226,SPR-8227
The overloading necessary to preserve the new signature as well as
the old causes ambiguities leading to deprecation warnings in some
caller scenarios.
Previously errors were being raised when trying to inject @Value
annotated paramaters such as:
@Feature
public FeatureSpec feature(@Value("#{environment['foo']}") String foo) {
return new FeatureSpec(foo);
}
This is not so much because dependency resolution of @Value-annotated
types was failing, but rather because the 'early bean reference'
proxying mechanism was throwing an exception if any final type was
detected as a parameter. This is of course because final types are
non-subclassable by CGLIB. On review, however, it's obvious that
certain final types must be allowed for injection. @Value injection
is an obvious one, but the rarer case of a Spring bean of type String
or int is another.
The explicit guard against final types as parameters to @Feature methods
has been removed. Final types are still checked for, however, and if
found, no proxing is attempted. The dependency is immediately resolved
against the current BeanFactory and injected into the @Feature method.
This means that @Value injection, @Qualifier injection, etc all work
as expected, but does mean that premature bean instantiation may occur
if a user unwittingly injects non-String, non-primitive final bean types
as @Feature method parameters.
Issue: SPR-7974
CGLIB-enhanced @Configuration subclasses now implement DisposableBean
such that Enhancer.registerStaticCallbacks(subclass, null) is invoked
on container shutdown. This ensures that garbage collection can work
properly and avoids memory consumption issues for applications that
create and destroy many application contexts within the same JVM.
Issue: SPR-7901
context:property-placeholder extends 'propertyPlaceholder' type
defintion once again. This relationship was inadvertently removed in
3.1 M1, and the effect was that XML tooling would raise errors on
use of attributes like 'location'.
The updated schema has also been published to
http://www.springframework.org/schema/context/spring-context-3.1.xsd
Issue: SPR-8037
Prove that injection of special container types such as ResourceLoader,
BeanFactory, etc already works with the current implementation of
@Feature methods.
Issue: SPR-7975
Current STS version of Spring (3.0.5) does not contain
the BeanUtils.instantiateClass(Class<?>, Class<T>) signature
that was added in 3.1.0, therefore NoSuchMethodErrors are
being thrown when STS classloads and delegates to
3.1.0 NamespaceHandler and BeanDefinitionParser implementations
on the user project classpath.
In this case, it's AbstractSpecificationBeanDefinitionParser
doing the calling to the unknown new method. In this specific
example, reverting back to the old single-arg signature is actually
not a problem, because it does accept Class<T> and returns an
instance of type T, which was the desired behavior in the first
place.
The newer signature remains in order to accommodate callers
who do not know the generic type of the Class to be instantiated
(i.e. Class<?>), but do know the type that it should be assignable
to -- this becomes the second argument Class<T>, and an instance
of type T is returned (if indeed it is assignable to the specified
type; otherwise IllegalArgumentException.
Defensively catch NoSuchMethodError when calling BDPD.getEnvironment()
and supply a DefaultEnvironment if not available.
Replace the single-arg constructor for BDPD and deprecate, preserving
binary compat particularly for Spring Integration who instantiates
this class directly, which is unusual.
Revert changes to ParserContext, ReaderContext, and XmlReaderContext
These changes cause cross-version incompatibilities at tooling time
-- for instance, an STS version that ships with Spring 3.0.5
classloads the ParserContext defined in that version, whereas it
classloads NamespaceHandlers and BeanDefinitionParsers (by default)
from the user application classpath, which may be building against
3.1.0. If so, the changes introduced to these types in 3.1.0 are
incompatible with expectations in the 3.0.5 world and cause all
manner of problems. In this case, it was NoSuchMethodError due to
the newly-added XmlReaderContext.getProblemReporter() method; also
IncompatibleClassChangeError due to the introduction of the
ComponentRegistrar interface on ParserContext.
Each of these problems have been mitigated, though the solutions
are not ideal. The method mentioned has been removed, and instead
the problemReporter field is now accessed reflectively.
ParserContext now no longer implements ComponentRegistrar, and
rather a ComponentRegistrarAdapter class has been introduced that
passes method calls through to a ParserContext delegate.
Introduce AbstractSpecificationBeanDefinitionParser
AbstractSpecificationBeanDefinitionParser has been introduced in
order to improve the programming model for BeanDefinitionParsers
that have been refactored to the new FeatureSpecification model.
This new base class and it's template method implementation of
parse/doParse ensure that common concerns like (1) adapting a
ParserContext into a SpecificationContext, (2) setting source and
source name on the specification, and (3) actually executing the
specification are all managed by the base class. The subclass
implementation of doParse need only actually parse XML, populate
and return the FeatureSpecification object. This change removed
the many duplicate 'createSpecificationContext' methods that had
been lingering.
Minor improvement to BeanDefinitionReaderUtils API
Introduced new BeanDefinitionReaderUtils#registerWithGeneratedName
variant that accepts BeanDefinition as opposed to
AbstractBeanDefinition, as BeanDefinition is all that is actually
necessary to satisfy the needs of the method implementation. The
latter variant accepting AbstractBeanDefinition has been deprecated
but remains intact and delegates to the new variant in order to
maintain binary compatibility.
This change broke binary compatibility as evidenced by running
the greenhouse test suite and finding that Spring Integration's
AbstractConsumerEndpointParser.parseInternal fails with
NoSuchMethodError when trying to invoke.