spring aop的实现_ssh框架工作原理及流程

spring aop的实现_ssh框架工作原理及流程Spring的AOP实现原理,酝酿了一些日子,写博客之前信心不是很足,所以重新阅读了一边AOP的实现核心代码,而且又从网上找了一些SpringAop剖析的例子,但是发现挂羊头买狗肉的太多,标题高大上,内容却大部分都是比较浅显的一些介绍,可能也是由于比较少人阅读这部分的核心代码逻辑把,然后写这部分介绍的人估计也是少之又少,不过说实话,SpringAop的核心原理实现介绍确实不太好写,里面涉及的类

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

Spring的AOP实现原理,酝酿了一些日子,写博客之前信心不是很足,所以重新阅读了一边AOP的实现核心代码,而且又从网上找了一些Spring Aop剖析的例子,但是发现挂羊头买狗肉的太多,标题高大上,内容却大部分都是比较浅显的一些介绍,可能也是由于比较少人阅读这部分的核心代码逻辑把,然后写这部分介绍的人估计也是少之又少,不过说实话,Spring Aop的核心原理实现介绍确实不太好写,里面涉及的类之间的调用还是蛮多的,关系图画的太细的画也很难画,而且最重要的一点就是,如果对AOP的概念以及spring的xml的解析,标签的解析,注解实现,还有java的代理,这些知识没有好好的理解的话也不可能对AOP的实现详细逻辑有一个好的理解。所以的话,建议是把这些前置知识都大概了解了,再来看这个AOP的实现,或者去阅读源代码,那样的话学习 起来会容易的多。

学习源代码的过程比较枯燥,尤其是spring比较严谨,调用层次比较多,没有画时序图的话可能真的被绕晕,所以建议学的时候还是画画时序图,然后跟着debug模式流程走一遍。

首先我们来热热身吧,先看看AOP的简介,待会再进入主题,

AOP简介

概念

切面(Aspect) :官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”。
连接点(Joinpoint) :程序执行过程中的某一行为。
通知(Advice) :“切面”对于某个“连接点”所产生的动作。
切入点(Pointcut) :匹配连接点的断言,在AOP中通知和一个切入点表达式关联。
目标对象(Target Object) :被一个或者多个切面所通知的对象。
AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。

通知(Advice)类型
前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext中在<aop:aspect>里面使用<aop:before>元素进行声明。
后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext中在<aop:aspect>里面使用<aop:after>元素进行声明。
返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext中在<aop:aspect>里面使用<after-returning>元素进行声明。
环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext中在<aop:aspect>里面使用<aop:around>元素进行声明。
抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。 ApplicationContext中在<aop:aspect>里面使用<aop:after-throwing>元素进行声明。

切入点表达式 :如execution(* com.spring.service.*.*(..))

特点

1、降低模块之间的耦合度

2、使系统容易扩展

3、更好的代码复用。

动态AOP使用示例

由于在之前的博客,已经介绍过spring源码剖析(五)利用AOP实现自定义Spring注解 里面有介绍到AOP 的简单使用,相信大家要看这个AOP的原理的也对AOP的使用比较熟悉了,所以在这里也不再重复展示了。

动态AOP自定义标签

我之前的博客中有说到,如何自定义Spring标签的,以及自定义Spring标签的大概解析流程,其实这里的AOP的标签的定义也和之前的逻辑类似,先上时序图把:

时序图

spring aop的实现_ssh框架工作原理及流程

流程说明

1)AOP标签的定义解析刘彻骨肯定是从NamespaceHandlerSupport的实现类开始解析的,这个实现类就是AopNamespaceHandler。至于为什么会是从NamespaceHandlerSupport的实现类开始解析的,这个的话我想读者可以去在回去看看Spring自定义标签的解析流程,里面说的比较详细。

2)要启用AOP,我们一般会在Spring里面配置<aop:aspectj-autoproxy/>  ,所以在配置文件中在遇到aspectj-autoproxy标签的时候我们会采用AspectJAutoProxyBeanDefinitionParser解析器

3)进入AspectJAutoProxyBeanDefinitionParser解析器后,调用AspectJAutoProxyBeanDefinitionParser已覆盖BeanDefinitionParser的parser方法,然后parser方法把请求转交给了AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary去处理

4)进入AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法后,先调用AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,里面在转发调用给registerOrEscalateApcAsRequired,注册或者升级AnnotationAwareAspectJAutoProxyCreator类。对于AOP的实现,基本是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根据@point注解定义的切点来代理相匹配的bean。

5)AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法处理完成之后,接下来会调用useClassProxyingIfNecessary() 处理proxy-target-class以及expose-proxy属性。如果将proxy-target-class设置为true的话,那么会强制使用CGLIB代理,否则使用jdk动态代理,expose-proxy属性是为了解决有时候目标对象内部的自我调用无法实现切面增强。

6)最后的调用registerComponentIfNecessary 方法,注册组建并且通知便于监听器做进一步处理。

创建AOP代理

上面说到AOP的核心逻辑是在AnnotationAwareAspectJAutoProxyCreator类里面实现,那么我们先来看看这个类的层次关系

spring aop的实现_ssh框架工作原理及流程

我们可以看到这个类实现了BeanPostProcessor接口,那就意味着这个类在spring加载实例化前会调用postProcessAfterInitialization方法,对于AOP的逻辑也是由此开始的。

时序图

spring aop的实现_ssh框架工作原理及流程

流程说明

1)spring 容器启动,每个bean的实例化之前都会先经过AbstractAutoProxyCreator类的postProcessAfterInitialization()这个方法,然后接下来是调用wrapIfNecessary方法。

[java] 
view plain  
copy

  1. /** 
  2.  * Create a proxy with the configured interceptors if the bean is 
  3.  * identified as one to proxy by the subclass. 
  4.  * @see #getAdvicesAndAdvisorsForBean 
  5.  */  
  6. public Object <strong>postProcessAfterInitialization</strong>(Object bean, String beanName) throws BeansException {  
  7.     if (bean != null) {  
  8.         Object cacheKey = getCacheKey(bean.getClass(), beanName);  
  9.         if (!this.earlyProxyReferences.containsKey(cacheKey)) {  
  10.             return wrapIfNecessary(bean, beanName, cacheKey);  
  11.         }  
  12.     }  
  13.     return bean;  
  14. }  

2)进入wrapIfNecessary方法后,我们直接看重点实现逻辑的方法getAdvicesAndAdvisorsForBean,这个方法会提取当前bean 的所有增强方法,然后获取到适合的当前bean 的增强方法,然后对增强方法进行排序,最后返回。

[java] 
view plain  
copy

  1. /** 
  2.      * Wrap the given bean if necessary, i.e. if it is eligible for being proxied. 
  3.      * @param bean the raw bean instance 
  4.      * @param beanName the name of the bean 
  5.      * @param cacheKey the cache key for metadata access 
  6.      * @return a proxy wrapping the bean, or the raw bean instance as-is 
  7.      */  
  8.     protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {  
  9.         if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) {  
  10.             return bean;  
  11.         }  
  12.         if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {  
  13.             return bean;  
  14.         }  
  15.         if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {  
  16.             this.advisedBeans.put(cacheKey, Boolean.FALSE);  
  17.             return bean;  
  18.         }  
  19.   
  20.         // Create proxy if we have advice.    
  21.         Object[] specificInterceptors = <strong>getAdvicesAndAdvisorsForBean</strong>(bean.getClass(), beanName, null);  
  22.         if (specificInterceptors != DO_NOT_PROXY) {  
  23.             this.advisedBeans.put(cacheKey, Boolean.TRUE);  
  24.             Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));  
  25.             this.proxyTypes.put(cacheKey, proxy.getClass());  
  26.             return proxy;  
  27.         }  
  28.   
  29.         this.advisedBeans.put(cacheKey, Boolean.FALSE);  
  30.         return bean;  
  31.     }  

3)获取到当前bean的增强方法后,便调用createProxy方法,创建代理。先创建代理工厂proxyFactory,然后获取当前bean 的增强器advisors,把当前获取到的增强器添加到代理工厂proxyFactory,然后设置当前的代理工的代理目标对象为当前bean,最后根据配置创建JDK的动态代理工厂,或者CGLIB的动态代理工厂,然后返回proxyFactory

[java] 
view plain  
copy

  1. /** 
  2.      * Create an AOP proxy for the given bean. 
  3.      * @param beanClass the class of the bean 
  4.      * @param beanName the name of the bean 
  5.      * @param specificInterceptors the set of interceptors that is 
  6.      * specific to this bean (may be empty, but not null) 
  7.      * @param targetSource the TargetSource for the proxy, 
  8.      * already pre-configured to access the bean 
  9.      * @return the AOP proxy for the bean 
  10.      * @see #buildAdvisors 
  11.      */  
  12.     protected Object createProxy(  
  13.             Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {  
  14.   
  15.         ProxyFactory proxyFactory = new ProxyFactory();  
  16.         // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.  
  17.         proxyFactory.copyFrom(this);  
  18.   
  19.         if (!shouldProxyTargetClass(beanClass, beanName)) {  
  20.             // Must allow for introductions; can’t just set interfaces to  
  21.             // the target’s interfaces only.  
  22.             Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);  
  23.             for (Class<?> targetInterface : targetInterfaces) {  
  24.                 proxyFactory.addInterface(targetInterface);  
  25.             }  
  26.         }  
  27.   
  28.         Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);  
  29.         for (Advisor advisor : advisors) {  
  30.             proxyFactory.addAdvisor(advisor);  
  31.         }  
  32.   
  33.         proxyFactory.<strong>setTargetSource</strong>(targetSource);  
  34.         customizeProxyFactory(proxyFactory);  
  35.   
  36.         proxyFactory.setFrozen(this.freezeProxy);  
  37.         if (advisorsPreFiltered()) {  
  38.             proxyFactory.setPreFiltered(true);  
  39.         }  
  40.   
  41.         return proxyFactory.getProxy(this.proxyClassLoader);  
  42.     }  


AOP动态代理执行

关于AOP的动态代理执行,有两种主要的方式JDK的动态代理和CGLIB的动态代理,如果对这两种代理不是很熟悉的话,建议先去看看我之前写的一篇博客
 java代理(静态代理和jdk动态代理以及cglib代理) 里面有介绍这两种代理的使用和实现方式。

接下来,我们先来看看AOP动态代理的实现选择方式,先上核心实现代码:

[java] 
view plain  
copy

  1. public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {  
  2.     if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {  
  3.         Class targetClass = config.getTargetClass();  
  4.         if (targetClass == null) {  
  5.             throw new AopConfigException(“TargetSource cannot determine target class: “ +  
  6.                     “Either an interface or a target is required for proxy creation.”);  
  7.         }  
  8.         if (targetClass.isInterface()) {  
  9.             return new JdkDynamicAopProxy(config);  
  10.         }  
  11.         return CglibProxyFactory.createCglibProxy(config);  
  12.     }  
  13.     else {  
  14.         return new JdkDynamicAopProxy(config);  
  15.     }  
  16. }  

Spring JDK动态代理实现


在上面的第三步骤说道或根据用户的配置(例如是否配置了
proxyTargetClass属性为true),选择创建的代理类型,这个的代理类型分两种实现,都是比较高效的,下面根据JDK的动态代理来说明AOP的执行,也是先上JdkDynamicAopProxy的核心代码invoke方法:
[java] 
view plain  
copy

  1. public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {  
  2.        MethodInvocation invocation = null;  
  3.        Object oldProxy = null;  
  4.        boolean setProxyContext = false;  
  5.    
  6.        TargetSource targetSource = this.advised.targetSource;  
  7.        Class targetClass = null;  
  8.        Object target = null;  
  9.    
  10.        try {  
  11.            //eqauls()方法,具目标对象未实现此方法  
  12.            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)){  
  13.                 return (equals(args[0])? Boolean.TRUE : Boolean.FALSE);  
  14.            }  
  15.    
  16.            //hashCode()方法,具目标对象未实现此方法  
  17.            if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)){  
  18.                 return newInteger(hashCode());  
  19.            }  
  20.    
  21.            //Advised接口或者其父接口中定义的方法,直接反射调用,不应用通知  
  22.            if (!this.advised.opaque &&method.getDeclaringClass().isInterface()  
  23.                     &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {  
  24.                 // Service invocations onProxyConfig with the proxy config…  
  25.                 return AopUtils.invokeJoinpointUsingReflection(this.advised,method, args);  
  26.            }  
  27.    
  28.            Object retVal = null;  
  29.    
  30.            if (this.advised.exposeProxy) {  
  31.                 // Make invocation available ifnecessary.  
  32.                 oldProxy = AopContext.setCurrentProxy(proxy);  
  33.                 setProxyContext = true;  
  34.            }  
  35.    
  36.            //获得目标对象的类  
  37.            target = targetSource.getTarget();  
  38.            if (target != null) {  
  39.                 targetClass = target.getClass();  
  40.            }  
  41.    
  42.            //获取可以应用到此方法上的Interceptor列表  
  43.            List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);  
  44.    
  45.            //如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)  
  46.            if (chain.isEmpty()) {  
  47.                 retVal = AopUtils.invokeJoinpointUsingReflection(target,method, args);  
  48.            } else {  
  49.                 //创建MethodInvocation  
  50.                 invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);  
  51.                 retVal = invocation.proceed();  
  52.            }  
  53.    
  54.            // Massage return value if necessary.  
  55.            if (retVal != null && retVal == target &&method.getReturnType().isInstance(proxy)  
  56.                     &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {  
  57.                 // Special case: it returned”this” and the return type of the method  
  58.                 // is type-compatible. Notethat we can’t help if the target sets  
  59.                 // a reference to itself inanother returned object.  
  60.                 retVal = proxy;  
  61.            }  
  62.            return retVal;  
  63.        } finally {  
  64.            if (target != null && !targetSource.isStatic()) {  
  65.                 // Must have come fromTargetSource.  
  66.                targetSource.releaseTarget(target);  
  67.            }  
  68.            if (setProxyContext) {  
  69.                 // Restore old proxy.  
  70.                 AopContext.setCurrentProxy(oldProxy);  
  71.            }  
  72.        }  
  73.     }  

其实上面的注释也说的比较清楚,各个步骤执行的说明:
1)获取拦截器
2)判断拦截器链是否为空,如果是空的话直接调用切点方法
3)如果拦截器不为空的话那么便创建ReflectiveMethodInvocation类,把拦截器方法都封装在里面,也就是执行
getInterceptorsAndDynamicInterceptionAdvice方法
[java] 
view plain  
copy

  1. public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {  
  2.                    MethodCacheKeycacheKey = new MethodCacheKey(method);  
  3.                    List<Object>cached = this.methodCache.get(cacheKey);  
  4.                    if(cached == null) {  
  5.                             cached= this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(  
  6.                                                this,method, targetClass);  
  7.                             this.methodCache.put(cacheKey,cached);  
  8.                    }  
  9.                    returncached;  
  10.          }  

4)其实实际的获取工作其实是由AdvisorChainFactory. getInterceptorsAndDynamicInterceptionAdvice()这个方法来完成的,获取到的结果会被缓存,下面来分析下这个方法的实现:

[java] 
view plain  
copy

  1. /** 
  2.     * 从提供的配置实例config中获取advisor列表,遍历处理这些advisor.如果是IntroductionAdvisor, 
  3.     * 则判断此Advisor能否应用到目标类targetClass上.如果是PointcutAdvisor,则判断 
  4.     * 此Advisor能否应用到目标方法method上.将满足条件的Advisor通过AdvisorAdaptor转化成Interceptor列表返回. 
  5.     */  
  6.     publicList getInterceptorsAndDynamicInterceptionAdvice(Advised config, Methodmethod, Class targetClass) {  
  7.        // This is somewhat tricky… we have to process introductions first,  
  8.        // but we need to preserve order in the ultimate list.  
  9.        List interceptorList = new ArrayList(config.getAdvisors().length);  
  10.    
  11.        //查看是否包含IntroductionAdvisor  
  12.        boolean hasIntroductions = hasMatchingIntroductions(config,targetClass);  
  13.    
  14.        //这里实际上注册一系列AdvisorAdapter,用于将Advisor转化成MethodInterceptor  
  15.        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();  
  16.    
  17.        Advisor[] advisors = config.getAdvisors();  
  18.         for (int i = 0; i <advisors.length; i++) {  
  19.            Advisor advisor = advisors[i];  
  20.            if (advisor instanceof PointcutAdvisor) {  
  21.                 // Add it conditionally.  
  22.                 PointcutAdvisor pointcutAdvisor= (PointcutAdvisor) advisor;  
  23.                 if(config.isPreFiltered() ||pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {  
  24.                     //TODO: 这个地方这两个方法的位置可以互换下  
  25.                     //将Advisor转化成Interceptor  
  26.                     MethodInterceptor[]interceptors = registry.getInterceptors(advisor);  
  27.    
  28.                     //检查当前advisor的pointcut是否可以匹配当前方法  
  29.                     MethodMatcher mm =pointcutAdvisor.getPointcut().getMethodMatcher();  
  30.    
  31.                     if (MethodMatchers.matches(mm,method, targetClass, hasIntroductions)) {  
  32.                         if(mm.isRuntime()) {  
  33.                             // Creating a newobject instance in the getInterceptors() method  
  34.                             // isn’t a problemas we normally cache created chains.  
  35.                             for (intj = 0; j < interceptors.length; j++) {  
  36.                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptors[j],mm));  
  37.                             }  
  38.                         } else {  
  39.                             interceptorList.addAll(Arrays.asList(interceptors));  
  40.                         }  
  41.                     }  
  42.                 }  
  43.            } else if (advisor instanceof IntroductionAdvisor){  
  44.                 IntroductionAdvisor ia =(IntroductionAdvisor) advisor;  
  45.                 if(config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {  
  46.                     Interceptor[] interceptors= registry.getInterceptors(advisor);  
  47.                     interceptorList.addAll(Arrays.asList(interceptors));  
  48.                 }  
  49.            } else {  
  50.                 Interceptor[] interceptors =registry.getInterceptors(advisor);  
  51.                 interceptorList.addAll(Arrays.asList(interceptors));  
  52.            }  
  53.        }  
  54.        return interceptorList;  
  55. }  

5)这个方法执行完成后,Advised中配置能够应用到连接点或者目标类的Advisor全部被转化成了MethodInterceptor.

6)接下来货到invoke方法中的proceed方法 ,我们再看下得到的拦截器链是怎么起作用的,也就是proceed方法的执行过程

[java] 
view plain  
copy

  1. public Object proceed() throws Throwable {  
  2.        //  We start with an index of -1and increment early.  
  3.        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()- 1) {  
  4.            //如果Interceptor执行完了,则执行joinPoint  
  5.            return invokeJoinpoint();  
  6.        }  
  7.    
  8.        Object interceptorOrInterceptionAdvice =  
  9.            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  
  10.          
  11.        //如果要动态匹配joinPoint  
  12.        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher){  
  13.            // Evaluate dynamic method matcher here: static part will already have  
  14.            // been evaluated and found to match.  
  15.            InterceptorAndDynamicMethodMatcher dm =  
  16.                 (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;  
  17.            //动态匹配:运行时参数是否满足匹配条件  
  18.            if (dm.methodMatcher.matches(this.method, this.targetClass,this.arguments)) {  
  19.                 //执行当前Intercetpor  
  20.                 returndm.interceptor.invoke(this);  
  21.            }  
  22.            else {  
  23.                 //动态匹配失败时,略过当前Intercetpor,调用下一个Interceptor  
  24.                 return proceed();  
  25.            }  
  26.        }  
  27.        else {  
  28.            // It’s an interceptor, so we just invoke it: The pointcutwill have  
  29.            // been evaluated statically before this object was constructed.  
  30.            //执行当前Intercetpor  
  31.            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
  32.        }  
  33. }  
7)好了拦截器到这边就可以执行了,复杂的代理终于可以起到他的作用了

Spring CGLIB动态代理实现

由于CGLIB的动态代理代码量比较长,在这就不贴出来代码了,其实这两个代理的实现方式都差不多,都是创建方法调用链,不同的是jdk的动态代理创建的是
ReflectiveMethodInvocation调用链,而cglib创建的是Cglib
MethodInvocation
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/194072.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • ICMP报文详解

    ICMP报文详解概述ICMP允许主机或路由报告差错情况和提供有关异常情况。ICMP是因特网的标准协议,但ICMP不是高层协议,而是IP层的协议。通常ICMP报文被IP层或更高层协议(TCP或UDP)使用。一些ICMP报文把差错报文返回给用户进程。ICMP报文作为IP层数据报的数据,加上数据报的首部,组成数据报发送出去。ICMP报文的种类有两种,即ICMP差错报告报文和ICMP询问报文。ICMP报文的格式类型:占8位代码:占8位检验和:占16位说明:ICMP所有报文的前4个.

  • 液压油报关_液压油算是危险品吗

    液压油报关_液压油算是危险品吗  韩国液压油进口代理报关知识整理  液压油就是我们利用液体压力能的液压控制系统可以使用的液压介质,在液压技术系统中起着能量信息传递、抗磨、系统进行润滑、防腐、防锈、冷却等作用。对于液压油,首先要满足液压装置在工作温度和启动温度下的液体粘度要求,因为润滑油的粘度变化直接关系到液压作用、传动效率和传动精度,还要求润滑油的粘温性能和剪切稳定性能满足不同用途的需要。液压油的种类繁多,分类管理方法各异,长期发展以来,习惯以用途可以进行垃圾分类,也有学生根据不同油品类型、化学组分或可燃性分类的。这些分类方法只反

  • JAVA分布式架构设计实例

    JAVA分布式架构设计实例一款Java语言基于SpringCloud、Vue、ElementUI、MySQL等框架精心打造的一款前后端分离框架,致力于实现模块化、组件化、可插拔的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发、提升开发效率的初衷,目前框架已集成了完整的RBAC权限架构和常规基础模块,前端Vue端支持多主题切换,可以根据自己喜欢的风格选择想一个的主题的个性化呈现的需

  • 高并发下的nginx性能优化实战

    高并发下的nginx性能优化实战

  • tracker服务器地址_rack服务器

    tracker服务器地址_rack服务器tracker服务器内容精选换一换云审计服务支持删除已创建的追踪器。删除追踪器对已有的操作记录没有影响,当您重新开通云审计服务后,依旧可以查看已有的操作记录。DELETE/v1.0/{project_id}/tracker无无无请参见错误码。云审计服务目前仅支持删除已创建的数据类追踪器。删除追踪器对已有的操作记录没有影响,当您重新开通云审计服务后,依旧可以查看已有的操作记录。DELETE/…

  • Java判断回文字符串_java将字符串反转输出

    Java判断回文字符串_java将字符串反转输出java判断回文字符串几种简单的实现:1.将字符串倒置后逐一比较,实现如下:publicclassHuiWenTest{/***@SERLIN*/publicstaticvoidmain(String[]args){Stringstr=””;System.out.println(“请输入一个字符串”);Scannerin

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号