美文网首页
SpringAOP源码解析过程

SpringAOP源码解析过程

作者: 笔记本一号 | 来源:发表于2021-10-08 12:13 被阅读0次

    spring的AOP基于JDK的动态代理和cglib实现,默认代理对象是某个接口的实现就会使用JDK动态代理,否则使用cglib,使用cglib时要注意,代理类不能是final类型,否则无法进行代理

    AOP示例

     @Aspect
     @Component
     public class SystemLogAspect {
     
         //注入Service用于把日志保存数据库  
         @Resource
         private SystemLogService systemLogService;  
         
         private  static  final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class);  
         
         //Controller层切点  
         @Pointcut("execution (* com.gcx.controller..*.*(..))")  
         public  void controllerAspect() {  
         }  
         
         /** 
          * 前置通知 用于拦截Controller层记录用户的操作 
          * 
          * @param joinPoint 切点 
          */ 
         @Before("controllerAspect()")
         public void doBefore(JoinPoint joinPoint) {
             System.out.println("==========执行controller前置通知===============");
             if(logger.isInfoEnabled()){
                 logger.info("before " + joinPoint);
             }
         }    
         
         //配置controller环绕通知,使用在方法aspect()上注册的切入点
           @Around("controllerAspect()")
           public void around(JoinPoint joinPoint){
               System.out.println("==========开始执行controller环绕通知===============");
               long start = System.currentTimeMillis();
               try {
                   ((ProceedingJoinPoint) joinPoint).proceed();
                   long end = System.currentTimeMillis();
                   if(logger.isInfoEnabled()){
                       logger.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms!");
                   }
                   System.out.println("==========结束执行controller环绕通知===============");
               } catch (Throwable e) {
                   long end = System.currentTimeMillis();
                   if(logger.isInfoEnabled()){
                       logger.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage());
                   }
               }
           }
         
         /** 
          * 后置通知 用于拦截Controller层记录用户的操作 
          * 
          * @param joinPoint 切点 
          */  
         @After("controllerAspect()")  
         public  void after(JoinPoint joinPoint) {  
             User user = new User();
             user.setId(1);
             user.setName("张三");
             String ip = "127.0.0.1";
              try {  
                 String targetName = joinPoint.getTarget().getClass().getName();  
                 String methodName = joinPoint.getSignature().getName();  
                 Object[] arguments = joinPoint.getArgs();  
                 Class targetClass = Class.forName(targetName);  
                 Method[] methods = targetClass.getMethods();
                 String operationType = "";
                 String operationName = "";
                  for (Method method : methods) {  
                      if (method.getName().equals(methodName)) {  
                         Class[] clazzs = method.getParameterTypes();  
                          if (clazzs.length == arguments.length) {  
                              operationType = method.getAnnotation(Log.class).operationType();
                              operationName = method.getAnnotation(Log.class).operationName();
                              break;  
                         }  
                     }  
                 }
                 //*========控制台输出=========*//  
                 System.out.println("=====controller后置通知开始=====");  
                 System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);  
                 System.out.println("方法描述:" + operationName);  
                 System.out.println("请求人:" + user.getName());  
                 System.out.println("请求IP:" + ip);  
                 //*========数据库日志=========*//  
                 SystemLog log = new SystemLog();  
                 log.setId(UUID.randomUUID().toString());
                 log.setDescription(operationName);  
                 log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);  
                 log.setLogType((long)0);  
                 log.setRequestIp(ip);  
                 log.setExceptioncode( null);  
                 log.setExceptionDetail( null);  
                 log.setParams( null);  
                 log.setCreateBy(user.getName());  
                 log.setCreateDate(new Date());  
                 //保存数据库  
                 systemLogService.insert(log);  
                 System.out.println("=====controller后置通知结束=====");  
             }  catch (Exception e) {  
                 //记录本地异常日志  
                 logger.error("==后置通知异常==");  
                 logger.error("异常信息:{}", e.getMessage());  
             }  
         } 
         
         //配置后置返回通知,使用在方法aspect()上注册的切入点
           @AfterReturning("controllerAspect()")
           public void afterReturn(JoinPoint joinPoint){
               System.out.println("=====执行controller后置返回通知=====");  
                   if(logger.isInfoEnabled()){
                       logger.info("afterReturn " + joinPoint);
                   }
           }
         
         /** 
          * 异常通知 用于拦截记录异常日志 
          * 
          * @param joinPoint 
          * @param e 
          */  
          @AfterThrowing(pointcut = "controllerAspect()", throwing="e")  
          public  void doAfterThrowing(JoinPoint joinPoint, Throwable e) {  
             //获取用户请求方法的参数并序列化为JSON格式字符串  
             User user = new User();
             user.setId(1);
             user.setName("张三");
             String ip = "127.0.0.1";
             
             String params = "";  
              if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {  
                  for ( int i = 0; i < joinPoint.getArgs().length; i++) {  
                     params += JsonUtil.getJsonStr(joinPoint.getArgs()[i]) + ";";  
                 }  
             }  
              try {  
                  
                  String targetName = joinPoint.getTarget().getClass().getName();  
                  String methodName = joinPoint.getSignature().getName();  
                  Object[] arguments = joinPoint.getArgs();  
                  Class targetClass = Class.forName(targetName);  
                  Method[] methods = targetClass.getMethods();
                  String operationType = "";
                  String operationName = "";
                   for (Method method : methods) {  
                       if (method.getName().equals(methodName)) {  
                          Class[] clazzs = method.getParameterTypes();  
                           if (clazzs.length == arguments.length) {  
                               operationType = method.getAnnotation(Log.class).operationType();
                               operationName = method.getAnnotation(Log.class).operationName();
                               break;  
                          }  
                      }  
                  }
                  /*========控制台输出=========*/  
                 System.out.println("=====异常通知开始=====");  
                 System.out.println("异常代码:" + e.getClass().getName());  
                 System.out.println("异常信息:" + e.getMessage());  
                 System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);  
                 System.out.println("方法描述:" + operationName);  
                 System.out.println("请求人:" + user.getName());  
                 System.out.println("请求IP:" + ip);  
                 System.out.println("请求参数:" + params);  
                    /*==========数据库日志=========*/  
                 SystemLog log = new SystemLog();
                 log.setId(UUID.randomUUID().toString());
                 log.setDescription(operationName);  
                 log.setExceptioncode(e.getClass().getName());  
                 log.setLogType((long)1);  
                 log.setExceptionDetail(e.getMessage());  
                 log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));  
                 log.setParams(params);  
                 log.setCreateBy(user.getName());  
                 log.setCreateDate(new Date());  
                 log.setRequestIp(ip);  
                 //保存数据库  
                 systemLogService.insert(log);  
                 System.out.println("=====异常通知结束=====");  
             }  catch (Exception ex) {  
                 //记录本地异常日志  
                 logger.error("==异常通知异常==");  
                 logger.error("异常信息:{}", ex.getMessage());  
             }  
              /*==========记录本地异常日志==========*/  
             logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params);  
         }  
     }
    

    @Aspect就是所谓的切面也叫做Advisor的织入,@Pointcut就是切点

    AOP源码分析

    涉及到几个关键的类AspectJAutoProxyBeanDefinitionParser,AnnotationAwareAspectJAutoProxyCreator,AbstractAutoProxyCreator,BeanPostProcessor。其中AnnotationAwareAspectJAutoProxyCreator是AOP的核心,AspectJAutoProxyBeanDefinitionParser主要是对AnnotationAwareAspectJAutoProxyCreator完成注册,AnnotationAwareAspectJAutoProxyCreator负责将获取到的aop的bean解析成出各种属性信息最后生成代理

    • AspectJAutoProxyBeanDefinitionParser的parse方法中调用registerAspectJAnnotationAutoProxyCreatorIfNecessary来向容器注册AnnotationAwareAspectJAutoProxyCreator,其中传入的element参数携带了AOP的xml节点资源,用于后面spring加载AnnotationAwareAspectJAutoProxyCreator生成代理代理使用
    @Override
        @Nullable
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
            extendBeanDefinition(element, parserContext);
            return null;
        }
    //AopNamespaceUtils类的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法
    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                ParserContext parserContext, Element sourceElement) {
            BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                    parserContext.getRegistry(), parserContext.extractSource(sourceElement));
            useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
            registerComponentIfNecessary(beanDefinition, parserContext);
        }
    //AopConfigUtils类的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法
    @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");
    
            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;
            }
    //cls就是AnnotationAwareAspectJAutoProxyCreator.class,将和element节点资源一起封装为beanDefinition 注册入容器中
            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;
        }
    
    接下来是解析AnnotationAwareAspectJAutoProxyCreator创建AOP的过程
    先看看AnnotationAwareAspectJAutoProxyCreator的继承图

    AnnotationAwareAspectJAutoProxyCreator继承了BeanPostProcessor,AOP的创建是在spring加载AnnotationAwareAspectJAutoProxyCreator这个bean的时候,在这个bean实例化后调用其父类BeanPostProcessor的postProcessAfterInitialization方法,这个方法已经由父类AbstractAutoProxyCreator实现了

    @Override
        public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
            if (bean != null) {
                Object cacheKey = getCacheKey(bean.getClass(), beanName);
                if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                    return wrapIfNecessary(bean, beanName, cacheKey);
                }
            }
            return bean;
        }
    

    AnnotationAwareAspectJAutoProxyCreator可以根据@Pointcut自动代理匹配的bean。AnnotationAwareAspectJAutoProxyCreator是实现了BeanPostProcessor,当spring初实例化完这个bean后会调用后置处理器的后置处理方法postProcessAfterInitialization,这个方法是其实是调用的AnnotationAwareAspectJAutoProxyCreator的父类AbstractAutoProxyCreator中的实现,其中关键的方法是wrapIfNecessary,wrapIfNecessary主要是获取切面的增强方法,加载标注有aop注解的bean,并将这些bean的增强方法包装成Advisor,Advisor中包装了增强方法的各类信息、增强器和注解上信息和通配符等,例如:" @AfterReturning("controllerAspect()")、execution (* com.gcx.controller...(..))",根据注解生成和初始化增强器,每一个增强方法都会包装成一个Advisor,然后调用createProxy方法根据注解的通配符信息创建生成相应的代理,根据bean的类型选择jdk的动态代理还GCLIB

    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;
            }
            if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
    
            // 获取切面所有的增强方法,并将其相关信息封装为Advisor类
            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;
        }
    

    AbstractAdvisorAutoProxyCreator类的getAdvicesAndAdvisorsForBean方法主要是获取aop注解的bean的增强方法,生成Advisor包装类,包装增强器和AOP注解上的通配符信息等

    @Override
        @Nullable
        protected Object[] getAdvicesAndAdvisorsForBean(
                Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    //查找aop的注解的bean,获取增强方法的消息,封装成Advisor
            List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
            if (advisors.isEmpty()) {
                return DO_NOT_PROXY;
            }
            return advisors.toArray();
        }
    

    查找aop的注解的bean,获取增强方法的消息,封装成Advisor,主要的过程就是从容器中获取所有的beanName,然后遍历,将有aop注解的类提取出来进行处理,然后获取这些bean的增强方法信息,然后将其封装到Advisor中

    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
            List<Advisor> candidateAdvisors = findCandidateAdvisors();
            List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
            extendAdvisors(eligibleAdvisors);
            if (!eligibleAdvisors.isEmpty()) {
                eligibleAdvisors = sortAdvisors(eligibleAdvisors);
            }
            return eligibleAdvisors;
        }
        protected List<Advisor> findCandidateAdvisors() {
            Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
            return this.advisorRetrievalHelper.findAdvisorBeans();
        }
    
    public List<Advisor> findAdvisorBeans() {
            String[] advisorNames = this.cachedAdvisorBeanNames;
            if (advisorNames == null) {
                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)) {
                    if (this.beanFactory.isCurrentlyInCreation(name)) {
                        ..........................
                    }
                    else {
                        try {
                            advisors.add(this.beanFactory.getBean(name, Advisor.class));
                        }
                    ...........................
                    }
                }
            }
            return advisors;
        }
    

    获取切面所有的增强方法,并将其相关信息封装为Advisor类后调用AbstractAutoProxyCreator类的createProxy方法,使用proxyFactory.getProxy创建代理。对于代理类的创建及处理,spring将其委托给了ProxyFactory,buildAdvisors方法将前面封装的一大堆Advisor进一步封装成config参数并加入ProxyFactory中同时将拦截器一并封装为Advisor也加入到ProxyFactory中,这些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()) {
              if (Proxy.isProxyClass(beanClass)) {
                    for (Class<?> ifc : beanClass.getInterfaces()) {
                        proxyFactory.addInterface(ifc);
                    }
                }
            }
            else {
                if (shouldProxyTargetClass(beanClass, beanName)) {
                    proxyFactory.setProxyTargetClass(true);
                }
                else {
                    evaluateProxyInterfaces(beanClass, proxyFactory);
                }
            }
    
            Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    //将所有封装好的advisors 置入ProxyFactory中
            proxyFactory.addAdvisors(advisors);
            proxyFactory.setTargetSource(targetSource);
            customizeProxyFactory(proxyFactory);
    
            proxyFactory.setFrozen(this.freezeProxy);
            if (advisorsPreFiltered()) {
                proxyFactory.setPreFiltered(true);
            }
            ClassLoader classLoader = getProxyClassLoader();
            if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
                classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
            }
            return proxyFactory.getProxy(classLoader);
        }
    
    public Object getProxy(@Nullable ClassLoader classLoader) {
            return createAopProxy().getProxy(classLoader);
        }
    
    protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                activate();
            }
            return getAopProxyFactory().createAopProxy(this);
        }
    

    在DefaultAopProxyFactory类中判断需要代理的bean是否有接口,有接口的则使用jdk的动态代理,否则使用cglib创建代理,创建代理是根据之前封装的消息进行创建的

    //在DefaultAopProxyFactory类中判断需要代理的bean是否有接口,有接口的则使用jdk的动态代理,否则使用cglib创建代理
    @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.");
                }
                if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                    return new JdkDynamicAopProxy(config);
                }
                return new ObjenesisCglibAopProxy(config);
            }
            else {
                return new JdkDynamicAopProxy(config);
            }
        }
    
    
    public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
            Assert.notNull(config, "AdvisedSupport must not be null");
            if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
                throw new AopConfigException("No advisors and no TargetSource specified");
            }
            this.advised = config;
            this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
            findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
        }
    

    by the way

    在上次分析的IOC中说到bean存入三级缓存会调用一个匿名函数,这个匿名函数也是AbstractAutoProxyCreator类的,会触发wrapIfNecessary方法,也会产生代理

    @Override
        public Object getEarlyBeanReference(Object bean, String beanName) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            this.earlyProxyReferences.put(cacheKey, bean);
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    

    相关文章

      网友评论

          本文标题:SpringAOP源码解析过程

          本文链接:https://www.haomeiwen.com/subject/ooxenltx.html