其实现在springboot是默认开启AOP的。
@EnableAspectJAutoProxy这个注解就是手动开启AOP的一个注解。
想看看Spring在背后做了哪些事情就得从源码入手一起来看下。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
@EnableAspectJAutoProxy注解中两个参数 proxyTargetClass 、exposeProxy
- proxyTargetClass
制AOP代理的具体实现方式。英文注释很简单哈,是否开启CGLIB(基于子类)的代理,为true 的话使用CGLIB,为false的话使用基于标准 Java 接口的代理。默认使用JDK的动态代理。 - exposeProxy
控制代理的暴露方式。是否暴露当前代理对象为ThreadLocal模式。可以解决内部调用不能使用切面的问题,为true的话可以获取代理对象,通过代理对象调用方法进入切面。
//实例伪代码
T proxy=(T) AopContext.currentProxy();
这里核心是@import(AspectJAutoProxyRegistrar.class)
AspectJAutoProxyRegistrarclass AspectJAutoProxyRegistrar implements importBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry) {
//装载bean
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassmetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
通过registerBeanDefinitions方法向Spring容器中注册bean实例。
重点是 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 这句。
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, (Object)null);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
AopConfigUtils这个工具类的主要作用就是把AnnotationAwareAspectJAutoProxyCreator这个类定义为BeanDefinition放到spring容器中,具体怎么实现装载的可以参看importBeanDefinitionRegistrar 这个接口。Spring官方在动态注册bean时,大部分套路其实是使用importBeanDefinitionRegistrar接口。
所有实现了该接口的类都会被ConfigurationClassPostProcessor处理,ConfigurationClassPostProcessor实现了BeanFactoryPostProcessor接口,所以importBeanDefinitionRegistrar中动态注册的bean是优先于依赖其的bean初始化的,也能被aop、validator等机制处理。
这里重点类就是被注册到容器中的AnnotationAwareAspectJAutoProxyCreator这个类。也是Spring AOP 最为核心的一个类。
AnnotationAwareAspectJAutoProxyCreator
从类图上可以大致了解AnnotationAwareAspectJAutoProxyCreator这个创建器是用来做什么的。
- 实现了一系列Aware的接口
Aware,翻译过来是知道的,已感知的,意识到的,所以这些接口从字面意思就是能感知到所有Aware前面的含义。
在Bean装载的时候获取BeanFactory(Bean容器),Bean的ClassLoader - 实现了Ordered接口
对切点上的切面进行排序 - 继承了PorxyConfig
ProxyConfig中主要封装了代理的通用处理逻辑,比如设置目标类,设置使用cglib还是java proxy等一些基础配置. - 实现了BeanPostProcessor接口
BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口。也是AOP实现代理的核心。
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
BeanPostProcessor接口有两个回调方法。当一个BeanPostProcessor的实现类注册到Spring IOC容器后,对于该Spring IOC容器所创建的每个bean实例在初始化方法(如afterPropertiesSet和任意已声明的init方法)调用前,将会调用BeanPostProcessor中的postProcessBeforeInitialization方法,而在bean实例初始化方法调用完成后,则会调用BeanPostProcessor中的postProcessAfterInitialization方法
AbstractAutoProxyCreator再看下最顶部的抽象类,主要抽象了实现代理的逻辑。也就是postProcessBeforeInitialization方法。
@Override
public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
//1.不需要创建代理
if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
//2.如果是基础设施或者应该跳过的类,则说明这个类不需要创建代理,缓存起来
//默认shouldSkip是false,都不应该跳过
//但是AspectJAwareAdvisorAutoProxyCreator实现了该方法
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
//2.对于自定义的TargetSource会立即创建代理,并缓存
if (beanName != null) {
//自定义 TargetSource
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
//如果不是TargetSource,一般不会走到这里
if (targetSource != null) {
this.targetSourcedBeans.add(beanName);
//获取切面
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
return null;
}
TargetSource(目标源)是被代理的target(目标对象)实例的来源。TargetSource被用于获取当前MethodInvocation(方法调用)所需要的目标对象target。换句话说,proxy代理的并不是target,而是targetSource对象。
通常情况下,一个代理对象只能代理一个target,每次方法调用目标也是唯一的target。但是如果让proxy代理TargetSource,可以使得每次方法调用的target实例都不相同。(当然,这取决于TargetSource的实现)。而这种机制,可以使得方法的调用更加灵活。
当我们开启了EbableAspectJAutoProxy后,每次Bean的装配时,都会执行这段逻辑.前面主要是校验是否需要对bean进行代理(特殊的类,和已经被代理),核心逻辑在后面几行的getAdvicesAndAdvisorsForBean方法来获取所有符合条件的切面,具体的实现在子类,这里是抽象方法,获取切面后就是创建代理:
protected Object createProxy(Class> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
//复制当前类的属性
proxyFactory.copyFrom(this);
//如果注解里面配置的是false
if (!proxyFactory.isProxyTargetClass()) {
if (this.shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
this.evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
//加入增强器
proxyFactory.addAdvisors(advisors);
//设置要代理的targetSource
proxyFactory.setTargetSource(targetSource);
//用户自定义代理
this.customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (this.advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//创建代理
return proxyFactory.getProxy(this.getProxyClassLoader());
}
TargetSource中存放被代理的对象,这段代码主要是为了构建ProxyFactory,将配置信息(是否使用java proxy,是否threadlocal等),目标类,切面,传入ProxyFactory中,而在ProxyFactory中,会通过createAopProxy()方法创建代理工厂DefaultAopProxyFactory,由代理厂生成具体的代理对目标类进行代理。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// //这里初步判断代理的创建方式,如果不满足则直接使用 JDK 动态代理,如果满足条件,则进一步在判断是否使用 JKD 动态代理还是 CGLIB 代理
if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
return new JdkDynamicAopProxy(config);
} else {
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.");
} else {
// 如果代理的是接口或者设置代理的类就是当前类,则使用 JDK 动态代理 ,否则使用 CGLIB 代理
return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
}
}
}
我们主要看一下JdkDynamicAopProxy的实现。
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 获取代理类的接口
Class>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 处理 equals , hashcode 方法
this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
JdkDynamicAopProxy同时实现了InvocationHandler,用来执行目标方法。Spring官方说法:
每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用.
看下JDK动态代理的invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
// 目标类
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 如果接口没有定义 equals 方法且当前方法是 equals 方法,则不会增强,直接返回
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// 如果接口没有定义 hashCode方法且当前方法是 hashCode方法,则不会增强,直接返回
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// 如果方法所在的类和Advised是同一个类或者是父类子类关系,则直接执行
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
// 返回值
Object retVal;
// 这里对应的是expose-proxy属性的应用,把代理暴露处理
// 目标方法内部的自我调用将无法实施切面中的增强,所以在这里需要把代理暴露出去
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class> targetClass = (target != null ? target.getClass() : null);
// 获取该方法的拦截器
List
在执行拦截器方法 proceed 中执行增强方法,比如前置增强在方法之前执行,后置增强在方法之后执行,proceed 方法如下:
public Object proceed() throws Throwable {
//当执行完所有增强方法后执行目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// method.invoke(target, args)
return invokeJoinpoint();
}
// 获取下一个要执行的拦截器
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 动态匹配
InterceptorAndDynamicMethodMatcher dm = interceptorOrInterceptionAdvice;
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 {
// 如果动态匹配失败,则跳过该拦截器,执行下一个拦截器
return proceed();
}
}
else {
// 普通拦截器,直接调用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
在该方法中完成了增强的植入,主要逻辑就是,每个方法都会有一个拦截器链,在 AOP 中我们称之为增强,然后循环执行每个拦截器链,当执行完所有的拦截器后,才会执行目标方法。比如 @After 对应的增强器AspectJAfterAdvice, @Around对应的增强器AspectJAroundAdvice等。
总结上面就是@EnableAspectJAutoProxy背后Spring做的一系列事情。其实还有一些细节没有再扣,比如Spring是如何获取切面的,创建器具体是怎么装载的等等。可以看到spring在背后确实为我们做了许多事情。
其实上面的一大段简单的来说就是
@EnableAspectJAutoProxy通过@import导入AspectJAutoProxyRegistrar.class,
然后AspectJAutoProxyRegistrar是importBeanDefinitionRegistrar接口的实现类,
又导入了AnnotationAwareAspectJAutoProxyCreator这个核心类;
PS:无关紧要的随笔,阅读源码真的很枯燥,但是又真的能让你看到很多以前看不到的东西。第一次的学习记录有很多瑕疵,期待越来越好的自己。



