Spring AOP module providing aspect-oriented programming capabilities for the Spring Framework
—
Automatic proxy creation through BeanPostProcessor implementations that analyze beans for advisor applicability and create proxies transparently during the Spring container initialization process. This system enables declarative AOP configuration where proxies are created automatically based on pointcut matching rather than explicit proxy factory configuration.
Abstract base class providing common functionality for automatic proxy creation during bean post-processing.
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements BeanPostProcessor, BeanFactoryAware {
/**
* Set whether or not the proxy should be frozen, preventing advice
* from being added to it once it is created.
* <p>Overridden from the superclass to prevent the proxy configuration
* from being frozen before the proxy is created.
*/
@Override
public void setFrozen(boolean frozen);
/**
* Set the ordering which will apply to this class's implementation
* of Ordered, used when applying multiple BeanPostProcessors.
* <p>The default value is {@code Ordered.LOWEST_PRECEDENCE}, meaning non-ordered.
* @param order the ordering value
*/
public void setOrder(int order);
/**
* Return the order value of this object, with a higher value meaning greater
* precedence. Normally starting with 0, with {@code Integer.MAX_VALUE}
* indicating the greatest precedence (corresponding to the lowest priority).
*/
@Override
public int getOrder();
/**
* Set whether to apply advisors only to beans in this container,
* or to beans in the entire BeanFactory hierarchy.
* <p>Default is "false": apply advisors to beans in the entire BeanFactory
* hierarchy, i.e. including ancestor contexts (as far as they are visible
* from the ApplicationContext that this post-processor is defined in).
* <p>Switch this flag to "true" in order to apply advisors only to beans
* in the local ApplicationContext, ignoring beans in ancestor contexts.
* This can be useful if ancestor contexts are read-only, and if you want
* to avoid applying advisors to beans defined in read-only contexts.
* @param applyCommonInterceptorsFirst whether to apply advisors only locally
*/
public void setApplyCommonInterceptorsFirst(boolean applyCommonInterceptorsFirst);
/**
* Set custom {@code TargetSourceCreators} to apply to this configuration.
* If the list is empty, no custom TargetSource will be applied.
* <p>Note that TargetSourceCreators will only be applied if this post-processor
* actually creates a proxy for the specific bean. If there are competing
* post-processors or if the bean is not eligible for proxying for other reasons,
* no custom TargetSource will be applied.
* <p>TargetSourceCreators can only be invoked if this post-processor comes first
* in the list of BeanPostProcessors; otherwise, the TargetSource will not be
* in effect. Custom target sources are disabled by default.
* @param targetSourceCreators list of TargetSourceCreator
* implementations to apply in the given order
*/
public void setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators);
/**
* Set the common interceptors. These must be bean names in the current factory.
* They can be of any advice or advisor type Spring supports.
* <p>If this property isn't set, there will be zero common interceptors.
* This is perfectly valid, if "specific" interceptors such as matching
* Advisors are all we want.
* @param interceptorNames the list of interceptor names
*/
public void setInterceptorNames(String... interceptorNames);
/**
* Set the BeanFactory to use. This will be used to retrieve the named
* interceptors set in this class.
*/
@Override
public void setBeanFactory(BeanFactory beanFactory);
/**
* Return the owning BeanFactory.
* May be {@code null}, as this post-processor doesn't need to belong to a bean factory.
*/
protected BeanFactory getBeanFactory();
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName);
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
/**
* Return an array of additional interceptors (or advisors) for the
* given bean. Is called if the bean is eligible for proxying.
* <p>The returned advisors will be applied to the bean in addition to
* any advisors corresponding to common interceptors for the proxy.
* Advisors are invoked in the order specified.
* <p>The default implementation returns the given advisors as-is.
* @param advisors the advisors obtained so far for the particular bean
* @param beanName the name of the bean
* @param targetClass the class of the bean to be advised
* @return the additional advisors for the particular bean;
* or the given advisors as-is.
* The return value will be added to the advisors list.
* Null means no additional advisor.
* @throws BeansException in case of errors
*/
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) throws BeansException;
/**
* Subclasses should override this to return {@code true} if the
* given bean should not be considered for auto-proxying.
* <p>Sometimes we need to be able to avoid this happening, e.g. if it will lead to
* a circular reference or if the existing target instance needs to be preserved.
* This implementation returns {@code false} unless the bean name indicates an
* "original instance" according to {@code AutoProxyUtils.isOriginalInstance}.
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @return whether to skip the given bean
*/
protected boolean shouldSkip(Class<?> beanClass, String beanName);
/**
* Create a target source for bean instances. Uses any TargetSourceCreators if set.
* Returns {@code null} if no custom TargetSource should be used.
* <p>This implementation uses the "customTargetSourceCreators" property.
* Subclasses can override this method to use a different mechanism.
* @param beanClass the class of the bean to create a TargetSource for
* @param beanName the name of the bean
* @return a TargetSource for this bean
* @see #setCustomTargetSourceCreators
*/
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName);
/**
* Create an AOP proxy for the given bean.
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @param specificInterceptors the set of interceptors that is
* specific to this bean (may be empty, but not null)
* @param targetSource the TargetSource for the proxy,
* already pre-configured to access the bean
* @return the AOP proxy for the bean
* @see #buildAdvisors
*/
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource);
/**
* Determine the advisors for the given bean, including the specific interceptors
* as well as the common interceptor, all adapted to the Advisor interface.
* @param beanName the name of the bean
* @param specificInterceptors the set of interceptors that is
* specific to this bean (may be empty, but not null)
* @return the list of Advisors for the given bean
*/
protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors);
}Auto-proxy creators that work with Advisor beans in the application context.
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
/**
* Set whether to use the bean name of the advisor bean as the advisor's name,
* instead of the default advisor name (which is the simple class name).
* <p>Default is "false".
* @param useAdvisorBeanNameAsAdvisorName whether to use the bean name as advisor name
*/
public void setUseAdvisorBeanNameAsAdvisorName(boolean useAdvisorBeanNameAsAdvisorName);
/**
* Return whether to use the bean name of the advisor bean as advisor name.
*/
public boolean isUseAdvisorBeanNameAsAdvisorName();
@Override
public void setBeanFactory(BeanFactory beanFactory);
/**
* Find all candidate Advisors to use in auto-proxying.
* @return the List of candidate Advisors
*/
protected List<Advisor> findCandidateAdvisors();
/**
* Search the given candidate Advisors to find all Advisors that
* can apply to the specified bean.
* @param candidateAdvisors the candidate Advisors
* @param beanClass the target's bean class
* @param beanName the target's bean name
* @return the List of applicable Advisors
* @see ProxyCreationContext#getCurrentProxiedBeanName()
*/
protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName);
/**
* Return whether the Advisor bean with the given name is eligible
* for proxying in the first place.
* @param beanName the name of the Advisor bean
* @return whether the bean is eligible
*/
protected boolean isEligibleAdvisorBean(String beanName);
/**
* Sort advisors based on ordering. Subclasses may choose to override this
* method to customize the sorting algorithm.
* @param advisors the source List of Advisors
* @return the sorted List of Advisors
* @see org.springframework.core.Ordered
* @see org.springframework.core.annotation.Order
* @see org.springframework.core.annotation.AnnotationAwareOrderComparator
*/
protected List<Advisor> sortAdvisors(List<Advisor> advisors);
/**
* Extension point that allows for providing a custom instance of the
* AutoProxyUtils that is used by auto-proxy creators.
* <p>The default implementation returns {@code DefaultAutoProxyUtils}.
* @return the AutoProxyUtils instance to use
* @since 4.2.3
*/
protected AutoProxyUtils getAutoProxyUtils();
}
public class DefaultAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
/**
* A marker prefix indicating that the bean name following the prefix is an advisor
* that should be included in the proxying process.
*/
public static final String ADVISOR_BEAN_NAME_PREFIX = "org.springframework.aop.Advisor.";
/**
* Set the prefix that advisor bean names must have.
* <p>The default value is {@link #ADVISOR_BEAN_NAME_PREFIX}.
* @param advisorBeanNamePrefix the required prefix for advisor bean names
*/
public void setAdvisorBeanNamePrefix(String advisorBeanNamePrefix);
/**
* Return the prefix that advisor bean names must have.
*/
public String getAdvisorBeanNamePrefix();
}
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
@Override
protected boolean isEligibleAdvisorBean(String beanName);
}Auto-proxy creator that selects beans for proxying based on their bean names.
public class BeanNameAutoProxyCreator extends AbstractAutoProxyCreator {
/**
* Set the names of the beans that should automatically get wrapped with proxies.
* A name can specify a prefix to match by ending with "*", e.g. "myBean,tx*"
* will match the bean named "myBean" and all beans whose name start with "tx".
* <p><b>NOTE:</b> In case of a FactoryBean, only the objects created by the
* FactoryBean will get proxied. This default behavior applies as of Spring 2.0.
* If you intend to proxy a FactoryBean itself, specify the bean name of the
* FactoryBean including the factory-bean prefix "&": e.g. "&myFactoryBean".
* @param beanNames the list of bean names
*/
public void setBeanNames(String... beanNames);
/**
* Set the common interceptors. These must be bean names in the current factory.
* They can be of any advice or advisor type Spring supports.
* <p>If this property isn't set, there will be zero common interceptors.
* This is perfectly valid, if "specific" interceptors such as matching
* Advisors are all we want.
* @param interceptorNames the list of interceptor names
*/
public void setInterceptorNames(String... interceptorNames);
/**
* Identify as a bean to proxy if the bean name is in the configured list of names.
*/
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource);
/**
* Check whether the given bean name is in the configured list of bean names.
* @param beanName the bean name to check
* @return whether the given bean name is in the configured list of bean names
*/
protected boolean isMatch(String beanName);
}Auto-proxy creator that integrates with AspectJ for advanced pointcut expressions and aspect processing.
public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
@Override
protected List<Advisor> sortAdvisors(List<Advisor> advisors);
/**
* Add an AspectJPrecedenceComparator decorator to the List returned by
* the superclass, so that AspectJ advisors are sorted according to AspectJ rules.
* @param advisors the source List of Advisors
* @return the sorted List of Advisors
* @see org.springframework.aop.aspectj.annotation.AspectJPrecedenceComparator
*/
@Override
protected List<Advisor> sortAdvisors(List<Advisor> advisors);
}
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
/**
* Set the list of aspect types for which to create Spring AOP Advisors.
* <p>Note: This is supported but not usually necessary. By default, Spring
* will automatically detect any @AspectJ classes in the application context.
* @param aspectClassNames the list of aspect class names
*/
public void setIncludePatterns(List<String> includePatterns);
/**
* Set the BeanNameAware bean names for this post-processor.
* <p>Note: This is supported but not usually necessary. By default, Spring
* will automatically detect any @AspectJ classes in the application context.
* @param aspectNames the list of aspect names
*/
public void setAspectNames(List<String> aspectNames);
/**
* Find all candidate Advisors to use in auto-proxying.
* @return the List of candidate Advisors
*/
@Override
protected List<Advisor> findCandidateAdvisors();
/**
* Build AspectJ advisors for all AspectJ aspects in the bean factory.
* @see #buildAspectJAdvisors()
*/
protected List<Advisor> buildAspectJAdvisors();
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName);
/**
* Check whether the given aspect bean is eligible for auto-proxying.
* <p>If no <aop:include> elements were used then "includePatterns" will be
* {@code null} and all beans are included. If "includePatterns" is non-null,
* then one of the patterns must match.
* @param beanName the name of the aspect bean
* @return whether the bean is eligible
*/
protected boolean isEligibleAspectBean(String beanName);
}Helper classes for auto-proxy creation functionality.
public class BeanFactoryAdvisorRetrievalHelper {
/**
* Create a new BeanFactoryAdvisorRetrievalHelper for the given BeanFactory.
* @param beanFactory the ListableBeanFactory to scan
*/
public BeanFactoryAdvisorRetrievalHelper(ListableBeanFactory beanFactory);
/**
* Find all eligible Advisor beans in the current bean factory,
* ignoring FactoryBeans and excluding beans that are currently in creation.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
public List<Advisor> findAdvisorBeans();
/**
* Determine whether the aspect bean with the given name is eligible.
* <p>The default implementation always returns {@code true}.
* @param beanName the name of the aspect bean
* @param beanDefinition the corresponding bean definition
* @return whether the bean is eligible
*/
protected boolean isEligibleBean(String beanName, BeanDefinition beanDefinition);
}
public interface TargetSourceCreator {
/**
* Create a special TargetSource for the given bean, if any.
* @param beanClass the class of the bean to create a TargetSource for
* @param beanName the name of the bean
* @return a special TargetSource or {@code null} if this TargetSourceCreator isn't
* interested in the particular bean
*/
TargetSource getTargetSource(Class<?> beanClass, String beanName);
}@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
// Define advisor beans - they will be automatically applied
@Bean
public Advisor transactionAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)");
return new DefaultPointcutAdvisor(pointcut, new TransactionInterceptor());
}
@Bean
public Advisor securityAdvisor() {
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames("secure*", "admin*");
return new DefaultPointcutAdvisor(pointcut, new SecurityInterceptor());
}
}@Component
public class CustomAutoProxyCreator extends AbstractAutoProxyCreator {
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource) {
// Custom logic to determine which beans should be proxied
if (beanClass.isAnnotationPresent(MyCustomAnnotation.class)) {
return new Object[] {
new LoggingInterceptor(),
new PerformanceInterceptor()
};
}
return DO_NOT_PROXY;
}
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// Skip internal Spring beans and configuration classes
return super.shouldSkip(beanClass, beanName) ||
beanClass.isAnnotationPresent(Configuration.class);
}
}@Configuration
public class BeanNameAutoProxyConfig {
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
creator.setBeanNames("*Service", "*Repository", "userManager");
creator.setInterceptorNames("loggingInterceptor", "transactionInterceptor");
return creator;
}
@Bean
public MethodInterceptor loggingInterceptor() {
return invocation -> {
System.out.println("Calling: " + invocation.getMethod().getName());
Object result = invocation.proceed();
System.out.println("Finished: " + invocation.getMethod().getName());
return result;
};
}
@Bean
public MethodInterceptor transactionInterceptor() {
return invocation -> {
System.out.println("Starting transaction");
try {
Object result = invocation.proceed();
System.out.println("Committing transaction");
return result;
} catch (Exception e) {
System.out.println("Rolling back transaction");
throw e;
}
};
}
}@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class AdvancedAopConfig {
@Bean
public AnnotationAwareAspectJAutoProxyCreator autoProxyCreator() {
AnnotationAwareAspectJAutoProxyCreator creator = new AnnotationAwareAspectJAutoProxyCreator();
creator.setProxyTargetClass(true);
creator.setExposeProxy(true);
creator.setOrder(Ordered.HIGHEST_PRECEDENCE);
// Only process beans matching these patterns
creator.setIncludePatterns(Arrays.asList(".*Service.*", ".*Controller.*"));
return creator;
}
@Aspect
@Component
public class PerformanceAspect {
@Around("@annotation(org.springframework.cache.annotation.Cacheable)")
public Object measureCacheablePerformance(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - start;
System.out.println("Cacheable method " + joinPoint.getSignature() +
" executed in " + executionTime + "ms");
return result;
}
}
}@Configuration
public class InfrastructureAopConfig {
@Bean
public InfrastructureAdvisorAutoProxyCreator infrastructureAutoProxyCreator() {
return new InfrastructureAdvisorAutoProxyCreator();
}
// Only infrastructure advisors will be applied
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public Advisor infrastructureAdvisor() {
return new DefaultPointcutAdvisor(
new AnnotationMatchingPointcut(Repository.class),
new DataAccessExceptionInterceptor()
);
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-springframework--spring-aop