, Object> aspectCache = new ConcurrentHashMap<>();
private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory();
@@ -144,7 +144,7 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
private MetadataAwareAspectInstanceFactory createAspectInstanceFactory(
AspectMetadata am, Class> aspectClass, String aspectName) {
- MetadataAwareAspectInstanceFactory instanceFactory = null;
+ MetadataAwareAspectInstanceFactory instanceFactory;
if (am.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// Create a shared aspect instance.
Object instance = getSingletonAspectInstance(aspectClass);
@@ -162,15 +162,20 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
* is created if one cannot be found in the instance cache.
*/
private Object getSingletonAspectInstance(Class> aspectClass) {
- synchronized (aspectCache) {
- Object instance = aspectCache.get(aspectClass);
- if (instance != null) {
- return instance;
+ // Quick check without a lock...
+ Object instance = aspectCache.get(aspectClass);
+ if (instance == null) {
+ synchronized (aspectCache) {
+ // To be safe, check within full lock now...
+ instance = aspectCache.get(aspectClass);
+ if (instance != null) {
+ return instance;
+ }
+ instance = new SimpleAspectInstanceFactory(aspectClass).getAspectInstance();
+ aspectCache.put(aspectClass, instance);
}
- instance = new SimpleAspectInstanceFactory(aspectClass).getAspectInstance();
- aspectCache.put(aspectClass, instance);
- return instance;
}
+ return instance;
}
diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java
index dd8823ec1c..eefecd1592 100644
--- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java
+++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -35,9 +35,8 @@ import org.springframework.aop.support.ComposablePointcut;
* Metadata for an AspectJ aspect class, with an additional Spring AOP pointcut
* for the per clause.
*
- * Uses AspectJ 5 AJType reflection API, so is only supported on Java 5.
- * Enables us to work with different AspectJ instantiation models such as
- * "singleton", "pertarget" and "perthis".
+ *
Uses AspectJ 5 AJType reflection API, enabling us to work with different
+ * AspectJ instantiation models such as "singleton", "pertarget" and "perthis".
*
* @author Rod Johnson
* @author Juergen Hoeller
@@ -102,20 +101,22 @@ public class AspectMetadata implements Serializable {
this.ajType = ajType;
switch (this.ajType.getPerClause().getKind()) {
- case SINGLETON :
+ case SINGLETON:
this.perClausePointcut = Pointcut.TRUE;
return;
- case PERTARGET : case PERTHIS :
+ case PERTARGET:
+ case PERTHIS:
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
- ajexp.setLocation("@Aspect annotation on " + aspectClass.getName());
+ ajexp.setLocation(aspectClass.getName());
ajexp.setExpression(findPerClause(aspectClass));
+ ajexp.setPointcutDeclarationScope(aspectClass);
this.perClausePointcut = ajexp;
return;
- case PERTYPEWITHIN :
+ case PERTYPEWITHIN:
// Works with a type pattern
this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));
return;
- default :
+ default:
throw new AopConfigException(
"PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);
}
@@ -125,8 +126,6 @@ public class AspectMetadata implements Serializable {
* Extract contents from String of form {@code pertarget(contents)}.
*/
private String findPerClause(Class> aspectClass) {
- // TODO when AspectJ provides this, we can remove this hack. Hence we don't
- // bother to make it elegant. Or efficient. Or robust :-)
String str = aspectClass.getAnnotation(Aspect.class).value();
str = str.substring(str.indexOf("(") + 1);
str = str.substring(0, str.length() - 1);
diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java
index 665eb648fe..e481eb9322 100644
--- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java
+++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectJAdvisorsBuilder.java
@@ -17,10 +17,10 @@
package org.springframework.aop.aspectj.annotation;
import java.util.Collections;
-import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import org.aspectj.lang.reflect.PerClauseKind;
@@ -43,12 +43,11 @@ public class BeanFactoryAspectJAdvisorsBuilder {
private final AspectJAdvisorFactory advisorFactory;
- private List aspectBeanNames;
+ private volatile List aspectBeanNames;
- private final Map> advisorsCache = new HashMap<>();
+ private final Map> advisorsCache = new ConcurrentHashMap<>();
- private final Map aspectFactoryCache =
- new HashMap<>();
+ private final Map aspectFactoryCache = new ConcurrentHashMap<>();
/**
@@ -56,7 +55,7 @@ public class BeanFactoryAspectJAdvisorsBuilder {
* @param beanFactory the ListableBeanFactory to scan
*/
public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory) {
- this(beanFactory, new ReflectiveAspectJAdvisorFactory());
+ this(beanFactory, new ReflectiveAspectJAdvisorFactory(beanFactory));
}
/**
@@ -80,56 +79,57 @@ public class BeanFactoryAspectJAdvisorsBuilder {
* @see #isEligibleBean
*/
public List buildAspectJAdvisors() {
- List aspectNames = null;
+ List aspectNames = this.aspectBeanNames;
- synchronized (this) {
- aspectNames = this.aspectBeanNames;
- if (aspectNames == null) {
- List advisors = new LinkedList<>();
- aspectNames = new LinkedList<>();
- String[] beanNames =
- BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
- for (String beanName : beanNames) {
- if (!isEligibleBean(beanName)) {
- continue;
- }
- // We must be careful not to instantiate beans eagerly as in this
- // case they would be cached by the Spring container but would not
- // have been weaved
- Class> beanType = this.beanFactory.getType(beanName);
- if (beanType == null) {
- continue;
- }
- if (this.advisorFactory.isAspect(beanType)) {
- aspectNames.add(beanName);
- AspectMetadata amd = new AspectMetadata(beanType, beanName);
- if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
- MetadataAwareAspectInstanceFactory factory =
- new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
- List classAdvisors = this.advisorFactory.getAdvisors(factory);
- if (this.beanFactory.isSingleton(beanName)) {
- this.advisorsCache.put(beanName, classAdvisors);
+ if (aspectNames == null) {
+ synchronized (this) {
+ aspectNames = this.aspectBeanNames;
+ if (aspectNames == null) {
+ List advisors = new LinkedList<>();
+ aspectNames = new LinkedList<>();
+ String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
+ this.beanFactory, Object.class, true, false);
+ for (String beanName : beanNames) {
+ if (!isEligibleBean(beanName)) {
+ continue;
+ }
+ // We must be careful not to instantiate beans eagerly as in this case they
+ // would be cached by the Spring container but would not have been weaved.
+ Class> beanType = this.beanFactory.getType(beanName);
+ if (beanType == null) {
+ continue;
+ }
+ if (this.advisorFactory.isAspect(beanType)) {
+ aspectNames.add(beanName);
+ AspectMetadata amd = new AspectMetadata(beanType, beanName);
+ if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
+ MetadataAwareAspectInstanceFactory factory =
+ new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
+ List classAdvisors = this.advisorFactory.getAdvisors(factory);
+ if (this.beanFactory.isSingleton(beanName)) {
+ this.advisorsCache.put(beanName, classAdvisors);
+ }
+ else {
+ this.aspectFactoryCache.put(beanName, factory);
+ }
+ advisors.addAll(classAdvisors);
}
else {
+ // Per target or per this.
+ if (this.beanFactory.isSingleton(beanName)) {
+ throw new IllegalArgumentException("Bean with name '" + beanName +
+ "' is a singleton, but aspect instantiation model is not singleton");
+ }
+ MetadataAwareAspectInstanceFactory factory =
+ new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
+ advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
- advisors.addAll(classAdvisors);
- }
- else {
- // Per target or per this.
- if (this.beanFactory.isSingleton(beanName)) {
- throw new IllegalArgumentException("Bean with name '" + beanName +
- "' is a singleton, but aspect instantiation model is not singleton");
- }
- MetadataAwareAspectInstanceFactory factory =
- new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
- this.aspectFactoryCache.put(beanName, factory);
- advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
+ this.aspectBeanNames = aspectNames;
+ return advisors;
}
- this.aspectBeanNames = aspectNames;
- return advisors;
}
}
diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java
index 49aaaababd..2cd3497d1b 100644
--- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java
+++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java
@@ -46,6 +46,7 @@ import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
import org.springframework.aop.aspectj.DeclareParentsAdvisor;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.aop.support.DefaultPointcutAdvisor;
+import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConvertingComparator;
@@ -95,6 +96,30 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
}
+ private final BeanFactory beanFactory;
+
+
+ /**
+ * Create a new {@code ReflectiveAspectJAdvisorFactory}.
+ */
+ public ReflectiveAspectJAdvisorFactory() {
+ this(null);
+ }
+
+ /**
+ * Create a new {@code ReflectiveAspectJAdvisorFactory}, propagating the given
+ * {@link BeanFactory} to the created {@link AspectJExpressionPointcut} instances,
+ * for bean pointcut handling as well as consistent {@link ClassLoader} resolution.
+ * @param beanFactory the BeanFactory to propagate (may be {@code null}}
+ * @since 4.3.6
+ * @see AspectJExpressionPointcut#setBeanFactory
+ * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#getBeanClassLoader()
+ */
+ public ReflectiveAspectJAdvisorFactory(BeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ }
+
+
@Override
public List getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
@@ -161,9 +186,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
}
if (DeclareParents.class == declareParents.defaultImpl()) {
- // This is what comes back if it wasn't set. This seems bizarre...
- // TODO this restriction possibly should be relaxed
- throw new IllegalStateException("defaultImpl must be set on DeclareParents");
+ throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
}
return new DeclareParentsAdvisor(
@@ -197,6 +220,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
+ ajexp.setBeanFactory(this.beanFactory);
return ajexp;
}