Apache Shiro—–Java权限安全框架

先记录,后学习!

学习链接:http://www.9iu.org/2013/12/10/springrain1-shiro.html

http://www.ibm.com/developerworks/cn/java/j-lo-shiro/

一、什么是Shiro
Apache Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能:

  • 认证 – 用户身份识别,常被称为用户“登录”;
  • 授权 – 访问控制;
  • 密码加密 – 保护或隐藏数据防止被偷窥;
  • 会话管理 – 每用户相关的时间敏感的状态。

对于任何一个应用程序,Shiro都可以提供全面的安全管理服务。并且相对于其他安全框架,Shiro要简单的多。

二、Shiro的架构介绍
首先,来了解一下Shiro的三个核心组件:Subject, SecurityManager 和 Realms. 如下图:

Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。

SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。

Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

Shiro完整架构图:


除前文所讲Subject、SecurityManager 、Realm三个核心组件外,Shiro主要组件还包括:
Authenticator :认证就是核实用户身份的过程。这个过程的常见例子是大家都熟悉的“用户/密码”组合。多数用户在登录软件系统时,通常提供自己的用户名(当事人)和支持他们的密码(证书)。如果存储在系统中的密码(或密码表示)与用户提供的匹配,他们就被认为通过认证。
Authorizer :授权实质上就是访问控制 – 控制用户能够访问应用中的哪些内容,比如资源、Web页面等等。
SessionManager :在安全框架领域,Apache Shiro提供了一些独特的东西:可在任何应用或架构层一致地使用Session API。即,Shiro为任何应用提供了一个会话编程范式 – 从小型后台独立应用到大型集群Web应用。这意味着,那些希望使用会话的应用开发者,不必被迫使用Servlet或EJB容器了。或者,如果正在使用这些容器,开发者现在也可以选择使用在任何层统一一致的会话API,取代Servlet或EJB机制。
CacheManager :对Shiro的其他组件提供缓存支持。

原文链接:http://kdboy.iteye.com/blog/1154644

Shiro与Spring集成:

Shiro的组件都是JavaBean/POJO式的组件,所以非常容易使用Spring进行组件管理,可以非常方便的从ini配置迁移到Spring进行管理,且支持JavaSE应用及Web应用的集成。

 

在示例之前,需要导入shiro-spring及spring-context依赖,具体请参考pom.xml。

spring-beans.xml配置文件提供了基础组件如DataSource、DAO、Service组件的配置。

 

JavaSE应用

 

spring-shiro.xml提供了普通JavaSE独立应用的Spring配置:

Java代码

  1. <!– 缓存管理器 使用Ehcache实现 –>
  2. <bean id=”cacheManager” class=”org.apache.shiro.cache.ehcache.EhCacheManager”>
  3.     <property name=”cacheManagerConfigFile” value=”classpath:ehcache.xml”/>
  4. </bean>
  5. <!– 凭证匹配器 –>
  6. <bean id=”credentialsMatcher” class=”
  7. com.github.zhangkaitao.shiro.chapter12.credentials.RetryLimitHashedCredentialsMatcher”>
  8.     <constructor-arg ref=”cacheManager”/>
  9.     <property name=”hashAlgorithmName” value=”md5″/>
  10.     <property name=”hashIterations” value=”2″/>
  11.     <property name=”storedCredentialsHexEncoded” value=”true”/>
  12. </bean>
  13. <!– Realm实现 –>
  14. <bean id=”userRealm” class=”com.github.zhangkaitao.shiro.chapter12.realm.UserRealm”>
  15.     <property name=”userService” ref=”userService”/>
  16.     <property name=”credentialsMatcher” ref=”credentialsMatcher”/>
  17.     <property name=”cachingEnabled” value=”true”/>
  18.     <property name=”authenticationCachingEnabled” value=”true”/>
  19.     <property name=”authenticationCacheName” value=”authenticationCache”/>
  20.     <property name=”authorizationCachingEnabled” value=”true”/>
  21.     <property name=”authorizationCacheName” value=”authorizationCache”/>
  22. </bean>
  23. <!– 会话ID生成器 –>
  24. <bean id=”sessionIdGenerator”
  25. class=”org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator”/>
  26. <!– 会话DAO –>
  27. <bean id=”sessionDAO”
  28. class=”org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO”>
  29.     <property name=”activeSessionsCacheName” value=”shiro-activeSessionCache”/>
  30.     <property name=”sessionIdGenerator” ref=”sessionIdGenerator”/>
  31. </bean>
  32. <!– 会话验证调度器 –>
  33. <bean id=”sessionValidationScheduler”
  34. class=”org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler”>
  35.     <property name=”sessionValidationInterval” value=”1800000″/>
  36.     <property name=”sessionManager” ref=”sessionManager”/>
  37. </bean>
  38. <!– 会话管理器 –>
  39. <bean id=”sessionManager” class=”org.apache.shiro.session.mgt.DefaultSessionManager”>
  40.     <property name=”globalSessionTimeout” value=”1800000″/>
  41.     <property name=”deleteInvalidSessions” value=”true”/>
  42.     <property name=”sessionValidationSchedulerEnabled” value=”true”/>
  43.    <property name=”sessionValidationScheduler” ref=”sessionValidationScheduler”/>
  44.     <property name=”sessionDAO” ref=”sessionDAO”/>
  45. </bean>
  46. <!– 安全管理器 –>
  47. <bean id=”securityManager” class=”org.apache.shiro.mgt.DefaultSecurityManager”>
  48.     <property name=”realms”>
  49.         <list><ref bean=”userRealm”/></list>
  50.     </property>
  51.     <property name=”sessionManager” ref=”sessionManager”/>
  52.     <property name=”cacheManager” ref=”cacheManager”/>
  53. </bean>
  54. <!– 相当于调用SecurityUtils.setSecurityManager(securityManager) –>
  55. <bean class=”org.springframework.beans.factory.config.MethodInvokingFactoryBean”>
  56. <property name=”staticMethod”
  57. value=”org.apache.shiro.SecurityUtils.setSecurityManager”/>
  58.     <property name=”arguments” ref=”securityManager”/>
  59. </bean>
  60. <!– Shiro生命周期处理器–>
  61. <bean id=”lifecycleBeanPostProcessor”
  62. class=”org.apache.shiro.spring.LifecycleBeanPostProcessor”/>

可以看出,只要把之前的ini配置翻译为此处的spring xml配置方式即可,无须多解释。LifecycleBeanPostProcessor用于在实现了Initializable接口的Shiro bean初始化时调用Initializable接口回调,在实现了Destroyable接口的Shiro bean销毁时调用 Destroyable接口回调。如UserRealm就实现了Initializable,而DefaultSecurityManager实现了Destroyable。具体可以查看它们的继承关系。

 

测试用例请参考com.github.zhangkaitao.shiro.chapter12.ShiroTest。

 

Web应用

Web应用和普通JavaSE应用的某些配置是类似的,此处只提供一些不一样的配置,详细配置可以参考spring-shiro-web.xml。

Java代码

  1. <!– 会话Cookie模板 –>
  2. <bean id=”sessionIdCookie” class=”org.apache.shiro.web.servlet.SimpleCookie”>
  3.     <constructor-arg value=”sid”/>
  4.     <property name=”httpOnly” value=”true”/>
  5.     <property name=”maxAge” value=”180000″/>
  6. </bean>
  7. <!– 会话管理器 –>
  8. <bean id=”sessionManager”
  9. class=”org.apache.shiro.web.session.mgt.DefaultWebSessionManager”>
  10.     <property name=”globalSessionTimeout” value=”1800000″/>
  11.     <property name=”deleteInvalidSessions” value=”true”/>
  12.     <property name=”sessionValidationSchedulerEnabled” value=”true”/>
  13.     <property name=”sessionValidationScheduler” ref=”sessionValidationScheduler”/>
  14.     <property name=”sessionDAO” ref=”sessionDAO”/>
  15.     <property name=”sessionIdCookieEnabled” value=”true”/>
  16.     <property name=”sessionIdCookie” ref=”sessionIdCookie”/>
  17. </bean>
  18. <!– 安全管理器 –>
  19. <bean id=”securityManager” class=”org.apache.shiro.web.mgt.DefaultWebSecurityManager”>
  20. <property name=”realm” ref=”userRealm”/>
  21.     <property name=”sessionManager” ref=”sessionManager”/>
  22.     <property name=”cacheManager” ref=”cacheManager”/>
  23. </bean>

1、sessionIdCookie是用于生产Session ID Cookie的模板;

2、会话管理器使用用于web环境的DefaultWebSessionManager;

3、安全管理器使用用于web环境的DefaultWebSecurityManager。

 

Java代码

  1. <!– 基于Form表单的身份验证过滤器 –>
  2. <bean id=”formAuthenticationFilter”
  3. class=”org.apache.shiro.web.filter.authc.FormAuthenticationFilter”>
  4.     <property name=”usernameParam” value=”username”/>
  5.     <property name=”passwordParam” value=”password”/>
  6.     <property name=”loginUrl” value=”/login.jsp”/>
  7. </bean>
  8. <!– Shiro的Web过滤器 –>
  9. <bean id=”shiroFilter” class=”org.apache.shiro.spring.web.ShiroFilterFactoryBean”>
  10.     <property name=”securityManager” ref=”securityManager”/>
  11.     <property name=”loginUrl” value=”/login.jsp”/>
  12.     <property name=”unauthorizedUrl” value=”/unauthorized.jsp”/>
  13.     <property name=”filters”>
  14.         <util:map>
  15.             <entry key=”authc” value-ref=”formAuthenticationFilter”/>
  16.         </util:map>
  17.     </property>
  18.     <property name=”filterChainDefinitions”>
  19.         <value>
  20.             /index.jsp = anon
  21.             /unauthorized.jsp = anon
  22.             /login.jsp = authc
  23.             /logout = logout
  24.             /** = user
  25.         </value>
  26.     </property>
  27. </bean>

1、formAuthenticationFilter为基于Form表单的身份验证过滤器;此处可以再添加自己的Filter bean定义;

2、shiroFilter:此处使用ShiroFilterFactoryBean来创建ShiroFilter过滤器;filters属性用于定义自己的过滤器,即ini配置中的[filters]部分;filterChainDefinitions用于声明url和filter的关系,即ini配置中的[urls]部分。

 

接着需要在web.xml中进行如下配置:

Java代码

  1. <context-param>
  2.     <param-name>contextConfigLocation</param-name>
  3.     <param-value>
  4.         classpath:spring-beans.xml,
  5.         classpath:spring-shiro-web.xml
  6.     </param-value>
  7. </context-param>
  8. <listener>
  9.    <listener-class>
  10. org.springframework.web.context.ContextLoaderListener
  11. </listener-class>
  12. </listener>

通过ContextLoaderListener加载contextConfigLocation指定的Spring配置文件。

 

Java代码

  1. <filter>
  2.     <filter-name>shiroFilter</filter-name>
  3.     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  4.     <init-param>
  5.         <param-name>targetFilterLifecycle</param-name>
  6.         <param-value>true</param-value>
  7.     </init-param>
  8. </filter>
  9. <filter-mapping>
  10.     <filter-name>shiroFilter</filter-name>
  11.     <url-pattern>/*</url-pattern>
  12. </filter-mapping>

DelegatingFilterProxy会自动到Spring容器中查找名字为shiroFilter的bean并把filter请求交给它处理。

 

其他配置请参考源代码。

 

Shiro权限注解

Shiro提供了相应的注解用于权限控制,如果使用这些注解就需要使用AOP的功能来进行判断,如Spring AOP;Shiro提供了Spring AOP集成用于权限注解的解析和验证。

为了测试,此处使用了Spring MVC来测试Shiro注解,当然Shiro注解不仅仅可以在web环境使用,在独立的JavaSE中也是可以用的,此处只是以web为例了。

 

在spring-mvc.xml配置文件添加Shiro Spring AOP权限注解的支持:

Java代码

  1. <aop:config proxy-target-class=”true”></aop:config>
  2. <bean class=”
  3. org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor”>
  4.     <property name=”securityManager” ref=”securityManager”/>
  5. </bean>

如上配置用于开启Shiro Spring AOP权限注解的支持;<aop:config proxy-target-class=”true”>表示代理类。

 

接着就可以在相应的控制器(AnnotationController)中使用如下方式进行注解:

Java代码

  1. @RequiresRoles(“admin”)
  2. @RequestMapping(“/hello2”)
  3. public String hello2() {
  4.     return “success”;
  5. }

访问hello2方法的前提是当前用户有admin角色。

 

当验证失败,其会抛出UnauthorizedException异常,此时可以使用Spring的ExceptionHandler(DefaultExceptionHandler)来进行拦截处理:

Java代码

  1. @ExceptionHandler({UnauthorizedException.class})
  2. @ResponseStatus(HttpStatus.UNAUTHORIZED)
  3. public ModelAndView processUnauthenticatedException(NativeWebRequest request, UnauthorizedException e) {
  4.     ModelAndView mv = new ModelAndView();
  5.     mv.addObject(“exception”, e);
  6.     mv.setViewName(“unauthorized”);
  7.     return mv;
  8. }

如果集成Struts2,需要注意《Shiro+Struts2+Spring3 加上@RequiresPermissions 后@Autowired失效》问题:

http://jinnianshilongnian.iteye.com/blog/1850425

 

权限注解

Java代码

  1. @RequiresAuthentication

表示当前Subject已经通过login进行了身份验证;即Subject. isAuthenticated()返回true。

 

Java代码

  1. @RequiresUser

表示当前Subject已经身份验证或者通过记住我登录的。

 

Java代码

  1. @RequiresGuest

表示当前Subject没有身份验证或通过记住我登录过,即是游客身份。

 

Java代码

  1. @RequiresRoles(value={“admin”, “user”}, logical= Logical.AND)

表示当前Subject需要角色admin和user。

 

Java代码

  1. @RequiresPermissions (value={“user:a”, “user:b”}, logical= Logical.OR)

表示当前Subject需要权限user:a或user:b。

 

 

链接:http://jinnianshilongnian.iteye.com/blog/2029717

30天学习30种新技术系列

原文地址:http://segmentfault.com/a/1190000000349384

编者注:我们发现了比较有趣的系列文章《30天学习30种新技术》,准备翻译,一天一篇更新,年终礼包。以下是译文,英文标题表示还未翻译,附原文链接;中文标题表示已翻译,附译文链接。

更新:全系列已经全部翻译完了~

让你30天学习30种新技术,你会觉得这是挑战吗?

img-1

我已经接受了挑战,我会在一个月的时间内每天学习一门新技术,挑战开始于2013年10月29日。下面就是我将要学习的新技术的列表,我会把每天学到的内容写出来。在我每天正常的工作之后,我会花几个小时学习一门新技术,再用一小时将今天学到的写在博客上。这项活动的目的是熟悉许多在开发者社区所使用的新技术。

我会把重点放在JavaScript及其相关技术的学习上,当然也会去了解一下像Java这类我比较感兴趣的其他技术。我也可能会在一门技术上花费好几天的时间,但我每次会选择和这门技术相关的不同的主题来讲。只要是有意义的,我将尽量展示它如何与OpenShift工作,我希望这是一次充满乐趣并能学到很多东西的旅程。(你可以在twitter上follow 我

下边是学习列表:


原文 Learning 30 Technologies in 30 Days: A Developer Challenge
翻译 SegmentFault

 

影响Java EE性能的十大问题(转载)

本文作者是一名有10多年经验的高级系统架构师,他的主要专业领域是Java EE、中间件和JVM技术。他在性能优化和提升方面也有很深刻的见解,下面他将和大家分享一下常见的10个影响Java EE性能问题。

1.缺乏正确的容量规划

容量规划是一个全面的和发展的过程标准,预测当前和未来的IT环境容量需求。制定合理的容量规划不仅会确保和跟踪当前IT生产能力和稳定性,同时也会确保新项目以最小的风险部署到现有的生产环境中。硬件、中间件、JVM、调整等在项目部署之前就应该准备好。

2.JavaEE中间件环境规范不足

“没有规矩,不成方圆”。第二个比较普遍的原因是Java EE中间件或者基础架构不规范。在项目初始,新平台上面没有制定合理的规范,导致系统稳定性差。这会增加客户成本,所以花时间去制定合理的Java EE中间件环境规范是必须的。这项工作应与初始容量规划迭代相结合。

3.Java虚拟机垃圾回收过度

各位对“java.lang.OutOfMemoryError”这个错误信息是不是很熟悉呢?由于JVM的内存空间过度消耗(Java堆、本机堆等)而抛出的异常。

垃圾收集问题并不一定会表现为一个OOM条件,过度的垃圾收集可以理解成是JVM GC线程在短时间里进行轻微或超量收集集合数据而导致的JVM暂停时间很长和性能下降。可能有以下几个原因:

1.与JVM的负载量和应用程序内存占用量相比,Java堆可能选择的太小。

2.JVM GC策略使用不合理。

3.应用程序静态或动态内存占用量太大,不适合在32位JVM上使用。

4.JVM OldGen随着时间推移,泄漏越来越严重,而GC在几个小时或者几天后才发现。

5.JVM PermGen空间(只有HotSpot VM)或本机堆随着时间推移会泄露是一个非常普遍的问题;OOM的错误往往是观察一段时间后,应用程序进行动态调动。

6.YoungGen和OldGen的比例空间与你的应用程序不匹配。

7.Java堆在32位的VM上太大,导致本机堆溢出,具体可以表现为OOM试着去链接一个新的Java EE应用程序、创建一个新的Java线程或者需要计算本地内存分配任务。

建议:

1.观察和深入理解JVM垃圾回收。启动GC,根据健康合理的评估来提供所有的数据。

2.记住,GC方面的相关问题不会在开发中或者功能测试时发现,它需要在多用户高负载的测试环境下发现。

4.与外部系统集成过多或过少

导致Java EE性能差的第四个原因是高分布式系统,典型案例是电信IT环境。在这个环境中,一个中间件领域(例如,服务总线)很少会做所有的工作,而仅仅是把一些业务“委托”给其他部分,例如产品质量,客户资料和订单管理,到其他Java EE中间件平台或遗留系统中,如支持各种不同的负载类型和通信协议的大型机。

这样的外部系统调用意味着客户端的Java EE应用程序触发创建或重用套接字链接从外部系统中读写数据。根据业务流程的实施和实现可以配置成同步调用或异步调用。需要注意的是,响应时间会根据外部系统的稳定状况进行改变,所以通过适当的使用超时来保护Java EE应用程序和中间件也是非常重要的。

下面这3种情况是经常出现问题和性能降低的地方:

1.同步和相继调用太多的外部系统。

2.在Java EE客户端应用程序和外部系统之间链接超时,使数据丢失或者值太高导致客户端线程被卡住,从而导致多米拉效应。

3.超时,但程序仍正常执行,可是中间件不处理这种奇怪的路径。

最后,建议多进行负面测试,这意味着需要“人为”创造产生这些问题的条件,用来测试应用程序和中间件之间是如何处理外部系统错误。

5.缺乏适当的数据库SQL调优和容量规划

大家可能会对这一个感到惊奇:数据库问题。大多数Java EE企业系统是依赖关系型数据库处理复杂的业务流程。一个基础扎实稳固的数据库环境可以确保IT环境有规模的增长,来支持日益不断扩大的业务。

在实际中,与数据库相关的性能问题是很常见的。由于多数数据库事务处理都是由JDBC数据源执行的(包括关系持久化API,例如Hibernate)。而性能问题最初都会表现为线程阻塞。

以下是我在10年的工作中,经常出现的关于数据库方面的问题(以Oracle数据库为例):

1.孤立的,长时间运行的SQL。主要表现为线程阻塞、SQL没有进行优化、缺少索引、非最佳的执行计划、返回大量数据集等等。

2.表或行级数据锁定。当提交一个双阶段事务模型时(例如,臭名昭著的Oracle可疑事务)。Java EE容器可能会留下一些未处理的事务等待最后的提交或回滚,留下的数据锁能触发性能问题,直到最后的锁被移除。例如中间件断电或者服务器崩溃都可能引起这些情况发生。

3.缺乏合理规范的数据库管理工具。例如Oracle里面的REDO logs,数据库数据文件等。磁盘空间不足,日志文件不旋转等都会触发较大的性能问题和断电情况。

建议:

1.合理的容量规划,包括负载和性能测试都是必不可少的,优化数据环境和及时发现问题。

2.如果是使用Oracle数据库,确保DBA团队定期审查AWR报告,尤其是在上下关联的事件和根源分析过程中。

3.使用JVM线程存储和AWR报告查明SQL运行缓慢的原因或者使用监控工具来做。

4.加强“操作”方面的数据库环境(磁盘空间、数据文件、重做日志、表空间等)以适当的监视和报警。如果不这么做,会让客户端IT环境出现较多的断电情况和花许多时间进行故障调修。

.特定应用程序性能问题

下面关注的是比较严重的Java EE应用程序问题。关于特定应用程序性能问题,总结了以下几个点:

1.线程安全的代码问题

2.通信API缺少超时设置

3.I/O、JDBC或者关系型API资源管理问题

4.缺乏适当的数据缓存

5.数据缓存过度

6.过多的日志记录

7.JavaEE中间件调优问题

一般Java EE中间件都已经够用了,只是缺少必要的优化。大多数Java EE容器都能有多种方案供你的应用程序和业务进程选择。

如果没有进行适当的调整和实践,那么Java EE容器可能会处于一种消极的状态。

下图是视图和检查列表示例:

8.主动监控不足

缺乏监控,并不会带来实际性能问题,但它会影响你对Java EE平台性能和健康状况的了解。最终,这个环境可以达到一个破发点,这可能会暴露出一些缺陷和问题(JVM的内存泄漏,等等)。

以我的经验来看,如果一开始不进行监控,而是运行几个月或者几年后再进行,平台稳定性将大打折扣。

也就是说,改善现有的环境永远都不会晚。下面是一些建议:

1.复查现有Java EE环境监测能力和找到需改进的地方。

2.监测方案应该尽可能的覆盖整个环境。

3.监控方案应该符合容量规划进程。

9.公共基础设施硬件饱和

这个问题经常在有太多的Java EE中间件环境随着JVM进程被部署到现有硬件上面时看到。太多的JVM进程对有限的物理CPU核心来说是一个真正的程序性能杀手。另外,随着客户端业务的增长,硬件方面也需要再次考虑。

10.网络延迟

最后一个影响性能问题的是网络,网络问题时不时的都会发生,如路由器、交换机和DNS服务器失败。更常见的是在一个高度分散的IT环境中定期或间歇性延迟。下面图片中的例子是一个位于同一区域的Weblogic集群通信与Oracle数据库服务器之间的延迟。

间歇或定期的延迟会触发一些重要的性能问题,以不同的方式影响Java EE应用程序。

1.因为大量的fetch迭代(网络传入和传出),涉及大数据集的数据查询问题的应用会非常受网络延迟的影响

2.应用程序在处理外部系统大数据负载(例如XML数据)时也会很受网络延迟的影响,会在发送和接收响应时产生巨大的响应间隔。

3.Java EE容器复制过程(集群)也会受到影响,并且会让故障转移功能(如多播或单播数据包损失)处于风险中。

JDBC行数据“预取”、XML数据压缩和数据缓存可以减少网络延迟。在设计一个新的网络拓扑时,应该仔细检查这种网络延迟问题。

希望本文能够帮助您理解一些常见的性能问题和压力点,每个IT环境都是独一无二的,所以文中提到的问题不一定会是您遇到的,您可以把您遇到的问题拿出来和大家一起分享一下!

英文来自:Top 10 Causes of Java EE Enterprise Performance Problems