ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

搞懂Spring AOP的前世今生

2021-09-26 15:01:54  阅读:196  来源: 互联网

标签:args return Spring AOP advisor new 搞懂 EchoService public


请添加图片描述

Spring AOP概述

在这里插入图片描述
方法调用优于方法执行 Spring目前只支持方法执行这一种类型的Joinpoint

织入

public interface EchoService {

    String echo(String message);
}
public class DefaultEchoService implements EchoService {

    @Override
    public String echo(String message) {
        return message;
    }
}

jdk动态代理

public class CostInvocationHandler implements InvocationHandler {

    private Object target;

    public CostInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = method.invoke(target, args);
        long cost = System.currentTimeMillis() - startTime;
        System.out.println("cost " + cost);
        return result;
    }
}
public static void main(String[] args) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    Object proxy = Proxy.newProxyInstance(classLoader,
            new Class[]{EchoService.class},
            new CostInvocationHandler(new DefaultEchoService()));
    EchoService echoService = (EchoService) proxy;
    // cost 0
    // hello world
    System.out.println(echoService.echo("hello world"));
}

cglib

public static void main(String[] args) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(DefaultEchoService.class);
    enhancer.setInterfaces(new Class[] {EchoService.class});
    enhancer.setCallback(new MethodInterceptor() {
        @Override
        public Object intercept(Object source, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            long startTime = System.currentTimeMillis();
            Object result = methodProxy.invokeSuper(source, args);
            long cost = System.currentTimeMillis() - startTime;
            System.out.println("cost " + cost);
            return result;
        }
    });
    EchoService echoService = (EchoService) enhancer.create();
    // cost 29
    // hello world
    System.out.println(echoService.echo("hello world"));
}

Spring AOP一代

Pointcut

public interface Pointcut {

	// 通过类过滤
	ClassFilter getClassFilter();

	// 通过方法过滤
	MethodMatcher getMethodMatcher();

	Pointcut TRUE = TruePointcut.INSTANCE;

}
public class EchoPointcut implements Pointcut {

    @Override
    public ClassFilter getClassFilter() {
        return new ClassFilter() {
            @Override
            public boolean matches(Class<?> clazz) {
                return EchoService.class.isAssignableFrom(clazz);
            }
        };
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return new MethodMatcher() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                return "echo".equals(method.getName()) &&
                        method.getParameterTypes().length == 1 &&
                        Objects.equals(String.class, method.getParameterTypes()[0]);
            }

            @Override
            public boolean isRuntime() {
                return false;
            }

            @Override
            public boolean matches(Method method, Class<?> targetClass, Object... args) {
                return false;
            }
        };
    }
}

在这里插入图片描述
Spring内部有很多内置的实现,一般情况下我们用内置的实现即可,不用自己定义

// 方法名为 echo 会被拦截
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedName("echo");

Advice

在这里插入图片描述

public interface SayName {

    String getName();
}
public class DefaultSayName implements SayName {

    @Override
    public String getName() {
        return "I am service";
    }
}
public static void main(String[] args) {
    SayName sayName = new DefaultSayName();
    EchoService echoService = new DefaultEchoService();
    DelegatingIntroductionInterceptor interceptor =
            new DelegatingIntroductionInterceptor(sayName);
    Advisor advisor = new DefaultIntroductionAdvisor(interceptor, SayName.class);
    ProxyFactory proxyFactory = new ProxyFactory(echoService);
    proxyFactory.addAdvisor(advisor);
    // hello world
    EchoService proxyService = (EchoService) proxyFactory.getProxy();
    System.out.println(proxyService.echo("hello world"));
    // I am service
    SayName proxySayName = (SayName) proxyFactory.getProxy();
    System.out.println(proxySayName.getName());
}
public static void main(String[] args) {
    JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
    pointcut.setPattern(".*put.*");
    DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
    advisor.setPointcut(pointcut);
    advisor.setAdvice(new MethodBeforeAdvice() {
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.printf("当前存放的key为 %s,值为 %s", args[0], args[1]);
        }
    });

    ProxyFactory proxyFactory = new ProxyFactory(new HashMap());
    proxyFactory.addAdvisor(advisor);
    Map<String, String> proxyMap = (Map<String, String>) proxyFactory.getProxy();
    // 当前存放的key为 a,值为 a
    proxyMap.put("a", "a");
}

Advisor

织入

Spring AOP的自动动态代理

请添加图片描述
手动配置

public class ProxyConfig {

    // 创建代理对象
    @Bean
    public EchoService echoService() {
        return new DefaultEchoService();
    }

    // 创建advice
    @Bean
    public CostMethodInterceptor costInterceptor() {
        return new CostMethodInterceptor();
    }

    // 使用pointcut和advice创建advisor
    @Bean
    public Advisor advisor() {
        NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
        advisor.setMappedName("echo");
        advisor.setAdvice(costInterceptor());
        return advisor;
    }

    // 创建代理对象
    @Bean("echoProxy")
    public ProxyFactoryBean proxyFactoryBean(EchoService echoService) {
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(echoService);
        proxyFactoryBean.setInterceptorNames("advisor");
        return proxyFactoryBean;
    }
}
public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProxyConfig.class);
    EchoService echoService = (EchoService) context.getBean("echoProxy");
    // cost 0
    // hello world
    System.out.println(echoService.echo("hello world"));
}

自动配置

public class AutoProxyConfig {

    // 创建代理对象
    @Bean
    public EchoService echoService() {
        return new DefaultEchoService();
    }

    // 创建advice
    @Bean
    public CostMethodInterceptor costInterceptor() {
        return new CostMethodInterceptor();
    }

    // 使用pointcut和advice创建advisor
    @Bean
    public Advisor advisor() {
        NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
        advisor.setMappedName("echo");
        advisor.setAdvice(costInterceptor());
        return advisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator autoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }
}
public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutoProxyConfig.class);
    EchoService echoService = context.getBean(EchoService.class);
    // cost 0
    // hello world
    System.out.println(echoService.echo("hello world"));
}

Spring AOP自动动态代理的实现方式

在这里插入图片描述
AbstractAutoProxyCreator重写了如下2个重要的方法
postProcessBeforeInstantiation(Bean实例化前阶段执行)
postProcessAfterInitialization(Bean初始化后阶段执行)

postProcessBeforeInstantiation
请添加图片描述
当用户自定义了TargetSource的实现时,会从TargetSourc
在这里插入图片描述
请添加图片描述

Spring AOP二代(集成了AspectJ)

激活Aspect

注解激活:@EnableAspectJAutoProxy
XML配置:<aop:aspectj-autoproxy>

Spring AOP用AspectJExpressionPointcut桥接了Aspect的筛选能力。其实Aspect有很多种类型的切点表达式,但是Spring AOP只支持如下10种,因为Aspect支持很多种类型的JoinPoint,但是Spring AOP只支持方法执行这一种JoinPoint,所以其余的表达式就没有必要了。
在这里插入图片描述

切点表达式

表达式类型解释
execution匹配方法表达式,首选方式
within限定类型
this代理对象是指定类型
target目标对象是指定类型
args匹配方法中的参数
@target目标对象有指定的注解
@args方法参数所属类型上有指定注解
@within
@annotation有指定注解的方法

execution

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
                throws-pattern?)

拦截Performance类的perform方法的切点表达式如下
在这里插入图片描述
放几个官方的Demo

// The execution of any public method:
execution(public * *(..))

// The execution of any method with a name that begins with set
execution(* set*(..))

// The execution of any method defined by the AccountService interface
execution(* com.xyz.service.AccountService.*(..))

// The execution of any method defined in the service package:
execution(* com.xyz.service.*.*(..))

within

this

target

args

@target

@args

@within

@annotation

参考博客

[1]https://zhuanlan.zhihu.com/p/104520344
大佬分析aop的实现
[2]https://blog.csdn.net/qq_20597727/article/details/84868035
[3]https://blog.csdn.net/qq_20597727/article/details/84800176
Spring AOP之Introduction
[4]https://www.cnblogs.com/lcngu/p/6346777.html
spring aop代理时机
[5]https://www.jianshu.com/p/ef3dc73bc3b1

标签:args,return,Spring,AOP,advisor,new,搞懂,EchoService,public
来源: https://blog.csdn.net/zzti_erlie/article/details/120379790

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有