Browse Source

Stronger warning about lookup methods not working with @Bean

Includes an updated CGLIB AOP proxy note on constructor invocations.

Issue: SPR-13108
Issue: SPR-13103
pull/813/head
Juergen Hoeller 11 years ago
parent
commit
2109db0c02
  1. 15
      spring-beans/src/main/java/org/springframework/beans/factory/annotation/Lookup.java
  2. 31
      src/asciidoc/index.adoc

15
spring-beans/src/main/java/org/springframework/beans/factory/annotation/Lookup.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@ -38,12 +38,15 @@ import java.lang.annotation.Target; @@ -38,12 +38,15 @@ import java.lang.annotation.Target;
* container to fill them in at runtime. In both cases, the container will generate
* runtime subclasses of the method's containing class via CGLIB, which is why such
* lookup methods can only work on beans that the container instantiates through
* regular constructors (i.e. lookup methods cannot get replaced on beans returned
* from factory methods where we can't dynamically provide a subclass for them).
* regular constructors: i.e. lookup methods cannot get replaced on beans returned
* from factory methods where we cannot dynamically provide a subclass for them.
*
* <p>Note: When used with component scanning or any other mechanism that filters
* out abstract beans, provide stub implementations of your lookup methods to be
* able to declare them as concrete classes.
* <p><b>Concrete limitations in typical Spring configuration scenarios:</b>
* When used with component scanning or any other mechanism that filters out abstract
* beans, provide stub implementations of your lookup methods to be able to declare
* them as concrete classes. And please remember that lookup methods won't work on
* beans returned from {@code @Bean} methods in configuration classes; you'll have
* to resort to {@code @Inject Provider&lt;TargetBean&gt;} or the like instead.
*
* @author Juergen Hoeller
* @since 4.1

31
src/asciidoc/index.adoc

@ -3327,15 +3327,17 @@ overrides the method. @@ -3327,15 +3327,17 @@ overrides the method.
[NOTE]
====
For this dynamic subclassing to work, the class that the Spring container will subclass
cannot be `final`, and the method to be overridden cannot be `final` either. Also,
testing a class that has an `abstract` method requires you to subclass the class
yourself and to supply a stub implementation of the `abstract` method. Finally, objects
that have been the target of method injection cannot be serialized. As of Spring 3.2 it
is no longer necessary to add CGLIB to your classpath, because CGLIB classes are
repackaged under org.springframework and distributed within the spring-core JAR. This is
done both for convenience as well as to avoid potential conflicts with other projects
that use differing versions of CGLIB.
* For this dynamic subclassing to work, the class that the Spring bean container will
subclass cannot be `final`, and the method to be overridden cannot be `final` either.
* Unit-testing a class that has an `abstract` method requires you to subclass the class
yourself and to supply a stub implementation of the `abstract` method.
* Concrete methods are also necessary for component scanning which requires concrete
classes to pick up.
* A further key limitation is that lookup methods won't work with factory methods and
in particular not with `@Bean` methods in configuration classes, since the container
is not in charge of creating the instance in that case and therefore cannot create
a runtime-generated subclass on the fly.
* Finally, objects that have been the target of method injection cannot be serialized.
====
Looking at the `CommandManager` class in the previous code snippet, you see that the
@ -15610,13 +15612,10 @@ so. However, there are some issues to consider: @@ -15610,13 +15612,10 @@ so. However, there are some issues to consider:
CGLIB classes are repackaged under org.springframework and included directly in the
spring-core JAR. This means that CGLIB-based proxy support 'just works' in the same
way that JDK dynamic proxies always have.
* The constructor of your proxied object will be called twice. This is a natural
consequence of the CGLIB proxy model whereby a subclass is generated for each proxied
object. For each proxied instance, two objects are created: the actual proxied object
and an instance of the subclass that implements the advice. This behavior is not
exhibited when using JDK proxies. Usually, calling the constructor of the proxied type
twice, is not an issue, as there are usually only assignments taking place and no real
logic is implemented in the constructor.
* As of Spring 4.0, the constructor of your proxied object will NOT be called twice
anymore since the CGLIB proxy instance will be created via Objenesis. Only if your
JVM does not allow for constructor bypassing, you might see double invocations and
corresponding debug log entries from Spring's AOP support.
To force the use of CGLIB proxies set the value of the `proxy-target-class` attribute of
the `<aop:config>` element to true:

Loading…
Cancel
Save