zoukankan      html  css  js  c++  java
  • 扩展Spring切面

    概述

    Spring的切面(Spring动态代理)在Spring中应用十分广泛,例如还有事务管理,重试等等。网上介绍SpringAop源码很多,这里假设你对SpringAop有基本的了解。如果你认为Spring代理类会创建多重代理,那说明你真的没了解。

    需求背景

    假设我现在想提供一个jar包,这个jar包会拦截制定注解方法,并做一些记录。这里要分析一下具体需求

    拦截的注解是在方法上

    如果注解是放在方法上,那么我们完全可以使用SpringAop的方式,通过自己定义一个注解,并对该注解进行拦截即可。这个不是本篇文章的重点,拦截制定注解的很简单。

    拦截的注解是在类上

    如果我们需要拦截的注解是类上,这里首先介绍第一个接口

    Advisor

    public interface Advisor {
        Advice getAdvice();
        boolean isPerInstance();
    }

    这个接口简单来说就是持有一个通知(Advice),但是一般不直接使用这个接口,因为这个对通知没有一个有效的过滤(当然如果你想对所有方法都进行拦截),所以一般是使用PointcutAdvisor,

    public interface PointcutAdvisor extends Advisor {
        Pointcut getPointcut();
    }

    这个接口就可以通过Pointcut做一些限制。为什么呢? 直接看AopUtils#findAdvisorsThatCanApply方法,这个方法就是从所有Advisor接口实现Bean选择对某个Class有效。

    public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
        if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
        }
        List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
        for (Advisor candidate : candidateAdvisors) {
            if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
                eligibleAdvisors.add(candidate);
            }
        }
        boolean hasIntroductions = !eligibleAdvisors.isEmpty();
        for (Advisor candidate : candidateAdvisors) {
            if (candidate instanceof IntroductionAdvisor) {
                // already processed
                continue;
            }
            //!!!有兴趣的可以重点看一下重点看这里实现,就不大段贴代码了
            if (canApply(candidate, clazz, hasIntroductions)) {
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
        }

    好了,我们知道了,要想让我们的自定义的切面生效,首先,

    第一步,创建一个Advisor
    public class MyAdvisor implements PointcutAdvisor {
    
        //这个是Spring提供的一个简单的通过注解来获取切点类
        AnnotationMatchingPointcut annotationMatchingPointcut = new AnnotationMatchingPointcut(MyAop.class);
        //这个是我们自己实现的继承于Advice,
        MyAdvice myAdvice =new MyAdvice();
    
        @Override
        public Pointcut getPointcut() {
            return annotationMatchingPointcut;
        }
    
        @Override
        public Advice getAdvice() {
            return myAdvice;
        }
    
        @Override
        public boolean isPerInstance() {
            return false;
        }
        
        //简单起见,就直接使用MethodInterceptor
        class MyAdvice implements MethodInterceptor{
    
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("haha");
                return invocation.proceed();
            }
        }
    第二步,定义一个开关注解,让我们的自定义切面生效

    创建一个开关注解,就是一个套路,先创建一个开关注解,@import我们一个Bean注册类

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Import(MyImporter.class)
    public @interface EnableMyAop {
    }

    在Bean注册类中把我们的MyAdvisor注册进去吧

    public class MyImporter implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            register(registry,MyAdvisor.class);
        }
    
        private void register(BeanDefinitionRegistry registry, Class<?> aopBeanFactoryPostClass) {
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
            rootBeanDefinition.setBeanClass(aopBeanFactoryPostClass);
            registry.registerBeanDefinition(aopBeanFactoryPostClass.getSimpleName(),rootBeanDefinition);
        }
    }

     至此,只要使用MyAop注解的类,在调用他的任何方法的时候(类内部调用不算),都会进入到我们的切面中。

    小结

    本篇文章是简单看了一下Spring Aop源码后,尝试自己进行扩展,因此可能不是最优的方法。不过希望能起到抛砖迎玉作用,在其基础上可以做很多有很意思的事情。如果有兴趣可以进一步研究spring自己的Advice,Pointcut的实现类。

  • 相关阅读:
    php 时间段查询排序分组
    php 导出word
    关于UVM driver的幕后
    三次握手的必要性
    如何卸载360天擎之火绒与天擎相爱相杀
    【虚拟机】VirtualBox设置共享文件夹
    【数据结构与算法】打开转盘锁:使用图的广度优先遍历实现
    【Python】PDF文档导出指定章节为TXT
    【数据结构与算法】不同路径 III:使用哈密尔顿路径算法实现
    【Java】可比较泛型建数组传递报强转类型错误解决方案
  • 原文地址:https://www.cnblogs.com/lizo/p/7759469.html
Copyright © 2011-2022 走看看