掘金 后端 ( ) • 2024-04-25 08:56

@[TOC]

系列文档索引

SpringAOP从入门到源码分析大全(一)熟悉动态代理 SpringAOP从入门到源码分析大全(二)熟悉ProxyFactory SpringAOP从入门到源码分析大全(三)ProxyFactory源码分析 SpringAOP从入门到源码分析大全(四)SpringAOP的源码分析 SpringAOP从入门到源码分析大全(五)手写一个编程式AOP

一、基于注解的AOP实现

日常我们开发中,通常都会使用基于注解的AOP实现。

此处就不多进行介绍了,相信咱们都会用。

但是要注意一点的,使用基于注解的AOP,必须要手动加上@EnableAspectJAutoProxy这个注解,开启注解AOP,并且要使用注解AOP的话,需要引入AOP的包。

二、基于编程实现的AOP

基于编程实现的AOP,相比较而言轻量的多。

1、自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}

2、定义拦截器

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * 这是一个Advice
 */
public class MyIntercepter implements MethodInterceptor {
    /**
     * 这相当于around通知
     */
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object result;
        try {
            System.out.println("前置通知");
            result = invocation.proceed();
            System.out.println("后置通知");
            return result;
        } catch (Exception e) {
            System.out.println("异常通知");
            throw e;
        } finally {
            System.out.println("最终通知");
        }
    }
}

3、定义Advisor

import org.aopalliance.aop.Advice;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.aop.support.StaticMethodMatcher;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.Assert;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 这是一个Advisor
 */
public class MyAdvisor extends AbstractPointcutAdvisor {

    // advice
    private final Advice advice;

    // 切点
    private final Pointcut pointcut;

    // 注解
    private final Class<? extends Annotation> annotation;

    public MyAdvisor(Advice advice, Class<? extends Annotation> annotation) {
        this.advice = advice;
        this.annotation = annotation;
        this.pointcut = buildPointcut();
    }
    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }

    @Override
    public Advice getAdvice() {
        return this.advice;
    }

    private Pointcut buildPointcut() {
        Pointcut cpc = new AnnotationMatchingPointcut(annotation, true);
        // 多个切点可以联合
        Pointcut mpc = new AnnotationMethodPoint(annotation);
        return new ComposablePointcut(cpc).union(mpc);
    }



    /**
     * In order to be compatible with the spring lower than 5.0
     */
    private static class AnnotationMethodPoint implements Pointcut {

        private final Class<? extends Annotation> annotationType;

        public AnnotationMethodPoint(Class<? extends Annotation> annotationType) {
            Assert.notNull(annotationType, "Annotation type must not be null");
            this.annotationType = annotationType;
        }

        @Override
        public ClassFilter getClassFilter() {
            return ClassFilter.TRUE;
        }

        @Override
        public MethodMatcher getMethodMatcher() {
            return new AnnotationMethodMatcher(annotationType);
        }

        private static class AnnotationMethodMatcher extends StaticMethodMatcher {
            private final Class<? extends Annotation> annotationType;

            public AnnotationMethodMatcher(Class<? extends Annotation> annotationType) {
                this.annotationType = annotationType;
            }

            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                if (matchesMethod(method)) {
                    return true;
                }
                // Proxy classes never have annotations on their redeclared methods.
                if (Proxy.isProxyClass(targetClass)) {
                    return false;
                }
                // The method may be on an interface, so let's check on the target class as well.
                Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
                return (specificMethod != method && matchesMethod(specificMethod));
            }

            private boolean matchesMethod(Method method) {
                return AnnotatedElementUtils.hasAnnotation(method, this.annotationType);
            }
        }
    }
}

4、配置类

import org.springframework.aop.Advisor;
import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyAOPConfig {


	// 注意,这里一般通过spring.factory文件进行配置,保证AbstractAutoProxyCreator不冲突
    @Bean
    @ConditionalOnMissingBean(AbstractAutoProxyCreator.class)
    public AbstractAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }

    @Bean
    public Advisor myAdvisor(){
        // 为Advisor加入拦截器与注解
        MyAdvisor myAdvisor = new MyAdvisor(new MyIntercepter(), MyAnnotation.class);
        return myAdvisor;
    }
}

5、测试

@GetMapping("/testa")
public String testa() {
    return "success";
}

@MyAnnotation
@GetMapping("/testb")
public String testb() {
    return "success";
}