当前位置: 首页 > article >正文

Spring系列 AOP实现过程

文章目录

  • AOP的核心概念
  • 使用方法
  • 实现原理
    • EnableAspectJAutoProxy
    • AnnotationAwareAspectJAutoProxyCreator 代理创建过程
      • TargetSource和TargetSourceCreator
      • wrapIfNecessary
      • getAdvicesAndAdvisorsForBean
        • findCandidateAdvisors
        • findAdvisorsThatCanApply
      • createProxy
        • ProxyFactory 代理工厂
        • AopProxy
          • AopProxy的创建过程
    • @AspectJ注解处理
    • 代理调用过程
      • CGlib代理
        • CglibMethodInvocation
        • 调用 Advice
        • 调用 JoinPoint
    • AdvisedSupport
    • SpringProxy
    • MethodProxy


AOP的核心概念

首先要大概了解AOP的核心概念和术语

  1. Aspect:切面,由一系列切点、增强和引入组成的模块对象,可定义优先级,从而影响增强和引入的执行顺序。
  2. Join point:接入点,程序执行期的一个点,例如方法执行、类初始化、异常处理。 在Spring AOP中,接入点始终表示方法执行。
  3. Advice:增强,切面在特定接入点的执行动作,包括 “around,” “before” and "after"等多种类型。包含Spring在内的许多AOP框架,通常会使用拦截器来实现增强,围绕着接入点维护着一个拦截器链。
  4. Pointcut:切点,用来匹配特定接入点的谓词(表达式),增强将会与切点表达式标识的切点产生关联,并运行在任何切点匹配到的接入点上。通过切点表达式匹配接入点是AOP的核心,Spring默认使用AspectJ的切点表达式。
  5. Introduction:引入,为某个类型声明额外的方法和字段。Spring AOP允许你引入任何接口以及它的默认实现到被增强对象上。
  6. Target object:目标对象,被一个或多个切面增强的对象。也叫作被增强对象。既然Spring AOP使用运行时代理(runtime proxies),那么目标对象就总是代理对象。
  7. AOP proxy:AOP代理,为了实现切面功能一个代理对象会被AOP创建出来。Spring中AOP代理的默认有接口就使用基于接口的JDK动态代理,没有就使用基于类的CGLIB动态代理。可以通过设置proxy-target-class=true,完全使用CGLIB动态代理。
  8. Weaving:织入,将一个或多个切面与目标对象关联在一起创建一个被增强对象的过程。织入能发生在编译时(例如使用AspectJ编译器),加载时(load time)或运行时(runtime) 。Spring AOP默认就是运行时织入,可以通过枚举AdviceMode来设置。

使用方法

https://docs.spring.io/spring-framework/reference/core/aop/ataspectj/advice.html#aop-ataspectj-advice-ordering

可以只用@Before,@After,@AfterThrowing,@AfterReturn,@Around等注解,并设置切点表达式,例如:

@Before("execution(* org.example..*..UserService.*(..))")
public void beforeUserServiceOperation(JoinPoint pjp) throws Throwable {

}

也可以@Pointcut和@Around等联合使用

@Pointcut("execution(* org.example..*..UserService.*(..))")
private void pointcut() {
}

@Around("pointcut()")
public Object aroundUserServiceOperation(ProceedingJoinPoint pjp) throws Throwable {  
    // ... 方法执行前操作
    // 执行切点方法
    Object retVal = pjp.proceed();
	// 方法执行后置操作
    return retVal;
}

实现原理

本文源码基于spring-aop-5.3.31版本,测试代码如下:

@Aspect
@Component
public class UserAspect {

    @Pointcut("execution(* org.example..*..UserService.*(..))")
    private void pointcut() {
    }

    @Around("pointcut()")
    public Object aroundUserServiceOperation(ProceedingJoinPoint pjp) throws Throwable {  //2
        long start = System.currentTimeMillis();
        Object retVal = pjp.proceed();
        long duration = System.currentTimeMillis() - start;
        System.out.printf("time for pointcut method is %d seconds%n", duration);
        return retVal;
    }
}

@Service
public class UserService {

    public String login(String username, String password) {
        return String.format(" %s login with password: %s\n", username, password);
    }
}

@RestController
@RequestMapping(value = "/api/user")
public class UserController {

    @Resource
    UserService userService;

    @PostMapping("/login")
    public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
        return userService.login(username, password);
    }
}

启动类

@SpringBootApplication
@EnableAspectJAutoProxy
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

EnableAspectJAutoProxy

使用 @EnableAspectJAutoProxy 注解开启对@AspectJ的支持,如果使用XML配置,则配置<aop:aspectj-autoproxy/>即可

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * 指定代理方式是CGLIB还是基于接口的动态代理
	 */
	boolean proxyTargetClass() default false;

	/**
	 * 是否暴露代理对象,暴露可以通过AopContext拿到
	 */
	boolean exposeProxy() default false;
}

导入了这个AspectJAutoProxyRegistrar,实际上是一个ImportBeanDefinitionRegistrar实现。我们知道,@Import + ImportBeanDefinitionRegistrar结合使用的效果就是向容器中注入一些Bean。

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * 注册, 配置AspectJ代理
	 */
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// 这一步就是所有的注册过程
		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);
			}
		}
	}
}

通过AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);可以看到

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
	return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
		BeanDefinitionRegistry registry, @Nullable Object source) {

	return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
		Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	// AUTO_PROXY_CREATOR_BEAN_NAME
	// org.springframework.aop.config.internalAutoProxyCreator
	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
		if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
			int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
			int requiredPriority = findPriorityForClass(cls);
			if (currentPriority < requiredPriority) {
				apcDefinition.setBeanClassName(cls.getName());
			}
		}
		return null;
	}

	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;
}

从上面的内容来看,AspectJAutoProxyRegistrar的工作就是注册一个AspectJAutoProxyCreator的东西,默认是org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator,如果容器中已经有了一个名称为org.springframework.aop.config.internalAutoProxyCreator的Bean,那么会优先使用它,否则使用AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator 代理创建过程

AspectJAwareAdvisorAutoProxyCreator的子类,负责处理所有AspectJ注解,以及所有Spring的Advisor。所有AspectJ注解的类都会被自动识别
在这里插入图片描述
主要关注点,它是一个BeanPostProcessor

在这里插入图片描述
最终org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator找到了Bean的后置处理逻辑

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
	Object cacheKey = getCacheKey(beanClass, beanName);

	if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
		if (this.advisedBeans.containsKey(cacheKey)) {
			return null;
		}
		if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return null;
		}
	}

	// Create proxy here if we have a custom TargetSource.
	// Suppresses unnecessary default instantiation of the target bean:
	// The TargetSource will handle target instances in a custom fashion.
	TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
	if (targetSource != null) {
		if (StringUtils.hasLength(beanName)) {
			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;
}

/**
 * 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(@Nullable Object bean, String beanName) {
	// bean 就是被代理对象
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

TargetSource和TargetSourceCreator

TargetSource用于获取AOP调用的当前目标对象,如果没有Advice结束拦截器链的调用工程,则将通过反射调用该目标对象的方法。
如果TargetSource是静态的,它将始终返回相同的目标,从而允许在AOP框架中进行优化。动态目标源可以支持池化、热交换等。
应用程序开发人员通常不需要直接使用TargetSource,这是一个AOP框架接口

如果存在TargetSourceCreator,则直接在postProcessBeforeInstantiation方法里就创建代理对象,也就是说不会创建目标对象的Bean

在这里插入图片描述

wrapIfNecessary

如果没有TargetSource和TargetSourceCreator,那么会通过wrapIfNecessary在postProcessAfterInitialization之后进行代理对象的创建,也就是说,被代理对象和代理对象都会放入容器中

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;
	}
	// 下面四个类不会被代理:Advice, Pointcut, Advisor, AopInfrastructureBean
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// Create proxy if we have advice.
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		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;
}

getAdvicesAndAdvisorsForBean

对于指定的Bean,获取可用的切面,如果没有切面,则无需生成代理

org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator实现了这个方法

@Override
protected Object[] getAdvicesAndAdvisorsForBean(
		Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
	if (advisors.isEmpty()) {
		return DO_NOT_PROXY;
	}
	return advisors.toArray();
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
	// 获取所有的Advisor
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
	// 找到与beanClass相关联的那些Advisor
	List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
	extendAdvisors(eligibleAdvisors);
	if (!eligibleAdvisors.isEmpty()) {
		eligibleAdvisors = sortAdvisors(eligibleAdvisors);
	}
	return eligibleAdvisors;
}
findCandidateAdvisors
/**
 * Find all candidate Advisors to use in auto-proxying.
 * @return the List of candidate Advisors
 */
protected List<Advisor> findCandidateAdvisors() {
	Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
	return this.advisorRetrievalHelper.findAdvisorBeans();
}

AnnotationAwareAspectJAutoProxyCreator中继承了此方法

@Override
protected List<Advisor> findCandidateAdvisors() {
	// Add all the Spring advisors found according to superclass rules.
	List<Advisor> advisors = super.findCandidateAdvisors();
	// Build Advisors for all AspectJ aspects in the bean factory.
	if (this.aspectJAdvisorsBuilder != null) {
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
	}
	return advisors;
}

切面的查找实际上委托给了BeanFactoryAdvisorRetrievalHelper和BeanFactoryAspectJAdvisorsBuilder这两个类来完成的

BeanFactoryAdvisorRetrievalHelper用于从BeanFactory中获取org.springframework.aop.Advisor接口的实现类,核心逻辑如下(省略了部分不重要的代码)

public List<Advisor> findAdvisorBeans() {
	// Determine list of advisor bean names, if not cached already.
	String[] advisorNames = this.cachedAdvisorBeanNames;
	if (advisorNames == null) {
		// 获取所有Advisor类型的Bean名称,同时缓存到 this.cachedAdvisorBeanNames
		advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this.beanFactory, Advisor.class, true, false);
		this.cachedAdvisorBeanNames = advisorNames;
	}
	if (advisorNames.length == 0) {
		return new ArrayList<>();
	}
	List<Advisor> advisors = new ArrayList<>();
	for (String name : advisorNames) {
		if (isEligibleBean(name)) {
			// 忽略正在创建的Bean
			if (this.beanFactory.isCurrentlyInCreation(name)) {
				// 记录日志
			} else {
				// ....
				advisors.add(this.beanFactory.getBean(name, Advisor.class));
				// ....
			}
		}
	}
	return advisors;
}

BeanFactoryAspectJAdvisorsBuilder

在项目启动的过程中,项目中的所有切面会被 AnnotationAwareAspectJAutoProxyCreator 解析,它会找到切面中的每一个通知以及通知对应的切点,拿这二者构建一个新的对象,这个对象就是 Advisor。最后将所有解析得到的增强器注入到容器中。

BeanFactoryAspectJAdvisorsBuilder这个类的操作是获取所有Advisor

创建代理

在这里插入图片描述

findAdvisorsThatCanApply

此方法的作用是找到目标类可用的Advisor列表

protected List<Advisor> findAdvisorsThatCanApply(
		List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
	ProxyCreationContext.setCurrentProxiedBeanName(beanName);
	try {
		return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
	} finally {
		ProxyCreationContext.setCurrentProxiedBeanName(null);
	}
}

判断Advisor和目标类是否匹配

  1. IntroductionAdvisor:使用ClassFilter类进行匹配
  2. PointcutAdvisor:使用Pointcut来进行匹配
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
	if (advisor instanceof IntroductionAdvisor) {
		return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
	}
	else if (advisor instanceof PointcutAdvisor) {
		PointcutAdvisor pca = (PointcutAdvisor) advisor;
		return canApply(pca.getPointcut(), targetClass, hasIntroductions);
	}
	else {
		// It doesn't have a pointcut so we assume it applies.
		return true;
	}
}

在这里插入图片描述

PointCut类型的

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
	Assert.notNull(pc, "Pointcut must not be null");
	if (!pc.getClassFilter().matches(targetClass)) {
		return false;
	}

	MethodMatcher methodMatcher = pc.getMethodMatcher();
	if (methodMatcher == MethodMatcher.TRUE) {
		// No need to iterate the methods if we're matching any method anyway...
		return true;
	}
	// AspectJExpressionPointcut
	IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
	if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
		introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
	}

	Set<Class<?>> classes = new LinkedHashSet<>();
	if (!Proxy.isProxyClass(targetClass)) {
		classes.add(ClassUtils.getUserClass(targetClass));
	}
	classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

	for (Class<?> clazz : classes) {
		Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
		for (Method method : methods) {
			if (introductionAwareMethodMatcher != null ?
					introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
					methodMatcher.matches(method, targetClass)) {
				return true;
			}
		}
	}
	return false;
}

AspectJExpressionPointcut是一个MethodMatcher的实现,代表了使用AspectJ注解@Pointcut定义的一个切点,比如:

@Pointcut("execution(* org.example..*..UserService.*(..))")
private void pointcut() {
}

createProxy

找到Advisor之后下一步就是创建代理对象
在这里插入图片描述

创建代理对象的过程如下所示

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);
	if (proxyFactory.isProxyTargetClass()) {
		// Explicit handling of JDK proxy targets and lambdas 
		// (for introduction advice scenarios)
		if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
			// Must allow for introductions; 
			// can't just set interfaces to the proxy's interfaces only.
			for (Class<?> ifc : beanClass.getInterfaces()) {
				proxyFactory.addInterface(ifc);
			}
		}
	} else {
		// No proxyTargetClass flag enforced, let's apply our default checks...
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		} else {
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}

	// 构建代理类的Advisor集合:包括定义的和通用的比如(equals、hashcode等)
	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	proxyFactory.addAdvisors(advisors);
	proxyFactory.setTargetSource(targetSource);
	// 这是protected空方法,留给子类扩展
	customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}

	// 类加载器,调用的是org.springframework.util.ClassUtils#getDefaultClassLoader
	ClassLoader classLoader = getProxyClassLoader();
	if (classLoader instanceof SmartClassLoader 
	&& classLoader != beanClass.getClassLoader()) {
		classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
	}
	return proxyFactory.getProxy(classLoader);
}
ProxyFactory 代理工厂

后续会在代理执行过程中将其作为AdvisedSupport使用

在这里插入图片描述
实现方式如下:

public Object getProxy(@Nullable ClassLoader classLoader) {
	return createAopProxy().getProxy(classLoader);
}
AopProxy

org.springframework.aop.framework.AopProxy 封装了代理对象的实现细节

public interface AopProxy {
	/**
	 * 创建代理对象
	 */
	Object getProxy();
	/**
	 * 使用指定的类加载器,创建代理对象
	 */
	Object getProxy(@Nullable ClassLoader classLoader);
}

基于不同的代理方式,有不同的实现类,如下图所示:

在这里插入图片描述

AopProxy的创建过程

AopProxy的创建过程也是基于工厂模式创建的,对应的工厂类型是org.springframework.aop.framework.AopProxyFactory

protected final synchronized AopProxy createAopProxy() {
	if (!this.active) {
		activate();
	}
	return getAopProxyFactory().createAopProxy(this);
}

AopProxyFactory只有一个默认实现org.springframework.aop.framework.DefaultAopProxyFactory

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	// config: 即ProxyFactory
	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (!NativeDetector.inNativeImage() &&
				(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.");
			}
			// 如果是接口,则使用JDK动态代理
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			// CGlib动态代理
			return new ObjenesisCglibAopProxy(config);
		} else {
			return new JdkDynamicAopProxy(config);
		}
	}

	// AdvisedSupport是否只指定了org.springframework.aop.SpringProxy这一个代理接口
	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
		Class<?>[] ifcs = config.getProxiedInterfaces();
		return (ifcs.length == 0 || (ifcs.length == 1 
				&& SpringProxy.class.isAssignableFrom(ifcs[0])));
	}
}

@AspectJ注解处理

@Aspect注解表示一个AspectJ配置类,里面可以配置切点和切面,以及二者之间的关系

注意:@Aspect在Spring中没有专门定义一个组件去扫描它,因此需要其他额外的配置将@AspectJ配置的那个类放入Spring容器

  1. 加@Component注解

  2. 使用@ComponentScan注解

  3. 如果使用XML配置,可以使用context:component-scan,还需要配置<context:include-filter/> ,其中context:component-scan这个标签是扫描@Component、@Controller、@Service等这些注解的类,则把这些类注册为bean。它不扫描@Aspect注解的。所以需要在子标签添加 <context:include-filter type="annotation"expression=“org.aspectj.lang.annotation.Aspect”/>

代理调用过程

如果想跟踪Advice是如何执行的,以及代理方法调用到Advice执行,再到被代理类方法执行的过程,该怎么办呢?
在这里插入图片描述
仅需要进行简单的设置,即可输出cglib以及jdk动态代理产生的class文件,然后工具查看生成的动态代理类

// 输出cglib动态代理产生的类
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
// 输出jdk动态代理产生的类
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

CGlib代理

基于CGlib的代理类命名方式为:被代理类类名 + $$EnhancerBySpringCGLIB$$ + 8个随机字符,例如:UserService$$EnhancerBySpringCGLIB$$efcfcced

在这里插入图片描述
使用jd-gui工具查看反编译的字节码,如下图所示
在这里插入图片描述
可以在里面找到login方法,这个方法就是代理类的login方法
在这里插入图片描述
下面将login方法调用的相关内容拿出来看看

import java.lang.reflect.Method;
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 UserService$$EnhancerBySpringCGLIB$$efcfcced 
		extends UserService implements SpringProxy, Advised, Factory {

	private MethodInterceptor CGLIB$CALLBACK_0;
	private static final MethodProxy CGLIB$login$0$Proxy;
	private static final Method CGLIB$login$0$Method;
	
	public final String login(String paramString1, String paramString2) {
	  if (this.CGLIB$CALLBACK_0 == null)
	    CGLIB$BIND_CALLBACKS(this); 
	  return (this.CGLIB$CALLBACK_0 != null) ? 
	  	(String)this.CGLIB$CALLBACK_0.intercept(this, 
	  			CGLIB$login$0$Method, new Object[] { 
	  				paramString1, paramString2 }, CGLIB$login$0$Proxy)
	   : super.login(paramString1, paramString2);
	}
}

代理方法实际调用了CGLIB$CALLBACK_0的intercept方法,而这个CGLIB$CALLBACK_0变量是MethodInterceptor类型,MethodInterceptor是spring-core提供的一个接口(org.springframework.cglib.proxy.MethodInterceptor)

public interface MethodInterceptor extends Callback {
	/**
	 * 1. obj:被代理的目标对象,即UserService
	 * 2. method:被调用的方法,即login方法
	 * 3. args:方法的参数
     * 4. proxy:用于调用目标方法的 MethodProxy 对象
	 **/
    Object intercept(Object obj, Method method, Object[] args, 
    							MethodProxy proxy) throws Throwable;
}

现在只知道CGLIB$CALLBACK_0是一个MethodInterceptor,但到底是哪个实现呢,我们可以通过Debug查看,如下图所示,可以看到它的实际类型是org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor,这是一个内部类,用于通用的AOP调用逻辑

在这里插入图片描述

下面是其intercept方法内容

@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
	Object oldProxy = null;
	boolean setProxyContext = false;
	Object target = null;
	// this.advised -> ProxyFactory
	TargetSource targetSource = this.advised.getTargetSource();
	try {
		if (this.advised.exposeProxy) {
			// 暴露代理对象到AopContext中,就是一个ThreadLocal
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}
		// 被代理对象
		target = targetSource.getTarget();
		// 被代理对象的Class类型
		Class<?> targetClass = (target != null ? target.getClass() : null);
		// 获取拦截器链,即@Around, @Before等修饰的方法,一般称之为 Advice
		List<Object> chain = 
			this.advised.getInterceptorsAndDynamicInterceptionAdvice(
									method, targetClass);
		Object retVal;
		// 检查是否只有一个InvokerInterceptor,没有任何advice
		// 如果没有Advice,那么只需要进行反射调用即可
		if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
			// 不创建MethodInvocation
			Object[] argsToUse = 
				AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			// 通过MethodProxy直接执行目标方法,简单的反射调用
			retVal = invokeMethod(target, method, argsToUse, methodProxy);
		} else {
			// 创建一个MethodInvocation对象,并调用proceed方法
			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) {
			AopContext.setCurrentProxy(oldProxy); // 执行完毕,重置上一个代理对象
		}
	}
}

实际上没有一个名称为InvokerInterceptor的类

org.aopalliance.intercept.MethodInterceptor

CglibMethodInvocation
@Override
@Nullable
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) {
		// Evaluate dynamic method matcher here: static part will already have
		// been evaluated and found to match.
		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 {
			// 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);
	}
}
调用 Advice

在这里插入图片描述

org.springframework.aop.interceptor.ExposeInvocationInterceptor是MethodInterceptor

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
	MethodInvocation oldInvocation = invocation.get();
	invocation.set(mi);
	try {
		return mi.proceed(); // 会重新进入CglibMethodInvocation#proceed方法
	} finally {
		invocation.set(oldInvocation);
	}
}

org.springframework.aop.aspectj.AspectJAroundAdvice,它也是一个MethodInterceptor

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
	if (!(mi instanceof ProxyMethodInvocation)) {
		throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
	}
	ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
	// 简单的new了一个MethodInvocationProceedingJoinPoint类型的ProceedingJoinPoint
	ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
	JoinPointMatch jpm = getJoinPointMatch(pmi);
	return invokeAdviceMethod(pjp, jpm, null, null);
}

ProxyMethodInvocation的实现有2种

在这里插入图片描述

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
	Object[] actualArgs = args;
	if (this.aspectJAdviceMethod.getParameterCount() == 0) {
		actualArgs = null;
	}
	try {
		ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
		// 反射调用
		// aspectJAdviceMethod 即为@Around注解标记的那个方法
		// actualArgs 为 ProceedingJoinPoint
		return this.aspectJAdviceMethod.invoke(
				this.aspectInstanceFactory.getAspectInstance(), actualArgs);
	} catch (XxxException ex) {
		// ... 省略异常处理
	}
}
调用 JoinPoint

JoinPoint调用,即切点方法执行

public Object proceed() throws Throwable {
	return this.methodInvocation.invocableClone().proceed();
}

@Override
public MethodInvocation invocableClone() {
	Object[] cloneArguments = this.arguments;
	if (this.arguments.length > 0) {
		// Build an independent copy of the arguments array.
		cloneArguments = this.arguments.clone();
	}
	return invocableClone(cloneArguments);
}

@Override
public MethodInvocation invocableClone(Object... arguments) {
	if (this.userAttributes == null) {
		this.userAttributes = new HashMap<>();
	}
	// Create the MethodInvocation clone.
	try {
		ReflectiveMethodInvocation clone = (ReflectiveMethodInvocation) clone();
		clone.arguments = arguments;
		return clone;
	} catch (CloneNotSupportedException ex) { ... }
}

这是最后一次进入ReflectiveMethodInvocation#proceed方法,直接执行切点方法,其实就是一次简单的反射调用被代理对象的被代理方法。比如代理对象调用了 login 方法,那这里就是调用共被代理对象的 login 方法

在这里插入图片描述

AdvisedSupport

保存了与某个被代理对象的所有Advice,Advisor信息
继承体系如下

在这里插入图片描述

随代理对象的创建而创建,并进行初始化,后续在代理方法调用的过程种进行使用

在这里插入图片描述

SpringProxy

org.springframework.aop.SpringProxy是一个标记接口,无任何方法需实现,Spring中所有代理类都要实现此接口

MethodProxy

org.springframework.cglib.proxy.MethodProxy


http://www.kler.cn/a/328501.html

相关文章:

  • 【Apache Paimon】-- 2 -- 核心特性 (0.9.0)
  • Figma中文网:UI设计师的新资源宝库
  • 15-大模型 RAG 经验篇
  • 一文了解 inductive bias(归纳偏好)
  • golang开源框架:go开源验证框架validator
  • springboot第82集:消息队列kafka,kafka-map
  • 【PostgreSQL】入门篇——PostgreSQL 的历史、特点和优势
  • 开卷可扩展自动驾驶(OpenDriveLab)
  • express,MySQL 实现登录接口,如果用户未注册直接注册
  • 【Python】Uvicorn:Python 异步 ASGI 服务器详解
  • vue3 环境配置vue-i8n国际化
  • Linux高级IO之poll与epoll
  • 基于Springboot+微信小程序 的高校社团管理小程序(含源码+数据库+lw)
  • TypeScript 算法手册【插入排序】
  • 搜维尔科技:SenseGlove DK1触觉反馈手套,远程操作机器人任务,保证你工作时的安全
  • js无法获取执行的线程号(Thread ID)
  • 【Golang】关于Go语言中的包
  • 超分服务的分量保存
  • Gateway和VirtualService
  • 代码随想录算法训练营day44
  • PostgreSQL 数据库语法学习:深入理解 `JOIN` 操作
  • 【AI基础】pytorch lightning 基础学习
  • 【JavaEE初阶】深入解析死锁的产生和避免以及内存不可见问题
  • 药品识别与分类系统源码分享
  • 【Transformer】长距离依赖
  • 微信小程序中的 `<block>` 元素:高效渲染与结构清晰的利器