proxies with AspectJ pointcuts are fully serializable within a BeanFactory now (SPR-6681)

This commit is contained in:
Juergen Hoeller 2010-02-01 14:43:35 +00:00
parent dcf0244566
commit 2d525901ff
2 changed files with 60 additions and 33 deletions

View File

@ -16,6 +16,8 @@
package org.springframework.aop.aspectj; package org.springframework.aop.aspectj;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@ -75,27 +77,29 @@ import org.springframework.util.StringUtils;
public class AspectJExpressionPointcut extends AbstractExpressionPointcut public class AspectJExpressionPointcut extends AbstractExpressionPointcut
implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware { implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {
private static final Set<PointcutPrimitive> DEFAULT_SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>(); private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>();
static { static {
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION); SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS); SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE); SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS); SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET); SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN); SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION); SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN); SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS); SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);
DEFAULT_SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET); SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);
} }
private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class); private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class);
private final Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32); private transient PointcutParser pointcutParser;
private PointcutParser pointcutParser; private transient PointcutExpression pointcutExpression;
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
private Class pointcutDeclarationScope; private Class pointcutDeclarationScope;
@ -105,26 +109,12 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
private BeanFactory beanFactory; private BeanFactory beanFactory;
private PointcutExpression pointcutExpression;
/** /**
* Create a new default AspectJExpressionPointcut. * Create a new default AspectJExpressionPointcut.
*/ */
public AspectJExpressionPointcut() { public AspectJExpressionPointcut() {
this(DEFAULT_SUPPORTED_PRIMITIVES); initializePointcutParser();
}
/**
* Create a new AspectJExpressionPointcut with the given supported primitives.
* @param supportedPrimitives Set of {@link org.aspectj.weaver.tools.PointcutPrimitive}
* instances
*/
public AspectJExpressionPointcut(Set supportedPrimitives) {
this.pointcutParser =
PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(
supportedPrimitives);
this.pointcutParser.registerPointcutDesignatorHandler(new BeanNamePointcutDesignatorHandler());
} }
/** /**
@ -134,7 +124,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
* @param paramTypes the parameter types for the pointcut * @param paramTypes the parameter types for the pointcut
*/ */
public AspectJExpressionPointcut(Class declarationScope, String[] paramNames, Class[] paramTypes) { public AspectJExpressionPointcut(Class declarationScope, String[] paramNames, Class[] paramTypes) {
this(DEFAULT_SUPPORTED_PRIMITIVES); initializePointcutParser();
this.pointcutDeclarationScope = declarationScope; this.pointcutDeclarationScope = declarationScope;
if (paramNames.length != paramTypes.length) { if (paramNames.length != paramTypes.length) {
throw new IllegalStateException( throw new IllegalStateException(
@ -144,6 +134,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
this.pointcutParameterTypes = paramTypes; this.pointcutParameterTypes = paramTypes;
} }
private void initializePointcutParser() {
this.pointcutParser =
PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(
SUPPORTED_PRIMITIVES);
this.pointcutParser.registerPointcutDesignatorHandler(new BeanNamePointcutDesignatorHandler());
}
/** /**
* Set the declaration scope for the pointcut. * Set the declaration scope for the pointcut.
@ -528,4 +525,18 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
} }
} }
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization, just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
initializePointcutParser();
this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2007 the original author or authors. * Copyright 2002-2010 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,9 @@
package org.springframework.aop.support; package org.springframework.aop.support;
import java.io.IOException;
import java.io.ObjectInputStream;
import org.aopalliance.aop.Advice; import org.aopalliance.aop.Advice;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
@ -41,9 +44,9 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
private BeanFactory beanFactory; private BeanFactory beanFactory;
private Advice advice; private transient Advice advice;
private final Object adviceMonitor = new Object(); private transient volatile Object adviceMonitor = new Object();
/** /**
@ -74,7 +77,7 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
synchronized (this.adviceMonitor) { synchronized (this.adviceMonitor) {
if (this.advice == null && this.adviceBeanName != null) { if (this.advice == null && this.adviceBeanName != null) {
Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'"); Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
this.advice = (Advice) this.beanFactory.getBean(this.adviceBeanName, Advice.class); this.advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
} }
return this.advice; return this.advice;
} }
@ -85,4 +88,17 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
return getClass().getName() + ": advice bean '" + getAdviceBeanName() + "'"; return getClass().getName() + ": advice bean '" + getAdviceBeanName() + "'";
} }
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization, just initialize state after deserialization.
ois.defaultReadObject();
// Initialize transient fields.
this.adviceMonitor = new Object();
}
} }