工程依赖
我们需要使用 @Async
注解来说明 Spring AOP 的原理,@Async
注解在 spring-context 工程下,引入其依赖。
org.springframework
spring-context
Spring Bean 的 this
Configuration Bean 的 this
Configuration Bean 就是标注了 @Configuration
注解的 Bean,又分为两种情况:proxyBeanMethods = true
和 proxyBeanMethods = false
。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
// Specify whether @Bean methods should get proxied in order to enforce bean lifecycle behavior, e.g. to return shared singleton bean instances even in case of direct @Bean method calls in user code. This feature requires method interception, implemented through a runtime-generated CGLIB subclass which comes with limitations such as the configuration class and its methods not being allowed to declare final.
// The default is true, allowing for 'inter-bean references' via direct method calls within the configuration class as well as for external calls to this configuration's @Bean methods, e.g. from another configuration class. If this is not needed since each of this particular configuration's @Bean methods is self-contained and designed as a plain factory method for container use, switch this flag to false in order to avoid CGLIB subclass processing.
// Turning off bean method interception effectively processes @Bean methods individually like when declared on non-@Configuration classes, a.k.a. "@Bean Lite Mode" (see @Bean's javadoc). It is therefore behaviorally equivalent to removing the @Configuration stereotype.
boolean proxyBeanMethods() default true;
@Configuration(proxyBeanMethods = true)
:默认设置,代理模式。@Bean methods 将被 CGLib Proxy 代理,无论在 Configuration Bean 中调用多少次 @Bean methods,该 Bean 实例只会被创建一次。
proxyBeanMethods = true
情况下,代码执行到 AppConfig
类中时,this
为 CGLib 代理对象。对于 CGLib Proxy,这种情况只有一种做法:在 MethodInterceptor
中执行 MethodProxy#invokeSuper()
方法。
此时执行 user()
方法会进入 BeanMethodInterceptor
切面逻辑中:如果 bean 已经在 Spring 容器中存在,则从容器中取,否则创建 bean 对象并放到 Spring 容器中。
@Configuration(proxyBeanMethods = false)
:无代理模式,Spring 把这种模式称作 @Bean Lite Mode,@Configuration(proxyBeanMethods = false)
和 @Component
注解效果是一样的。在 proxyBeanMethods = false
情况下,代码执行到 AppConfig
类中时,this
为原始对象(非代理对象)。
普通 Bean 的 this
何为普通 Bean,我理解除去使用 @Configuration
注册的 Bean 大部分都是普通 Bean,比如 @Component
、@Service
、@Repository
、@Controller
、@Bean
等。在本工程中,UserService
就是普通 bean。
@Bean
public UserService userService() {
return new UserServiceImpl(user());
}
UserService this 的截图
Configuration 原理
Proxy 执行流程
由于 this
为 CGLib 代理对象,在执行 user()
方法时会进入切面 BeanMethodInterceptor
中,该切面会被执行两次。
第一次进入 intercept()
方法中,因为当前正在创建 userService bean,不是 user bean,所以 if (isCurrentlyInvokedFactoryMethod(beanMethod))
条件为 false
,会进入 resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName)
方法中,调用 beanFactory.getBean(beanName)
方法创建 user bean。
第二次进入 intercept()
方法中(至于为啥进两次,我也没研究清楚),因为当前正在创建 user bean,if (isCurrentlyInvokedFactoryMethod(beanMethod))
条件为 true
,会执行 cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs)
方法,调用父类 AppConfig#user()
方法创建 user bean。
class ConfigurationClassEnhancer {
// Intercepts the invocation of any Bean-annotated methods in order to ensure proper handling of bean semantics such as scoping and AOP proxying.
private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {
// Enhance a @Bean method to check the supplied BeanFactory for the existence of this bean object.
@Override
@Nullable
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// Determine whether this bean is a scoped-proxy
if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}
// To handle the case of an inter-bean method reference, we must explicitly check the
// container for already cached instances.
// First, check to see if the requested bean is a FactoryBean. If so, create a subclass
// proxy that intercepts calls to getObject() and returns any cached bean instance.
// This ensures that the semantics of calling a FactoryBean from within @Bean methods
// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
factoryContainsBean(beanFactory, beanName)) {
Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// Scoped proxy factory beans are a special case and should not be further proxied
}
else {
// It is a candidate FactoryBean - go ahead with enhancement
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
// The factory is calling the bean method in order to instantiate and register the bean
// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
// create the bean instance.
if (logger.isInfoEnabled() &&
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
"result in a failure to process annotations such as @Autowired, " +
"@Resource and @PostConstruct within the method's declaring " +
"@Configuration class. Add the 'static' modifier to this method to avoid " +
"these container lifecycle issues; see @Bean javadoc for complete details.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
}
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
// Check whether the given method corresponds to the container's currently invoked factory method. Compares method name and parameter types only in order to work around a potential problem with covariant return types (currently only known to happen on Groovy classes).
private boolean isCurrentlyInvokedFactoryMethod(Method method) {
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}
private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
ConfigurableBeanFactory beanFactory, String beanName) {
// The user (i.e. not the factory) is requesting this bean through a call to
// the bean method, direct or indirect. The bean may have already been marked
// as 'in creation' in certain autowiring scenarios; if so, temporarily set
// the in-creation status to false in order to avoid an exception.
boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
try {
if (alreadyInCreation) {
beanFactory.setCurrentlyInCreation(beanName, false);
}
boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
if (useArgs && beanFactory.isSingleton(beanName)) {
// Stubbed null arguments just for reference purposes,
// expecting them to be autowired for regular singleton references?
// A safe assumption since @Bean singleton arguments cannot be optional...
for (Object arg : beanMethodArgs) {
if (arg == null) {
useArgs = false;
break;
}
}
}
Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
beanFactory.getBean(beanName));
if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
// Detect package-protected NullBean instance through equals(null) check
if (beanInstance.equals(null)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("@Bean method %s.%s called as bean reference " +
"for type [%s] returned null bean; resolving to null value.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
beanMethod.getReturnType().getName()));
}
beanInstance = null;
}
else {
String msg = String.format("@Bean method %s.%s called as bean reference " +
"for type [%s] but overridden by non-compatible bean instance of type [%s].",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
try {
BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore - simply no detailed message then.
}
throw new IllegalStateException(msg);
}
}
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
if (currentlyInvoked != null) {
String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
beanFactory.registerDependentBean(beanName, outerBeanName);
}
return beanInstance;
}
finally {
if (alreadyInCreation) {
beanFactory.setCurrentlyInCreation(beanName, true);
}
}
}
第一次进入 intercept()
方法中,执行 resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName)
方法。
第二次进入 intercept()
方法中,执行 cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs)
方法。
Proxy 创建流程
以 BeanMethodInterceptor
为源头,找到引用该类的地方: ConfigurationClassEnhancer
中 static final Callback[] CALLBACKS
--> Class createClass(Enhancer enhancer)
。在 createClass()
方法中,调用 Enhancer.registerStaticCallbacks(subclass, CALLBACKS)
, 将 Callback[] CALLBACKS
设置到代理类中。
在 newEnhancer()
方法中,设置了一些 enhancer
对象的属性:
enhancer.setSuperclass(configSuperClass)
:设置代理类的父类为 Configuration 类。
enhancer.setInterfaces(new Class[] {EnhancedConfiguration.class})
:EnhancedConfiguration
接口继承了 BeanFactoryAware
接口,因此在 Configuration 类中可以获取 BeanFactory
实例,BeanMethodInterceptor
中就是这样干的!
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE)
:设置代理类名称的生成策略为 SpringNamingPolicy
。
class ConfigurationClassEnhancer {
// The callbacks to use. Note that these callbacks must be stateless.
static final Callback[] CALLBACKS = new Callback[] {
new BeanMethodInterceptor(),
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
// Loads the specified class and generates a CGLIB subclass of it equipped with container-aware callbacks capable of respecting scoping and other bean semantics.
public Class enhance(Class configClass, @Nullable ClassLoader classLoader) {
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Ignoring request to enhance %s as it has " +
"already been enhanced. This usually indicates that more than one " +
"ConfigurationClassPostProcessor has been registered (e.g. via " +
"). This is harmless, but you may " +
"want check your configuration and remove one CCPP if possible",
configClass.getName()));
}
return configClass;
}
Class enhancedClass = createClass(newEnhancer(configClass, classLoader));
if (logger.isTraceEnabled()) {
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
configClass.getName(), enhancedClass.getName()));
}
return enhancedClass;
}
// Creates a new CGLIB Enhancer instance.
private Enhancer newEnhancer(Class configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
enhancer.setInterfaces(new Class[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setAttemptLoad(true);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
// Uses enhancer to generate a subclass of superclass, ensuring that callbacks are registered for the new subclass.
private Class createClass(Enhancer enhancer) {
Class subclass = enhancer.createClass();
// Registering callbacks statically (as opposed to thread-local)
// is critical for usage in an OSGi environment (SPR-5932)...
Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
return subclass;
}
ConfigurationClassEnhancer#enhance()
调用 createClass()
方法生成代理类。
顺着调用链路,发现是 ConfigurationClassPostProcessor#enhanceConfigurationClasses()
方法中调用了 ConfigurationClassEnhancer#enhance()
方法。
在 proxyBeanMethods = true
的情况下,Configuration 类处于 full 模式,if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr))
条件成立,会执行 configBeanDefs.put(beanName, abd)
。紧接着会遍历 configBeanDefs
,为每个 configBeanDef
都创建 CGLib 代理类。
在 proxyBeanMethods = false
的情况下,Configuration 类处于 lite 模式,if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr))
条件不成立,不会为 AppConfig
创建 CGLib 代理类。
// BeanFactoryPostProcessor used for bootstrapping processing of @Configuration classes.
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
BeanRegistrationAotProcessor, BeanFactoryInitializationAotProcessor, PriorityOrdered,
ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {
// Prepare the Configuration classes for servicing bean requests at runtime by replacing them with CGLIB-enhanced subclasses.
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
// Post-processes a BeanFactory in search of Configuration class BeanDefinitions; any candidates are then enhanced by a ConfigurationClassEnhancer. Candidate status is determined by BeanDefinition attribute metadata.
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
StartupStep enhanceConfigClasses = this.applicationStartup.start("spring.context.config-classes.enhance");
Map configBeanDefs = new LinkedHashMap();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
AnnotationMetadata annotationMetadata = null;
MethodMetadata methodMetadata = null;
if (beanDef instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {
annotationMetadata = annotatedBeanDefinition.getMetadata();
methodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
}
if ((configClassAttr != null || methodMetadata != null) &&
(beanDef instanceof AbstractBeanDefinition abd) && !abd.hasBeanClass()) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> eagerly resolve bean class at this point, unless it's a 'lite' configuration
// or component class without @Bean methods.
boolean liteConfigurationCandidateWithoutBeanMethods =
(ConfigurationClassUtils.CONFIGURATION_CLASS_LITE.equals(configClassAttr) &&
annotationMetadata != null && !ConfigurationClassUtils.hasBeanMethods(annotationMetadata));
if (!liteConfigurationCandidateWithoutBeanMethods) {
try {
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
if (!(beanDef instanceof AbstractBeanDefinition abd)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
configBeanDefs.put(beanName, abd);
}
}
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
enhanceConfigClasses.end();
return;
}
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// Set enhanced subclass of the user-specified bean class
Class configClass = beanDef.getBeanClass();
Class enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
if (logger.isTraceEnabled()) {
logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
}
beanDef.setBeanClass(enhancedClass);
}
}
enhanceConfigClasses.tag("classCount", () -> String.valueOf(configBeanDefs.keySet().size())).end();
}
在 proxyBeanMethods = true
的情况下,Configuration 类处于 full 模式。
在 proxyBeanMethods = false
的情况下,Configuration 类处于 lite 模式
@Async 原理
CglibAopProxy
Debug 流程解析:
Step into userService.doThingsAsync()
方法,会发现代码进入到 CglibAopProxy#FixedChainStaticTargetInterceptor
类中,获取到的 interception chain 为 [AnnotationAsyncExecutionInterceptor
]
执行 proceed()
方法的调用链路为:CglibMethodInvocation#proceed()
--> ReflectiveMethodInvocation#proceed()
。
执行 ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)
会进入切面方法 AsyncExecutionInterceptor#invoke()
中。
执行 invocation.proceed()
会进入 ReflectiveMethodInvocation#proceed()
方法中,此时切面都执行完了,会调用 invokeJoinpoint()
执行被代理对象的方法。
执行invokeJoinpoint()
方法会调用 AopUtils#invokeJoinpointUsingReflection()
,该方法使用反射执行被代理对象的方法。为啥不用 MethodProxy
呢?感觉 CGLib Proxy 优势被抛弃了。。
进入到 UserServiceImpl
类中,this
为被代理对象。
源码解析:
执行代理对象的方法会进入 CglibMethodInvocation#DynamicAdvisedInterceptor
类的 intercept()
方法中,DynamicAdvisedInterceptor
类实现了 MethodInterceptor
接口,是一个切面实现类。
名称中 Dynamic 的含义:代理对象的 interception chain 可能会改变,因此每次执行 intercept()
方法都会调用 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
,获取可能会动态变化的 interception chain。与之相反的切面类为 FixedChainStaticTargetInterceptor
,该 interceptor 创建的时候就会指定 adviceChain
,后面就不会再变了。
class CglibAopProxy implements AopProxy, Serializable {
// General purpose AOP callback. Used when the target is dynamic or when the proxy is not frozen.
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class targetClass = (target != null ? target.getClass() : null);
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
private static class FixedChainStaticTargetInterceptor implements MethodInterceptor, Serializable {
private final List adviceChain;
@Nullable
private final Object target;
@Nullable
private final Class targetClass;
public FixedChainStaticTargetInterceptor(
List adviceChain, @Nullable Object target, @Nullable Class targetClass) {
this.adviceChain = adviceChain;
this.target = target;
this.targetClass = targetClass;
}
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
MethodInvocation invocation = new CglibMethodInvocation(
proxy, this.target, method, args, this.targetClass, this.adviceChain, methodProxy);
// If we get here, we need to create a MethodInvocation.
Object retVal = invocation.proceed();
retVal = processReturnType(proxy, this.target, method, retVal);
return retVal;
}
}
获取到的 advice chain 不为空,则会执行 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed()
,CglibMethodInvocation
类继承了 ReflectiveMethodInvocation
,可以看到 CglibMethodInvocation
中几乎没有什么逻辑,主要逻辑都在 ReflectiveMethodInvocation
类中。
class CglibAopProxy implements AopProxy, Serializable {
// Implementation of AOP Alliance MethodInvocation used by this AOP proxy.
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
Object[] arguments, @Nullable Class targetClass,
List interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
}
@Override
@Nullable
public Object proceed() throws Throwable {
try {
return super.proceed();
}
catch (RuntimeException ex) {
throw ex;
}
catch (Exception ex) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||
KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {
// Propagate original exception if declared on the target method
// (with callers expecting it). Always propagate it for Kotlin code
// since checked exceptions do not have to be explicitly declared there.
throw ex;
}
else {
// Checked exception thrown in the interceptor but not declared on the
// target method signature -> apply an UndeclaredThrowableException,
// aligned with standard JDK dynamic proxy behavior.
throw new UndeclaredThrowableException(ex);
}
}
}
}
执行 super.proceed()
会进入到 ReflectiveMethodInvocation#proceed()
方法中。List interceptorsAndDynamicMethodMatchers
是由 interceptors 组成的责任链。
proceed()
方法责任链实现逻辑:
如果没有 interceptor 的话:if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1)
,就执行被代理对象的方法:return invokeJoinpoint()
。
否则遍历 interceptor chain:Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex)
我们程序中定义的切面类几乎都是 MethodInterceptor
类型,会走到 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)
注意责任链的实现精髓就是这个 this
,这样下一个 MethodInterceptor
就能拿到 ReflectiveMethodInvocation
实例,继续调用 ReflectiveMethodInvocation#proceed()
方法,重新回到责任链的执行逻辑中,注意此时 currentInterceptorIndex
已经在上一步完成了 ++
操作。
// Spring's implementation of the AOP Alliance MethodInvocation interface, implementing the extended ProxyMethodInvocation interface.
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
protected final Object proxy;
@Nullable
protected final Object target;
protected final Method method;
protected Object[] arguments;
@Nullable
private final Class targetClass;
/**
* Lazily initialized map of user-specific attributes for this invocation.
*/
@Nullable
private Map userAttributes;
/**
* List of MethodInterceptor and InterceptorAndDynamicMethodMatcher
* that need dynamic checks.
*/
protected final List interceptorsAndDynamicMethodMatchers;
/**
* Index from 0 of the current interceptor we're invoking.
* -1 until we invoke: then the current interceptor.
*/
private int currentInterceptorIndex = -1;
// Construct a new ReflectiveMethodInvocation with the given arguments.
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
@Nullable Class targetClass, List interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
// Proceed to the next interceptor in the chain.
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher dm) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
Class targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
// Invoke the joinpoint using reflection. Subclasses can override this to use custom invocation.
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
MethodInterceptor
是 Spring
定义的拦截器接口,用于实现 around advice。
// Intercepts calls on an interface on its way to the target. These are nested "on top" of the target.
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
// Implement this method to perform extra treatments before and after the invocation.
Object invoke(@Nonnull MethodInvocation invocation) throws Throwable;
执行 ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)
会进入 AsyncExecutionInterceptor#invoke()
方法中,首先会根据方法的 @Async
注解获取执行任务的线程池:AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod)
,然后将待执行的操作封装成一个 Callable
对象,最后调用 doSubmit(task, executor, invocation.getMethod().getReturnType())
方法执行被代理对象的方法。
// AOP Alliance MethodInterceptor that processes method invocations asynchronously, using a given AsyncTaskExecutor. Typically used with the org.springframework.scheduling.annotation.Async annotation.
public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport implements MethodInterceptor, Ordered {
// Intercept the given method invocation, submit the actual calling of the method to the correct task executor and return immediately to the caller.
@Override
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
if (executor == null) {
throw new IllegalStateException(
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
}
Callable task = () -> {
try {
Object result = invocation.proceed();
if (result instanceof Future) {
return ((Future) result).get();
}
}
catch (ExecutionException ex) {
handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());
}
catch (Throwable ex) {
handleError(ex, userDeclaredMethod, invocation.getArguments());
}
return null;
};
return doSubmit(task, executor, invocation.getMethod().getReturnType());
}
invocation.proceed()
会进入到 ReflectiveMethodInvocation#proceed()
方法中,此时 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1)
条件成立,会执行 return invokeJoinpoint()
--> AopUtils#invokeJoinpointUsingReflection()
,最终使用 JDK 反射执行被代理对象的方法,和 CGLib Proxy 根本没有关系,所以进入到 UserServiceImpl
中,this
为被代理对象。从这里也可以看到,Spring 舍弃了 CGLib 的 MethodProxy
和 FastClass
,为什么呢?使用 CGLib Proxy 性能不是会好一些吗?
public abstract class AopUtils {
// Invoke the given target via reflection, as part of an AOP method invocation.
@Nullable
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
throws Throwable {
// Use reflection to invoke the method.
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}
JdkDynamicAopProxy
@EnableAsync
注解有一个属性:proxyTargetClass
:
proxyTargetClass = true
表示条件满足的情况下(见下),会创建 CGLib Proxy 创建。
proxyTargetClass = false
表示条件满足的情况下(见下),会创建使用 JDK Proxy。
public @interface EnableAsync {
// Indicate whether subclass-based (CGLIB) proxies are to be created as opposed to standard Java interface-based proxies.
boolean proxyTargetClass() default false;
设置 @EnableAsync(proxyTargetClass = false)
,Step into userService.doThingsAsync()
方法,发现变成了切面 JdkDynamicAopProxy
。JdkDynamicAopProxy
中的逻辑与 CglibAopProxy
基本一致。至于为什么选择 Copy and Paste,Spring 官方给出的解释是:
NOTE: We could avoid the code duplication between this class and the CGLIB proxies by refactoring "invoke" into a template method. However, this approach adds at least 10% performance overhead versus a copy-paste solution, so we sacrifice elegance for performance (we have a good test suite to ensure that the different proxies behave the same :-)). This way, we can also more easily take advantage of minor optimizations in each class.
JdkDynamicAopProxy
和 CglibAopProxy
代码逻辑基本一致。
// JDK-based AopProxy implementation for the Spring AOP framework, based on JDK dynamic proxies.
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
// Implementation of InvocationHandler.invoke.
// Callers will see exactly the exception thrown by the target, unless a hook method throws an exception.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fall back on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
Proxy 创建流程
DefaultAopProxyFactory
类:创建 JDK Proxy 或者 CGLib Proxy。我们设置 @EnableAsync(proxyTargetClass = true)
将影响 config.isProxyTargetClass()
的值。如果被代理类不是接口、不是 JDK Proxy Class,不是 Lambda Class,则创建 ObjenesisCglibAopProxy
,否则创建 JdkDynamicAopProxy
。
// Default AopProxyFactory implementation, creating either a CGLIB proxy or a JDK dynamic proxy.
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
// Create an AopProxy for the given AOP configuration.
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
// Determine whether the supplied AdvisedSupport has only the SpringProxy interface specified (or no proxy interfaces specified at all).
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
创建 ObjenesisCglibAopProxy
:
@EnableAsync(proxyTargetClass = true)
配置下,DefaultAopProxyFactory
会创建 CGLib Proxy。
ObjenesisCglibAopProxy
类继承了 CglibAopProxy
类,重写了父类中的两个方法,实现 objenesis 相关的逻辑,这里不展开。
// Objenesis-based extension of CglibAopProxy to create proxy instances without invoking the constructor of the class. Used by default as of Spring 4.
class ObjenesisCglibAopProxy extends CglibAopProxy {
private static final SpringObjenesis objenesis = new SpringObjenesis();
// Create a new ObjenesisCglibAopProxy for the given AOP configuration.
public ObjenesisCglibAopProxy(AdvisedSupport config) {
super(config);
}
@Override
protected Class createProxyClass(Enhancer enhancer) {
return enhancer.createClass();
}
@Override
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
Class proxyClass = enhancer.createClass();
Object proxyInstance = null;
if (objenesis.isWorthTrying()) {
try {
proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
}
catch (Throwable ex) {
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex);
}
}
if (proxyInstance == null) {
// Regular instantiation via default constructor...
try {
Constructor ctor = (this.constructorArgs != null ?
proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
proxyClass.getDeclaredConstructor());
ReflectionUtils.makeAccessible(ctor);
proxyInstance = (this.constructorArgs != null ?
ctor.newInstance(this.constructorArgs) : ctor.newInstance());
}
catch (Throwable ex) {
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
"and regular proxy instantiation via default constructor fails as well", ex);
}
}
((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}
CglibAopProxy#getProxy()
方法用于创建代理对象,CglibAopProxy#getProxyClass()
方法用于创建代理类,最终都会走到 buildProxy()
方法中。buildProxy()
方法根据 advised
配置设置 enhancer
对象相关属性,调用 enhancer.create()
创建代理对象,或者调用 enhancer.createClass()
创建代理类。
// CGLIB-based AopProxy implementation for the Spring AOP framework.
class CglibAopProxy implements AopProxy, Serializable {
// Constants for CGLIB callback array indices
private static final int AOP_PROXY = 0;
private static final int INVOKE_TARGET = 1;
private static final int NO_OVERRIDE = 2;
private static final int DISPATCH_TARGET = 3;
private static final int DISPATCH_ADVISED = 4;
private static final int INVOKE_EQUALS = 5;
private static final int INVOKE_HASHCODE = 6;
/** Logger available to subclasses; static to optimize serialization. */
protected static final Log logger = LogFactory.getLog(CglibAopProxy.class);
/** Keeps track of the Classes that we have validated for final methods. */
private static final Map[] constructorArgTypes;
/** Dispatcher used for methods on Advised. */
private final transient AdvisedDispatcher advisedDispatcher;
private transient Map fixedInterceptorMap = Collections.emptyMap();
private transient int fixedInterceptorOffset;
// Create a new CglibAopProxy for the given AOP configuration.
public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
this.advised = config;
this.advisedDispatcher = new AdvisedDispatcher(this.advised);
}
@Override
public Object getProxy() {
return buildProxy(null, false);
}
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
return buildProxy(classLoader, false);
}
@Override
public Class getProxyClass(@Nullable ClassLoader classLoader) {
return (Class) buildProxy(classLoader, true);
}
private Object buildProxy(@Nullable ClassLoader classLoader, boolean classOnly) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
try {
Class rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class proxySuperClass = rootClass;
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
Class[] additionalInterfaces = rootClass.getInterfaces();
for (Class additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setAttemptLoad(true);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
Callback[] callbacks = getCallbacks(rootClass);
Class[] types = new Class[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
return (classOnly ? createProxyClass(enhancer) : createProxyClassAndInstance(enhancer, callbacks));
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
protected Class createProxyClass(Enhancer enhancer) {
enhancer.setInterceptDuringConstruction(false);
return enhancer.createClass();
}
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
enhancer.setInterceptDuringConstruction(false);
enhancer.setCallbacks(callbacks);
return (this.constructorArgs != null && this.constructorArgTypes != null ?
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
enhancer.create());
}
CglibAopProxy
对象实现了 AopProxy
接口的 getProxy()
和 getProxyClass()
方法
// Delegate interface for a configured AOP proxy, allowing for the creation of actual proxy objects.
public interface AopProxy {
// Create a new proxy object.
Object getProxy();
// Create a new proxy object.
Object getProxy(@Nullable ClassLoader classLoader);
// Determine the proxy class.
Class getProxyClass(@Nullable ClassLoader classLoader);
@EnableAsync(proxyTargetClass = true)
配置下,AsyncAnnotationBeanPostProcessor#postProcessAfterInitialization()
方法负责创建 CGLib Proxy,该方法在 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization()
中被调用。
创建 JdkDynamicAopProxy
:
JdkDynamicAopProxy#getProxy()
方法用于创建 JDK Proxy 对象。
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
/** Config used to configure this proxy. */
private final AdvisedSupport advised;
private final Class[] proxiedInterfaces;
/* Is the {@link #equals} method defined on the proxied interfaces? */
private boolean equalsDefined;
/* Is the {@link #hashCode} method defined on the proxied interfaces? */
private boolean hashCodeDefined;
// Construct a new JdkDynamicAopProxy for the given AOP configuration.
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
this.advised = config;
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
}
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
@EnableAsync(proxyTargetClass = false)
配置下,DefaultAopProxyFactory
会创建 JDK Proxy。
@EnableAsync(proxyTargetClass = false)
配置下,AsyncAnnotationBeanPostProcessor#postProcessAfterInitialization()
方法负责创建 JDK Proxy。