Spring AOP
Aop原理与动态代理: https://mp.weixin.qq.com/s/PX7A3pUqQHhxkO3zJBWSJg
1.介绍
AOP是一种设计思想,称为面向切面编程,利用横切技术剖析对象内部,将业务之间共同调用的逻辑提取并封装为一个可复用的模块,这个模块被命名为切面(Aspect), 该模块减少系统中的重复代码,降低模块间的耦合度,可用于日志、权限认证、事务管理等。 SpringAOP思想的实现一般都是基于代理模式 ,在Java中采用JDK动态代理模式,但是JDK动态代理模式只能代理接口而不能代理类。 因此SpringAOP会在CGLIB、JDK动态代理之间进行切换。
1.1.专业术语
- 切面(Aspect),一个关注点的模块化,这个关注点可能会横切多个对象。也就是我们的aop的类
- 连接点(JoinPoint),当切面 对某个切入点实行切入时,这个切入点就叫做连接点。也就是controller中的方法
- 通知(Advice),指的是切面对于某个连接点产生的动作,其中一个切片可以包含多个通知。也就是方法前后进行aop增强
- 前置通知(Before):在某个连接点之前执行的通知,但这个通知不能阻断连接点之前的代码的执行
- 后置通知(After Finally):某个连接点退出时执行的通知,不管是正常返回还是异常退出
- 环绕通知(Around):包围一个连接点的通知,类似Web Servlet规范中Filter的doFilter()方法,在方法调用前后完成自定义的行为
- 返回后通知(After Returning):在某个连接点正常完成后执行的通知,不包括抛出异常的通知
- 异常通知(After Throwing):在方法异常导致退出时执行的通知
- 切入点(Pointcut),规定切面可以切目标的哪些位置,这些位置就是切入点。就是匹配规则,判断是否进行切入
- 目标对象(Target Object),要访问的对象
- 代理对象(Proxy),目标和切面织在一起形成的新对象。对于客户对象来说,目标对象和代理对象是一样的
- 织入(Weaving),动词 指的就是把目标和切面织在一起的动作
切面(Aspect)

织入(Weaving)

1.2.使用场景
- 日志处理
- 用户登录
- 权限(Authentication )
- 性能优化(Performance optimization)比如缓存:CacheInterceptor
- 事务(Transactions )比如:TransactionInterceptor
- 记录跟踪 优化 监控等(logging, tracing, profiling and monitoring)
- 调试(Debugging):比如: DebugInterceptor
- 懒加载(Lazy loading)
- 错误处理(Error handling)
- 资源池(Resource pooling)
- 异步(async),比如:AsyncExecutionInterceptor
aspectJ 相关的代理类: AspectJMethodBeforeAdvice、AspectJAroundAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice等
1.3.动态代理常见方案
常见的方案有 jdk proxy, cglib, AspectJ。spring中我们使用 jdk proxy 和 cglib。
- jdk proxy:jdk通过实现目标的接口,完成动态代理。生成的新class会加载到jvm中,特点是类名是:class com.sun.proxy.$Proxy0
- cglib:动态继承目标类,创建子类的方式,完成动态代理。生成的新class会加载到jvm中,特点是类名是:com.zx.RealSubjectImpl\(EnhancerByCGLIB\)36e2bca2
- AspectJ:通过字节码增强的方式,在编译的时候,将增强的代码编译到目标类中,完成动态代理。不会生成新的class。
2. 实现原理
在Spring IOC流程中,实例化对象后的初始化对象环节,通过调用BeanPostProcessor#后置处理器,判断该对象需要代理的功能,并将这些功能以 MethdInterceptor 的责任链的方式保存到这个代理对象中。

整体的步骤分为三步
- 配置aop
- 创建并注入代理对象
- 使用代理对象
2.1 配置aop
在spring boot项目中采用下面2种方式
- 方式1:使用 @EnableAspectJAutoProxy(proxyTargetClass = true)
- 方式2:配置 spring.aop.proxy-target-class=true
2.1.1. 我们的配置
会被 spring 解析为下面的注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
// 设置为true,表示代理对象的生成都是通过CGLIB方式
boolean proxyTargetClass() default false;
// 为了解决一些由于代理引发的切面失效问题,Spring AOP在Spring 4.3.1中引入了AopContext类来将处理类的引用存储在ThreadLocal中,通过AopContext可以快速获取当前类的代理类
//默认为关闭,如果声明为true,即可使用AopContext获取代理类
boolean exposeProxy() default false;
}
2.1.2. Import 注解导入 AspectJAutoProxyRegistrar
AspectJAutoProxyRegistrar 是 ImportBeanDefinitionRegistrar 的实现类,用于动态向IOC容器注册BeanDefinition。
作用:1. 注册后置处理器: AnnotationAwareAspectJAutoProxyCreator;2.配置aop的全局变量
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 向ioc容器中注册一个 AnnotationAwareAspectJAutoProxyCreator 后置处理器,它是用来生成代理对象的
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 处理注解的两个属性
AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
// 如果proxyTargetClass设置为true,则强制指定AutoProxyCreator使用CGLIB进行代理
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 如果exposeProxy设置为true,则开启exposeProxy特性
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
2.1.3. AnnotationAwareAspectJAutoProxyCreator 是 BeanPostProcessor 的实现类

后置处理方法。AbstractAutoProxyCreator#postProcessAfterInitialization
// 1.后置处理方法
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 从BeanFactory中找到bean的key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// earlyProxyReferences 保存创建中的代理对象,如果bean跟缓存的对象不一致或者不存在,就开始生成代理对象
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 生成代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
// 2.判断是否需要生成代理对象
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 判断是否需要生成代理对象
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 判断是否需要生成代理对象
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {// DO_NOT_PROXY = null
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 生成代理
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 3. 为当前bean实例生成代理对象
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (proxyFactory.isProxyTargetClass()) {
if (Proxy.isProxyClass(beanClass)) {
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
} else {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 所有aop的切面
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 设置代理工厂
// 1. 设置切面
proxyFactory.addAdvisors(advisors);
// 2. 设置目标对象
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 3.生成代码对象
return proxyFactory.getProxy(getProxyClassLoader());
}
2.2 创建并注入代理对象
2.2.1. 创建对象流程
AbstractAutowireCapableBeanFactory#doCreateBean。以下是简化的代码。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
// 1. 实例化对象
// 反射生成对象 beanName -> BeanWrapper
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
// 获得原始对象 BeanWrapper -> bean
Object bean = instanceWrapper.getWrappedInstance();
// 2.处理特殊的BeanPostProcessor,比如AutowiredAnnotationBeanPostProcessor,解析@Autowired的属性
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
// 3.将创建中的对象,先保存到三级缓存中。判断条件: 单例 && 允许循环引用 && 对象正在创建中
// 作用1:将单例对象缓存起来,目的是为了解决循环引用的问题(在允许循环引用的前提下,已经正在创建中的单例)
// 作用2: 调用 getEarlyBeanReference 方法,对需要进行aop的对象生成 代理对象,不需要的还是原始对象。并将其封装为ObjectFactory对象。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if(earlySingletonExposure){
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// exposedObject 表示对外暴露的对象
Object exposedObject = bean;
// 4.自动装配Bean实例的属性
populateBean(beanName, mbd, instanceWrapper);
// 5.初始化对象,即调用init(),并且根据需要生成AOP的代理对象(如果在上面第3步的时候已经生成过AOP代理,此步不再生成)
exposedObject = initializeBean(beanName, exposedObject, mbd);
// 如果对象保存在三级缓存的话,在完成对象创建后,对依赖的对象进行处理
if (earlySingletonExposure) {
// 获得当前对象,getSingleton 将三级缓存转移到二级缓存中
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// 如果bean创建的时候,有依赖的对象,这里需要判断所有依赖的对象是否也存在创建了
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// 有依赖没有创建就抛出异常
if (!actualDependentBeans.isEmpty()){
throw new BeanCurrentlyInCreationException(beanName);
}
}
}
}
return exposedObject;
}
/**
* 将刚刚创建的对象放入缓存
* 这里并不是直接将Bean放入缓存,而是包装成了ObjectFactory对象再放入
*/
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);// 加入三级缓存
this.earlySingletonObjects.remove(beanName); // 保护性的从二级缓存删除
this.registeredSingletons.add(beanName);
}
}
}
// 初始化bean
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
// 依次调用 BeanNameAware BeanClassLoaderAware BeanFactoryAware 的增强方法
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
// 调用BeanPostProcessor 的前置初始化方法
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 调用初始化方法
// 调用 InitializingBean#afterPropertiesSet方法
// 调用 xml配置的 init 方法
invokeInitMethods(beanName, wrappedBean, mbd);
// 调用BeanPostProcessor 的后置初始化方法
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
// 生成早期代理对象
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 找到后置处理器中的 SmartInstantiationAwareBeanPostProcessor (也就是 AnnotationAwareAspectJAutoProxyCreator )
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
// 其实调用的是AbstractAutoProxyCreator#getEarlyBeanReference方法去创建代理对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return null;
}
}
}
}
// 代理对象或者原始对象
return exposedObject;
}
2.2.2. 创建代理对象的位置
我们可以看到在初始化流程中有两次可以创建代理对象。 代码都在上面了
第一次是:将创建中的对象,先保存到三级缓存中,提前暴露出来。 AbstractAutowireCapableBeanFactory#getEarlyBeanReference 第二次是:initializeBean,调用 AbstractAutoProxyCreator#postProcessAfterInitialization
2.2.3. 创建代理对象
上面说的两次创建代理对象,都是通过 ProxyFactory 创建的。
public Object getProxy(@Nullable ClassLoader classLoader) {
//1.createAopProxy()判断生成代理的方式: cglib或jdk
//2.getProxy()生成代理对象
return createAopProxy().getProxy(classLoader);
}
/**
* 获取动态代理生成器
*/
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 如果没有用户接口的话,那就使用CGLIB生成动态代理
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 {
// 有接口就通过JDK的动态代理
return new JdkDynamicAopProxy(config);
}
}
2.2.4. 动态代理类
- JdkDynamicAopProxy,只有JdkDynamicAopProxy一个实现类
public Object getProxy(@Nullable ClassLoader classLoader) { Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // JDK的动态代理 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } - CglibAopProxy 就是cglib的动态代理类,内置了多个拦截器,用于代理不同类型的方法,比如 Static方法、Equals方法、hash方法等
public Object getProxy(@Nullable ClassLoader classLoader) { 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); } } validateClassIfNecessary(proxySuperClass, classLoader); // 配置CGLIB增强器 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.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(); } enhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); // 生成动态代理类和代理类的实例 return 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) { throw new AopConfigException("Unexpected AOP exception", ex); } }2.3 使用代理对象
JdkDynamicAopProxy 和 CglibAopProxy 生成的代理,都是调用 invoke 方法。 我们已经把需要代理对象的功能,组合成一个合集(List

2.4 自定义aop
自己实现日志记录。虽然我们使用的注解是 Aspect,但是他的实现还是spring aop,并不是AspectJ,主要还是为了方便
- 定义注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface LoggerManage { public String description(); } - 使用 @Aspect 注解定义我们的切面
@Aspect @Component @Slf4j public class LoggerAdvice { @Before("within(com.zx.web.aop..*) && @annotation(loggerManage)") public void addBeforeLogger(JoinPoint joinPoint, LoggerManage loggerManage) { log.info("执行 " + loggerManage.description() + " 开始"); log.info(joinPoint.getSignature().toString()); log.info(parseParames(joinPoint.getArgs())); } @AfterReturning("within(com.zx.web.aop..*) && @annotation(loggerManage)") public void addAfterReturningLogger(JoinPoint joinPoint, LoggerManage loggerManage) { log.info("执行 " + loggerManage.description() + " 结束"); } @AfterThrowing(pointcut = "within(com.zx.web.aop..*) && @annotation(loggerManage)", throwing = "ex") public void addAfterThrowingLogger(JoinPoint joinPoint, LoggerManage loggerManage, Exception ex) { log.error("执行 " + loggerManage.description() + " 异常", ex); } private String parseParames(Object[] parames) { if (null == parames || parames.length <= 0) { return ""; } StringBuffer param = new StringBuffer("传入参数[{}] "); for (Object obj : parames) { param.append(obj.toString()).append(" "); } return param.toString(); } } - 使用我们的注解
@RestController @RequestMapping("aop") public class AopController { @LoggerManage(description = "根据名字查询用户1") @RequestMapping("/d1")// http://127.0.0.1:8080/myApp/aop/d1?name=张三 public Response d1(UserQueryForm form) { String name = form.getName(); return new Response(new User(1L, name, 18)); } }
3.常见面试题
问题:何时使用JDK动态代理,何时使用CGLIB动态代理?
首先,只有bean用到aop的时候,才会使用到动态代理。所以对于普通的bean,spring只会帮我们实例化成原始的对象。
需要进行动态代理的时候:
- 目标对象实现了接口的话,默认使用JDK的动态代理
- 目标对象实现了接口的话,通过配置代理类型,强制使用 CGLib
- 目标对象没有实现接口,只能使用CGLib
- 在spring boot中,默认使用CGLib。https://segmentfault.com/a/1190000041034026
默认使用CGLib的原因是: 使用jdk动态代理,无法使用实现类注入属性。 因为JdkProxy实例化的是接口,所以通过类型找不到对象。CGLib 实例化的子类,通过类型可以找到对象。
// 接口
public interface IFun{
}
// 实现类
@Service
public class FunImpl implements IFun {
}
// 注入实现类, spring 项目中会因为找不到fun报错了。而spring boot项目中可以找到
@Service
public class Demo {
@Autowrite
private FunImpl fun;
}
问题:多重代理如何实现?
很多时候,我们对同一个方法可能需要多重代理。比如,事务、缓存、监控、日志等。
jdk proxy 是可以对代理对象进行二次代理,但是这样将导致我们的代理对象变得非常复杂,并且会创建出更多的class文件。
cglib 的设计是只能被代理一次。这和我们的需求不一致。
所以 spring 是怎么实现的呢? 责任链模式
spring 将我们的目标对象 封装为 MethodInvocation 对象(cglib是CglibMethodInvocation, jdk是ReflectiveMethodInvocation)
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
// 代理对象
protected final Object proxy;
// 目标原始对象
protected final Object target;
// 需要调用的方法
protected final Method method;
// 目标类型
private final Class<?> targetClass;
// 需要执行的功能责任链,比如事务的 TransactionInterceptor、CacheInterceptor....
protected final List<?> interceptorsAndDynamicMethodMatchers;
// 责任链执行的位置,从0开始依次执行
private int currentInterceptorIndex = -1;
public Object proceed() throws Throwable {
// 1. 依次执行责任链中的功能,当没有 interceptor 都执行完之后,我们就通过反射调用目标对象
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 2. 找到需要执行的 interceptor
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 3. 调用 interceptor
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) 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 {
// 正常的时候,都调用这个,MethodInterceptor 对象在执行自己的功能后,
// 都会调用 invocation.proceed(),继续执行责任链的 interceptor
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
//通过反射调用目标对象
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
}
责任链中的 interceptor 执行案例
// 1. 异步调用
public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport implements MethodInterceptor, Ordered {
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");
}
// 创建一个回调函数,里面调用 invocation.proceed(),并把任务提交到线程池
Callable<Object> 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());
}
}
// 2.事务
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 开启事务后,调用 invocation.proceed()
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
}
问题:动态代理方案的性能对比
实际中,高版本的JDK 动态代理的性能是高于CGLib
在aop方面,关于性能,我们其实可以得出一个排序:AspectJ > JDK > CGLib
- AspectJ的缺点是编译时直接改写class文件,没有扩展性
- CGLib 是扩展性最好的。
问题:aop 实现原理
使用jdk或者cglib的动态代理实现的
- 在spring IOC启动过程中,有两个地方会创建代理对象。1.创建过程中在保存到三级缓存的时候,提前创建暴露代理对象。2,init阶段,通过 beanPostProcesser#后置处理方法,创建代理对象。
- 通过 ProxyFactory 创建代理对象,根据配置以及目标类型 判断使用 jdk还是cglib 进行动态代理。
问题:springboot中的@Aspect 和 AspectJ是一回事吗?
Spring Boot 中最常用的 AOP 方式(通过 @Aspect 定义切面、@Before/@After 等注解定义通知),是 Spring 框架对 AspectJ 注解的 "借用"。 但底层实现依赖的是 Spring 自身的 动态代理机制,而非 AspectJ 框架的字节码增强。 因为:spring需要更加灵活的扩展性,以及热更新等特性。字节码增强是无法满足需求。
- 本文作者:zhangxue
- 本文链接:https://lucksnow1989.github.io/article/9.开源/spring/4.Spring AOP.html
- 版权声明:本文为本人原创文章,遵循 CC 4.0 BY-NC-SA版权协议,转载请附上原文出处链接和本声明。