Formerly named {@code Cglib2AopProxy}, as of Spring 3.2, this class depends on
- * Spring's own internally repackaged version of CGLIB 3..
- *
*
Objects of this type should be obtained through proxy factories,
* configured by an {@link AdvisedSupport} object. This class is internal
* to Spring's AOP framework and need not be used directly by client code.
@@ -241,10 +239,11 @@ class CglibAopProxy implements AopProxy, Serializable {
* validates it if not.
*/
private void validateClassIfNecessary(Class> proxySuperClass, ClassLoader proxyClassLoader) {
- if (logger.isInfoEnabled()) {
+ if (logger.isWarnEnabled()) {
synchronized (validatedClasses) {
if (!validatedClasses.containsKey(proxySuperClass)) {
- doValidateClass(proxySuperClass, proxyClassLoader);
+ doValidateClass(proxySuperClass, proxyClassLoader,
+ ClassUtils.getAllInterfacesForClassAsSet(proxySuperClass));
validatedClasses.put(proxySuperClass, Boolean.TRUE);
}
}
@@ -255,30 +254,35 @@ class CglibAopProxy implements AopProxy, Serializable {
* Checks for final methods on the given {@code Class}, as well as package-visible
* methods across ClassLoaders, and writes warnings to the log for each one found.
*/
- private void doValidateClass(Class> proxySuperClass, ClassLoader proxyClassLoader) {
+ private void doValidateClass(Class> proxySuperClass, ClassLoader proxyClassLoader, Set> ifcs) {
if (proxySuperClass != Object.class) {
Method[] methods = proxySuperClass.getDeclaredMethods();
for (Method method : methods) {
int mod = method.getModifiers();
if (!Modifier.isStatic(mod)) {
if (Modifier.isFinal(mod)) {
- logger.info("Unable to proxy method [" + method + "] because it is final: " +
- "All calls to this method via a proxy will NOT be routed to the target instance.");
+ if (implementsInterface(method, ifcs)) {
+ logger.warn("Unable to proxy interface-implmenting method [" + method + "] because " +
+ "it is marked as final: Consider using interface-based proxies instead!");
+ }
+ logger.info("Final method [" + method + "] cannot get proxied via CGLIB: " +
+ "Calls to this method will NOT be routed to the target instance and " +
+ "might lead to NPEs against uninitialized fields in the proxy instance.");
}
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) && !Modifier.isPrivate(mod) &&
proxyClassLoader != null && proxySuperClass.getClassLoader() != proxyClassLoader) {
- logger.info("Unable to proxy method [" + method + "] because it is package-visible " +
- "across different ClassLoaders: All calls to this method via a proxy will " +
- "NOT be routed to the target instance.");
+ logger.info("Method [" + method + "] is package-visible across different ClassLoaders " +
+ "and cannot get proxied via CGLIB: Declare this method as public or protected " +
+ "if you need to support invocations through the proxy.");
}
}
}
- doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader);
+ doValidateClass(proxySuperClass.getSuperclass(), proxyClassLoader, ifcs);
}
}
private Callback[] getCallbacks(Class> rootClass) throws Exception {
- // Parameters used for optimisation choices...
+ // Parameters used for optimization choices...
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
@@ -317,14 +321,14 @@ class CglibAopProxy implements AopProxy, Serializable {
Callback[] callbacks;
// If the target is a static one and the advice chain is frozen,
- // then we can make some optimisations by sending the AOP calls
+ // then we can make some optimizations by sending the AOP calls
// direct to the target using the fixed chain for that method.
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap(methods.length);
- // TODO: small memory optimisation here (can skip creation for methods with no advice)
+ // TODO: small memory optimization here (can skip creation for methods with no advice)
for (int x = 0; x < methods.length; x++) {
List