欢迎访问shiker.tech

请允许在我们的网站上展示广告

您似乎使用了广告拦截器,请关闭广告拦截器。我们的网站依靠广告获取资金。

AOP如何进行功能增强
(last modified Apr 28, 2023, 12:34 AM )
by
侧边栏壁纸
  • 累计撰写 182 篇文章
  • 累计创建 64 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

AOP如何进行功能增强

橙序员
2023-04-28 / 0 评论 / 0 点赞 / 438 阅读 / 3,127 字 / 正在检测百度是否收录... 正在检测必应是否收录...
文章摘要(AI生成)

前置-动态代理示例代码如下:public interface UserService { void add(); void remove();}public class UserServiceImpl implements UserService{public void add(){Sy

前言-动态代理

示例代码如下:

public interface UserService {
    void add();

    void remove();
}

public class UserServiceImpl implements UserService{
	public void add(){
		System.out.println("添加用户");
	}

	public void remove(){
		System.out.println("删除用户");
	}
}

我们的代理对象实现为:

public class UserServiceProxy implements MethodInterceptor, InvocationHandler {

    //JDK动态代理
    private final UserService userService;

    public UserServiceProxy(UserService userService) {
        this.userService = userService;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK Start...");
        Object result = method.invoke(userService, args);
        System.out.println("JDK End");
        return result;
    }

    //Cglib动态代理
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib Start...");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("Cglib End");
        return result;
    }
}


public class Demo{
    public static void main(String[] args) {
		UserService userService = new UserServiceImpl();
		UserServiceProxy userServiceProxy = new UserServiceProxy(userService);
		//jdk代理对象调用
		ClassLoader classLoader = DemoTest.class.getClassLoader();
		userService = (UserService) Proxy.newProxyInstance(classLoader, new Class[]{UserService.class}, userServiceProxy);
		userService.add();
		//Cglib代理对象调用
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(UserServiceImpl.class);
		enhancer.setCallback(userServiceProxy);
		userService = (UserService)enhancer.create();
		userService.add();
	}
}

在使用JDK动态代理时,我们的代理目标是接口,而使用Cglib代理时,我们的代理目标是对象:

image-20230426223721762

代理模式的实践-AOP

spring AOP是通过动态代理拓展代理对象原有功能的集大成者,他通过代理链的方式层层叠加,完成我们对代理对象的层层拓展。

在我们通过spring IOC获取bean的时候,spring AOP通过实现BeanPostProcessor,返回对应的代理对象:

image-20230426224525936

实例化前置处理

而bean实例化前的前置处理中调用了postProcessBeforeInstantiation方法,该方法(位置在:AbstractAutoProxyCreator)主要做了以下流程:

  1. 如果该bean未被处理过:
    1. 指定的增强器中含有该bean,则返回null
    2. 如果bean是基础设施类或设置为不代理,则返回null
  2. 如果bean有定制的目标源:
    1. 获取bean对应的增强器
    2. 根据对应的增强器创建代理
    3. 返回代理对象
  3. 上述流程都没走到,则返回null

流程示意图如下:

image-20230426235241489

可以看到主要处理在bean是否有自定义的targetSource,如果有,则对自定义的targetSource创建代理。否则返回null走bean的创建流程。

对于自定义targetSource的使用,我们可以参考spring官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-targetsource

初始化后置处理

在bean初始化时,通过调用postProcessAfterInitialization方法,完成代理类的创建:

  1. 根据给定的bean生成代理对象的key
  2. 如果需要被代理,则获取指定的代理bean:
    1. 如果该bean已被处理过,则直接返回bean对象
    2. 如果指定的切面不含有该bean,则直接返回bean对象
    3. 如果bean是基础设施类或被设置不代理,则直接返回bean对象
    4. 获取bean对应的增强器
    5. 根据对应的增强器创建代理
    6. 返回代理对象

流程图如下所示:

image-20230426235304201

代理增强器

上述流程我们总结下来,代理对象的创建一共有两步:

  1. 通过getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null)方法获取作用域指定bean上的所有增强器
  2. 调用 createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))方法创建指定切面的代理增强器

增强器获取

切面获取主要流程为:

  1. 获取所有切面作为候选增强器(findCandidateAdvisors);
  2. 过滤出候选切面中的可用增强器(findAdvisorsThatCanApply
  3. 拓展可用增强器(对AspectJ的支持)
  4. @Ordered优先级对切面进行排序

在获取所有切面中,有两种实现一种是获取xml中的增强器,一种是获取注解中声明的增强器。我们常用的注解前置通知、环绕通知、后置通知等都是通过增强器获取工厂ReflectiveAspectJAdvisorFactory获取到的:

@Override
	@Nullable
	public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

		Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
		validate(candidateAspectClass);
		//获取候选增强方法的aspectJ注解
		AspectJAnnotation<?> aspectJAnnotation =
				AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
		if (aspectJAnnotation == null) {
			return null;
		}

		// 检查对应的类是否有相应注解
		if (!isAspect(candidateAspectClass)) {
			throw new AopConfigException("Advice must be declared inside an aspect type: " +
					"Offending method '" + candidateAdviceMethod + "' in class [" +
					candidateAspectClass.getName() + "]");
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Found AspectJ method: " + candidateAdviceMethod);
		}

		AbstractAspectJAdvice springAdvice;
		//判断注解类型,返回不同的AOP增强器
		switch (aspectJAnnotation.getAnnotationType()) {
			case AtPointcut:
				if (logger.isDebugEnabled()) {
					logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
				}
				return null;
			case AtAround:
				springAdvice = new AspectJAroundAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtBefore:
				springAdvice = new AspectJMethodBeforeAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfter:
				springAdvice = new AspectJAfterAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				break;
			case AtAfterReturning:
				springAdvice = new AspectJAfterReturningAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterReturningAnnotation.returning())) {
					springAdvice.setReturningName(afterReturningAnnotation.returning());
				}
				break;
			case AtAfterThrowing:
				springAdvice = new AspectJAfterThrowingAdvice(
						candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
				AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
				if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
					springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
				}
				break;
			default:
				throw new UnsupportedOperationException(
						"Unsupported advice type on method: " + candidateAdviceMethod);
		}

		// Now to configure the advice...
		springAdvice.setAspectName(aspectName);
		springAdvice.setDeclarationOrder(declarationOrder);
		String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
		if (argNames != null) {
			springAdvice.setArgumentNamesFromStringArray(argNames);
		}
		springAdvice.calculateArgumentBindings();

		return springAdvice;
	}

增强器概览

通过上述增强器获取的代码中,我们可以知道常用的通知和其实现类对应为:

通知类型 增强器
环绕通知 AspectJAroundAdvice
前置通知 AspectJMethodBeforeAdvice
后置通知 AspectJAfterAdvice
最终通知 AspectJAfterReturningAdvice
异常通知 AspectJAfterThrowingAdvice

增强器主要由两个作用:执行我们对代理方法的增强功能invokeAdviceMethod,以及调用下一个增强器proceed

上述5个通知中,我们依次看调用逻辑:

环绕通知:只执行增强方法,下一个增强器的调用不做实现

	@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;
		ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
		JoinPointMatch jpm = getJoinPointMatch(pmi);
		return invokeAdviceMethod(pjp, jpm, null, null);
	}

前置通知:先调用增强方法,再调用下一个增强器

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		return mi.proceed();
	}

	@Override
	public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
		invokeAdviceMethod(getJoinPointMatch(), null, null);
	}

后置通知:不管调用下一个增强器的过程是否出现异常,也要执行增强方法

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

最终通知:先调用下一个增强器获取返回值,再调用增强方法

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		Object retVal = mi.proceed();
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}

	@Override
	public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
		if (shouldInvokeOnReturnValueOf(method, returnValue)) {
			invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
		}
	}

异常通知:当调用下一个增强器的过程出现异常时,执行增强方法

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		}
		catch (Throwable ex) {
			if (shouldInvokeOnThrowing(ex)) {
				invokeAdviceMethod(getJoinPointMatch(), null, ex);
			}
			throw ex;
		}
	}

上述我们增强器的完整调用,即是使用我们的责任链模式进行实现:

image-20230427230544768

具体的实现逻辑在ReflectiveMethodInvocation.proceed()这个方法中,该方法采用递归方式,流程图示如下:

image-20230427234040098

创建代理

代理对象的第二步,即调用 createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))方法创建代理对象,接下来我们看代理是如何完成创建的。

代理工厂

AOP通过代理工厂DefaultAopProxyFactory中的createAopProxy方法完成Aop代理的创建:

  1. 如果使用优化的代理配置或者目标类为接口代理或者仅指定了SpringProxy接口
    1. 如果代理对象为接口,则使用JDK动态代理
    2. 否则使用CGLIB代理
  2. 除了上述条件外的其他条件则使用JDK动态代理
	@Override
	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);
		}
	}

动态代理类

JDK动态代理和CGLIB动态代理的实现跟我们自己实现时一样,只需要按照对应的规范进行填充即可。

JDK动态代理

例如JdkDynamicAopProxy,本身只有两个核心方法,分别是获取代理对象getProxy和代理方法执行invoke.

获取代理对象的代码与我们自己实现时相同,也是调用JDK的Proxy.newProxyInstance进行代理对象的创建:

	@Override
	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);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

JdkDynamicAopProxy本身则实现了InvocationHandler接口,在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 {
			//省略:前置条件判断的流程

			Object retVal;

			if (this.advised.exposeProxy) {
				// 暂存当前代理,使调用可用。
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// 尽可能晚,以尽量减少我们“拥有”目标的时间,以防它来自池。
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// 获取此方法的拦截链。
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// 检查我们是否有任何advice。 如果为空直接反射调用代理方法,并避免创建 MethodInvocation。
			if (chain.isEmpty()) {
				// 我们可以跳过创建 MethodInvocation:直接调用目标方法 
                // 请注意,最终调用者必须是 InvokerInterceptor,因此我们知道它除了对目标进行反射操作外什么都不做,没有热交换或花哨的代理。
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// 我们需要创建一个方法调用...
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// 通过拦截器链进入连接点。
				retVal = invocation.proceed();
			}

			// 返回值按返回类型进行转换
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// 特殊情况:它返回“this”并且该方法的返回类型是类型兼容的。 
                // 请注意,如果代理对象在另一个返回的对象中设置了对自身的引用,那么将无能为力,需要抛出异常。
				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()) {
				// 必须来自 TargetSource。
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// 恢复旧代理。
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

CGLIB动态代理

CGLIB代理同样通过实现MethodInterceptor接口创建代理。

其代理对象的获取主要在我们设置Enhancer的回调上,其回调的获取如下:

  1. 如果非静态方法且拦截器链未冻结:

    1. AOP拦截器的获取

    2. 代理方法拦截器的获取

  2. 如果是静态方法且拦截器链被冻结,则可以进行一些调用的优化

	private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
		// 设置用于优化选择的参数...
		boolean exposeProxy = this.advised.isExposeProxy();
		boolean isFrozen = this.advised.isFrozen();
		boolean isStatic = this.advised.getTargetSource().isStatic();

		// 选择一个“aop”拦截器(用于 AOP 调用)。).
		Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

		// 选择“直达目标”拦截器(用于未经过增强器但可以返回的调用)。可能需要公开代理。
		Callback targetInterceptor;
		if (exposeProxy) {
			targetInterceptor = (isStatic ?
					new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
					new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
		}
		else {
			targetInterceptor = (isStatic ?
					new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
					new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
		}

		// 选择一个“直接到目标”调度程序(用于对无法返回此的静态目标的未经增强器的调用)。
		Callback targetDispatcher = (isStatic ?
				new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());

		Callback[] mainCallbacks = new Callback[] {
				aopInterceptor,  // 正常增强器
				targetInterceptor,  // 调用目标而不考虑增强器,如果优化
				new SerializableNoOp(),  // 没有覆盖映射到此的方法
				targetDispatcher, this.advisedDispatcher,
				new EqualsInterceptor(this.advised),
				new HashCodeInterceptor(this.advised)
		};

		Callback[] callbacks;

		// 如果目标是静态的并且增强器链被冻结,那么我们可以通过使用该方法的固定链将 AOP 调用直接发送到目标来进行一些优化。
		if (isStatic && isFrozen) {
            //。。。省略此处代码
		}
		else {
			callbacks = mainCallbacks;
		}
		return callbacks;
	}

而在AOP拦截器中,我们可以看到跟我们自己调用CGLIB时相同的代码

		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 {
				// 与AOP中invoke相同的代码,不再重复
				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 {
				// 与AOP中invoke相同的代码,不再重复
			}
		}
0

评论区