`
jinnianshilongnian
  • 浏览: 21440153 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2406127
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:2998617
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5632141
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:257785
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1593493
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:249079
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5848387
Group-logo
跟我学Nginx+Lua开...
浏览量:698421
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:780863
社区版块
存档分类
最新评论

关于spring的aop拦截的问题 protected方法代理问题

 
阅读更多

之前一论坛朋友问的,复制保存下。原文地址。

 

问题

貌似不能拦截私有方法? 
试了很多次,都失败了,是不是不行啊? 

我想了一下,因为aop底层是代理, 
jdk是代理接口,私有方法必然不会存在在接口里,所以就不会被拦截到; 
cglib是子类,private的方法照样不会出现在子类里,也不能被拦截。 

我不是类内部直接调用方法,而是通过维护一个自身实例的代理 

execution(* test.aop.ServiceA.*(..)) 

Java代码  收藏代码
  1. public class ServiceA {  
  2.   
  3.     private ServiceA  self;  
  4.   
  5.     public void setSelf(ServiceA self) {  
  6.         this.self = self;  
  7.     }  
  8.   
  9.     public String methodA(String str) {  
  10.         System.out.println("methodA: args=" + str);  
  11.         self.methodB("b");  
  12.         return "12345" + str;  
  13.     }  
  14.   
  15.     private String methodB(String str) {  
  16.         System.out.println("methodB: args=" + str);  
  17.         self.methodC("c");  
  18.         return "12345" + str;  
  19.     }  
  20.   
  21.     public String methodC(String str) {  
  22.         System.out.println("methodC: args=" + str);  
  23.         return "12345" + str;  
  24.     }  
  25. }  



如果外部调用methodA,那么methodA和methodC会被拦截到,methodB不行 

是不是这么回事? 
但是stackoverflow上,有人说 it works fine 
http://stackoverflow.com/questions/4402009/aspectj-and-catching-private-or-inner-methods 

execution(public * test.aop.ServiceA.*(..)) 
还有个奇怪的现象,execution里如果不写权限,那么public protected package的方法都能被拦截到 
如果写了public,那就只拦截public方法这个没问题, 
如果写了protected,他就什么事情都不做,连protected的方法也不拦截。

 

分析

private方法 在Spring使用纯Spring AOP(只能拦截public/protected/包)都是无法被拦截的 因为子类无法覆盖;包级别能被拦截的原因是,如果子类和父类在同一个包中是能覆盖的。 

在cglib代理情况下, execution(* *(..)) 可以拦截 public/protected/包级别方法(即这些方法都是能代理的)。 

Java代码  收藏代码
  1. private static boolean isOverridable(Method method, Class targetClass) {  
  2.         if (Modifier.isPrivate(method.getModifiers())) {  
  3.             return false;  
  4.         }  
  5.         if (Modifier.isPublic(method.getModifiers()) || Modifier.isProtected(method.getModifiers())) {  
  6.             return true;  
  7.         }  
  8.         return getPackageName(method.getDeclaringClass()).equals(getPackageName(targetClass));  
  9.     }  




如果想要实现拦截private方法的 可以使用 原生 AspectJ 编译期/运行期织入。 


引用
如果写了protected,他就什么事情都不做,连protected的方法也不拦截;这个应该不会


原因基本分析明白了: 

是否能应用增强的判断代码如下(org.springframework.aop.support.AopUtils): 

Java代码  收藏代码
  1. public static boolean canApply(Pointcut pc, Class targetClass, boolean hasIntroductions) {  
  2.     if (!pc.getClassFilter().matches(targetClass)) {  
  3.         return false;  
  4.     }  
  5.   
  6.     MethodMatcher methodMatcher = pc.getMethodMatcher();  
  7.     IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;  
  8.     if (methodMatcher instanceof IntroductionAwareMethodMatcher) {  
  9.         introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;  
  10.     }  
  11.   
  12.     Set classes = new HashSet(ClassUtils.getAllInterfacesForClassAsSet(targetClass));  
  13.     classes.add(targetClass);  
  14.     for (Iterator it = classes.iterator(); it.hasNext();) {  
  15.         Class clazz = (Class) it.next();  
  16.         Method[] methods = clazz.getMethods();  
  17.         for (int j = 0; j < methods.length; j++) {  
  18.             if ((introductionAwareMethodMatcher != null &&  
  19.                     introductionAwareMethodMatcher.matches(methods[j], targetClass, hasIntroductions)) ||  
  20.                     methodMatcher.matches(methods[j], targetClass)) {  
  21.                 return true;  
  22.             }  
  23.         }  
  24.     }  
  25.   
  26.     return false;  
  27. }  



此处Method[] methods = clazz.getMethods();只能拿到public方法。。 

场景1:execution(* *(..)) 

Java代码  收藏代码
  1. public class Impl2  {  
  2.       
  3.     protected/public String testAop2() {  
  4.         System.out.println("234");  
  5.         return "1233";  
  6.     }  
  7. }  


因为切入点没有访问修饰符,即可以是任意,因此canApply方法能拿到如wait这种public方法,即可以实施代理。 

场景2:execution(public * *(..)) 

Java代码  收藏代码
  1. public class Impl2  {  
  2.       
  3.     public String testAop2() {  
  4.         System.out.println("234");  
  5.         return "1233";  
  6.     }  
  7. }  


因为拦截public的,因此canApply方法能拿到如wait这种public方法,即可以实施代理。 


场景3:execution(protected * *(..)) 

Java代码  收藏代码
  1. public class Impl2  {  
  2.       
  3.     protected String testAop2() {  
  4.         System.out.println("234");  
  5.         return "1233";  
  6.     }  
  7. }  


还记得之前说过,在canApply方法中 的 Method[] methods = clazz.getMethods();只能拿到public方法的,因此跟protected访问修饰符是无法匹配的,所以如果“execution(protected * *(..))” 是 无法代理的。 

这就是为什么execution(protected * *(..))在纯Spring AOP环境下不行的原因。 

注,@Transactional注解事务的特殊情况: 

引用
方法的可见度和 @Transactional 
在使用代理的时候,@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,系统也不会报错, 但是这个被注解的方法将不会执行已配置的事务设置。如果你非要注解非公共方法的话,请参考使用AspectJ 



关于spring切入点语法可以参考我的博客 【http://jinnianshilongnian.iteye.com/blog/1420691

 

 

wangyu1221 写道

 

非常感谢您的回帖~canApply方法是不是用于判断某个切点能否应用于某个类上,只要这个类里面有一个方法能够和切点匹配,就返回true,从整个逻辑来看,就是这个类可以/需要被代理。 

实际运行时在方法拦截的时候,如果某个类不需要被代理,就直接调用这个类实例的方法,而不是这个类的代理的方法, 
如果需要代理,再匹配方法名和修饰符? 

对于上面这个帖子里,之所以protected方法能被无访问修修饰符的execution拦截,是因为这个类里面其他public方法被execution匹配了,导致spring认为这个类可以被代理,而不是protected的方法本身被execution匹配?



引用

 

canApply方法是不是用于判断某个切点能否应用于某个类上,只要这个类里面有一个方法能够和切点匹配,就返回true,从整个逻辑来看,就是这个类可以/需要被代理。


是的。 

引用

 

实际运行时在方法拦截的时候,如果某个类不需要被代理,就直接调用这个类实例的方法,而不是这个类的代理的方法, 
如果需要代理,再匹配方法名和修饰符?



这个只看Cglib2AopProxy吧: 

Java代码  收藏代码
  1. public int accept(Method method) {  
  2.             if (AopUtils.isFinalizeMethod(method)) {  
  3.                 logger.debug("Found finalize() method - using NO_OVERRIDE");  
  4.                 return NO_OVERRIDE;  
  5.             }  
  6.             if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&  
  7.                     method.getDeclaringClass().isAssignableFrom(Advised.class)) {  
  8.                 if (logger.isDebugEnabled()) {  
  9.                     logger.debug("Method is declared on Advised interface: " + method);  
  10.                 }  
  11.                 return DISPATCH_ADVISED;  
  12.             }  
  13.             // We must always proxy equals, to direct calls to this.  
  14.             if (AopUtils.isEqualsMethod(method)) {  
  15.                 logger.debug("Found 'equals' method: " + method);  
  16.                 return INVOKE_EQUALS;  
  17.             }  
  18.             // We must always calculate hashCode based on the proxy.  
  19.             if (AopUtils.isHashCodeMethod(method)) {  
  20.                 logger.debug("Found 'hashCode' method: " + method);  
  21.                 return INVOKE_HASHCODE;  
  22.             }  
  23.             Class targetClass = this.advised.getTargetClass();  
  24.             // Proxy is not yet available, but that shouldn't matter.  
  25.             List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);  
  26.             boolean haveAdvice = !chain.isEmpty();  
  27.             boolean exposeProxy = this.advised.isExposeProxy();  
  28.             boolean isStatic = this.advised.getTargetSource().isStatic();  
  29.             boolean isFrozen = this.advised.isFrozen();  
  30.             if (haveAdvice || !isFrozen) {  
  31.                 // If exposing the proxy, then AOP_PROXY must be used.  
  32.                 if (exposeProxy) {  
  33.                     if (logger.isDebugEnabled()) {  
  34.                         logger.debug("Must expose proxy on advised method: " + method);  
  35.                     }  
  36.                     return AOP_PROXY;  
  37.                 }  
  38.                 String key = method.toString();  
  39.                 // Check to see if we have fixed interceptor to serve this method.  
  40.                 // Else use the AOP_PROXY.  
  41.                 if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {  
  42.                     if (logger.isDebugEnabled()) {  
  43.                         logger.debug("Method has advice and optimisations are enabled: " + method);  
  44.                     }  
  45.                     // We know that we are optimising so we can use the  
  46.                     // FixedStaticChainInterceptors.  
  47.                     int index = ((Integer) this.fixedInterceptorMap.get(key)).intValue();  
  48.                     return (index + this.fixedInterceptorOffset);  
  49.                 }  
  50.                 else {  
  51.                     if (logger.isDebugEnabled()) {  
  52.                         logger.debug("Unable to apply any optimisations to advised method: " + method);  
  53.                     }  
  54.                     return AOP_PROXY;  
  55.                 }  
  56.             }  
  57.             else {  
  58.                 // See if the return type of the method is outside the class hierarchy  
  59.                 // of the target type. If so we know it never needs to have return type  
  60.                 // massage and can use a dispatcher.  
  61.                 // If the proxy is being exposed, then must use the interceptor the  
  62.                 // correct one is already configured. If the target is not static cannot  
  63.                 // use a Dispatcher because the target can not then be released.  
  64.                 if (exposeProxy || !isStatic) {  
  65.                     return INVOKE_TARGET;  
  66.                 }  
  67.                 Class returnType = method.getReturnType();  
  68.                 if (targetClass == returnType) {  
  69.                     if (logger.isDebugEnabled()) {  
  70.                         logger.debug("Method " + method +  
  71.                                 "has return type same as target type (may return this) - using INVOKE_TARGET");  
  72.                     }  
  73.                     return INVOKE_TARGET;  
  74.                 }  
  75.                 else if (returnType.isPrimitive() || !returnType.isAssignableFrom(targetClass)) {  
  76.                     if (logger.isDebugEnabled()) {  
  77.                         logger.debug("Method " + method +  
  78.                                 " has return type that ensures this cannot be returned- using DISPATCH_TARGET");  
  79.                     }  
  80.                     return DISPATCH_TARGET;  
  81.                 }  
  82.                 else {  
  83.                     if (logger.isDebugEnabled()) {  
  84.                         logger.debug("Method " + method +  
  85.                                 "has return type that is assignable from the target type (may return this) - " +  
  86.                                 "using INVOKE_TARGET");  
  87.                     }  
  88.                     return INVOKE_TARGET;  
  89.                 }  
  90.             }  
  91.         }  


List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 
即如果此方法有对应的advice就走代理。 

//getInterceptorsAndDynamicInterceptionAdvice代码如下所示: 

Java代码  收藏代码
  1. public List getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {  
  2.     MethodCacheKey cacheKey = new MethodCacheKey(method);  
  3.     List cached = (List) this.methodCache.get(cacheKey);  
  4.     if (cached == null) {  
  5.         cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(  
  6.                 this, method, targetClass); //转调DefaultAdvisorChainFactory  
  7.         this.methodCache.put(cacheKey, cached);  
  8.     }  
  9.     return cached;  
  10. }  



也就是说需要一次切入点的匹配,即如果方法有切入点就走代理方法 否则目标方法。 


再来看CglibMethodInvocation(cglib的 DynamicAdvisedInterceptor使用): 

引用

 

public Object proceed() throws Throwable { 
// We start with an index of -1 and increment early. 
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { 
return invokeJoinpoint(); 


Object interceptorOrInterceptionAdvice = 
    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); 
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { 
// Evaluate dynamic method matcher here: static part will already have 
// been evaluated and found to match. 
InterceptorAndDynamicMethodMatcher dm = 
    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; 
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { 
return dm.interceptor.invoke(this); 

else { 
// Dynamic matching failed. 
// Skip this interceptor and invoke the next in the chain. 
return proceed(); 


else { 
// It's an interceptor, so we just invoke it: The pointcut will have 
// been evaluated statically before this object was constructed. 
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); 



                 /** 
* Gives a marginal performance improvement versus using reflection to 
* invoke the target when invoking public methods. 
*/ 
protected Object invokeJoinpoint() throws Throwable { 
if (this.protectedMethod) { 
return super.invokeJoinpoint(); 

else { 
return this.methodProxy.invoke(this.target, this.arguments); 




即如果有InterceptorAndDynamicMethodMatcher 这是动态切入点切入点匹配器: 

引用spring文档 

引用

 

7.2.4.2. 动态切入点 
动态切入点比起静态切入点在执行时要消耗更多的资源。它们同时计算方法参数和静态信息。 这意味着它们必须在每次方法调用时都被计算;由于参数的不同,结果不能被缓存。 
动态切入点的主要例子是控制流切入点。 


这个在spring aop中只有一种情况:PerTargetInstantiationModelPointcut 这个切入点;这个可以参考《【第六章】 AOP 之 6.8 切面实例化模型 ——跟我学spring3 》 pertarget。 

也就是说如果是 
静态切入点代理:如果有匹配的advice就走代理; 
动态切入点代理:需要在运行时进行匹配。 


综上所述: 
execution(* *(..)) 可以匹配public/protected的,因为public的有匹配的了,目标类就代理了,,,再进行切入点匹配时也是能匹配的,而且cglib方式能拿到包级别/protected方法,而且包级别/protected方法可以直接通过反射调用。 


引用

 


对于上面这个帖子里,之所以protected方法能被无访问修修饰符的execution拦截,是因为这个类里面其他public方法被execution匹配了,导致spring认为这个类可以被代理,而不是protected的方法本身被execution匹配?


这个是因为protected 修饰符的切入点 无法匹配 Method[] methods = clazz.getMethods(); 这里的任何一个,因此无法代理的。 

8
1
分享到:
评论
1 楼 anxihuixiang 2016-07-10  
讲的真好地地道道

相关推荐

    peak-linux-driver-8.15.2.tar

    peak-linux-driver-8.15.2.tar

    VSCodeUserSetup-x64-1.86.1.exe

    VSCodeUserSetup-x64-1.86.1

    毕业设计使用ncnn在ios+android上部署yolov5源码+详细说明.zip

    高分毕业设计 毕业设计源码 使用ncnn在ios+android上部署yolov5源码+详细说明.zip 高分毕业设计 毕业设计源码 使用ncnn在ios+android上部署yolov5源码+详细说明.zip 高分毕业设计 毕业设计源码 使用ncnn在ios+android上部署yolov5源码+详细说明.zip 高分毕业设计 毕业设计源码 使用ncnn在ios+android上部署yolov5源码+详细说明.zip 高分毕业设计 毕业设计源码 使用ncnn在ios+android上部署yolov5源码+详细说明.zip 高分毕业设计 毕业设计源码 使用ncnn在ios+android上部署yolov5源码+详细说明.zip 高分毕业设计 毕业设计源码 使用ncnn在ios+android上部署yolov5源码+详细说明.zip 高分毕业设计 毕业设计源码 使用ncnn在ios+android上部署yolov5源码+详细说明.zip 高分毕业设计 毕业设计源码 使用ncnn在ios+android上部署yolov5源码+详细说明.zip

    课设毕设基于SSM的医院远程诊断系统-LW+PPT+源码可运行.zip

    课设毕设基于SSM的医院远程诊断系统--LW+PPT+源码可运行.

    node-v0.10.25-sunos-x86.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v0.10.24-x64.msi

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    matlab-简明实例教程详解

    matlab实用的例程详解可供学习与参考理解,MATLAB 已经受了用户的多年考验 在欧美发达国家 MATLAB 已经成为应用线性代数 自动控制理论 数理统计 数字信号处理 时间序列分析 动态系统仿真等高级课程的基本教学工具 成为攻读学位的大学生 硕士生 博士生必须掌握的基本技能 在设计研究单位和工业部门 MATLAB 被广泛地用于研究和解决各种具体工程问题。

    node-v0.10.26-sunos-x64.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    javascript 中关于 this 的用法.zip

    javascript 中关于 this 的用法.zip

    【课程设计】基于python实现多AGV路径规划算法研究源码.zip

    【课程设计】基于python实现多AGV路径规划算法研究源码.zip

    【课程设计】基于间接卡尔曼滤波的IMU与GPS融合MATLAB仿真(IMU与GPS数据由仿真生成)源码.zip

    【课程设计】基于间接卡尔曼滤波的IMU与GPS融合MATLAB仿真(IMU与GPS数据由仿真生成)源码.zip

    静态网页比赛.zip

    静态网页比赛.zip

    【毕业设计】缺陷检测-基于深度学习实现的高效轮胎磨损+缺陷检测算法实现python源码.zip

    【毕业设计】缺陷检测-基于深度学习实现的高效轮胎磨损+缺陷检测算法实现python源码.zip

    springboot282基于web的机动车号牌管理系统.rar

    开发语言:java 框架:springboot,vue JDK版本:JDK1.8 数据库:mysql5.7+(推荐5.7,8.0也可以) 数据库工具:Navicat11+ 开发软件:idea/eclipse(推荐idea)

    《软件设计与体系结构R》实验报告

    21级太原理工大学JACVAEE实验报告,各位当个参考即可,不用过分较真,如果与你们想法不同,请以自己为主,各位加油。

    node-v4.2.2-darwin-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于Java与SNMP实现的网络设备MIB信息采集.zip

    运用java语言设计了一个针对TCP/IP网络的基于SNMP网络设备的MIB信息采集系统。 这个系统采用三层模型进行设计 最底层负责SNMP中基本对象编码、定义,与设备连接通信等; 中间层在底层的基础上定义了MIB对象,负责OID与MIB对象间的转换,分析MIB信息文件以生成MIB树型结构,单个MIB变量信息查询等功能 顶层,即界面层则在中间层的基础上实现了用户界面。

    QuarkCloudDrive.exe

    QuarkCloudDrive网盘

    node-v0.8.20-x64.msi

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

Global site tag (gtag.js) - Google Analytics