发布时间:2024-04-02 16:01
springboot:1.5.17.RELEASE
使用aop需要我们配置什么呢?答案是不需要,springboot已经全部封装好直接使用即可,那么springboot是如何帮我们完成aop配置的呢?直接看autoconfig jar呀,里面可以看到aop目录有一个AopAutoConfiguration配置类,那么看下都做了哪些动作吧
配置类代码很简单,自动启用AOP的条件限制
其实上面可以认为就一个条件1,几乎不需要认为干预。配置文件中有两类代理配置
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = true)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false)
public static class CglibAutoProxyConfiguration {
}
}
import导入AspectJAutoProxyRegistrar注册器
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* 表示是否使用基于子类(CGLIB)创建代理,相反则使用标准java的基于接口的代理,默认为false
*/
boolean proxyTargetClass() default false;
/**
* 表示代理将由AOP框架作为一个ThreadLocal暴露,为了可以通过
* {@link org.springframework.aop.framework.AopContext} 类取回代理。
* 默认关闭。即不保证 {@code AopContext} 访问能工作。
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
注册或升级APC(AutoProxyCreator)定义。如果注册中心已经存在APC类型定义则判断当前要注册的APC(AnnotationAwareAspectJAutoProxyCreator)的优先级,使用优先级高的定义,优先级定义如下
// 注册AnnotationAwareAspectJAutoProxyCreator bean定义
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
// org.springframework.aop.config.AopConfigUtils#APC_PRIORITY_LIST
static {
// Set up the escalation list...
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
如果注册中心中不存在APC类型定义则创建,默认lazyInit为false,完成上下文刷新时会初始化该bean
// org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
AnnotationAwareAspectJAutoProxyCreator bean父类AbstractAutoProxyCreator实现SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware接口
初始化bean时回调setBeanFactory方法,初始化advisor通知检索工具类,切面通知者构建者:aspectJAdvisorsBuilder,反射切面通知者工厂ReflectiveAspectJAdvisorFactory(工厂可以从支持AspectJ5语法的类中创建创建通知者,使用反射调用相应的advice方法)
// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#initBeanFactory
this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
// org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#initBeanFactory
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
postProcessBeforeInstantiation回调时返回当前bean之前的最终类型
如果需要则包装bean
包装bean如果需要
逻辑同getEarlyBeanReference,但是不需要向earlyProxyReferences缓存中添加该bean对应的cacheKey
返回给定的bean是否被代理,如果是返回代理bean应用的附加通知(例如:AOP Alliance interceptors)和advisors通知者。由父类实现该方法:org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
findCandidateAdvisors
findAdvisorsThatCanApply
extendAdvisors
如果使用的是AspectJ切面,则添加默认通知:org.springframework.aop.support.DefaultPointcutAdvisor
sortAdvisors
使用AnnotationAwareOrderComparator比较器排序通知
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
基于getAdvicesAndAdvisorsForBean返回的指定拦截器创建代理:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
基于beanName与特定的拦截器构建统一类型的通知(org.springframework.aop.Advisor):org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#buildAdvisors。org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#wrap将其他联盟(包含aspectJ)实现spring-aop接口org.aopalliance.aop.Advice类型(包含org.aopalliance.intercept.MethodInterceptor)的实例封装为默认的:DefaultPointcutAdvisor
回调AdvisedSupportListener.adviceChanged方法通知监听通知发生变更
回调自定义配置重写代理工厂配置:customizeProxyFactory
从代理工厂中获取代理并返回
第一次创建代理时回调org.springframework.aop.framework.AdvisedSupportListener#activated方法通知监听器当前创建代理配置(可再次重写配置)
创建aop代理:org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
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)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
基于创建的代理获取代理对象:org.springframework.aop.framework.AopProxy#getProxy(java.lang.ClassLoader)
JdkDynamicAopProxy、ObjenesisCglibAopProxy而且区别也就不再多说,相比普通的两种代理而言,aop代理在原代理基础上增加了切面需要注入的钩子方法来实现before,after,around三种类型的通知,或者MethodInterceptor.invoke的包装
来点直观的感受吧看下aop所生成的动态代理类是个啥样子
目标bean:MyService
/**
* @author 会灰翔的灰机
* @date 2020/9/6
*/
@Component
public class MyService {
public void sayHello(){
System.out.println("Hello !!!");
}
}
MyService切面:MyServiceAspect
/**
* @author 会灰翔的灰机
* @date 2020/9/6
*/
@Aspect
@Component
public class MyServiceAspect {
@Pointcut("execution(public * com.dianwoda.billing.settle.provider.MyService.*(..))")
public void pointcut() {
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = new Object();
System.out.println("MyServiceAspect start");
result = proceedingJoinPoint.proceed();
System.out.println("MyServiceAspect end");
return result;
}
}
代理类
MyService$$EnhancerBySpringCGLIB$$399fe137.class
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Advisor;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.TargetClassAware;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Dispatcher;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
public class MyService$$EnhancerBySpringCGLIB$$399fe137 extends MyService implements SpringProxy, Advised, Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private MethodInterceptor CGLIB$CALLBACK_1;
private NoOp CGLIB$CALLBACK_2;
private Dispatcher CGLIB$CALLBACK_3;
private Dispatcher CGLIB$CALLBACK_4;
private MethodInterceptor CGLIB$CALLBACK_5;
private MethodInterceptor CGLIB$CALLBACK_6;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$sayHello$0$Method;
private static final MethodProxy CGLIB$sayHello$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK257() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.dianwoda.billing.settle.provider.MyService$$EnhancerBySpringCGLIB$$399fe137");
Class var1;
CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("com.dianwoda.billing.settle.provider.MyService")).getDeclaredMethods())[0];
CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0");
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
}
final void CGLIB$sayHello$0() {
super.sayHello();
}
public final void sayHello() {
try {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
} else {
super.sayHello();
}
} catch (Error | RuntimeException var1) {
throw var1;
} catch (Throwable var2) {
throw new UndeclaredThrowableException(var2);
}
}
...
}