And*_*ich 6 aop expression aspectj spring-aop pointcut
在我们的应用程序中,我们有几个(实际上很多,大约30个)Web服务.每个Web服务都驻留在自己的WAR文件中,并且具有自己的Spring上下文,该上下文在应用程序启动时初始化.
我们还有许多应用于Web服务类的注释驱动的方面类.在开始时,poincut表达式看起来像这样:
@Pointcut("execution(public * my.package.service.business.*BusinessServiceImpl.*(..))")
public void methodsToBeLogged() {
}
Run Code Online (Sandbox Code Playgroud)
并且通过配置输入启用了AOP服务.
但是当网络服务的数量增加时,我们开始OutOfMemoryException在服务器上体验s.在进行一些分析和分析之后,看起来内存是由AspectJExpressionPointcut类的实例保存的缓存占用的.
每个实例的缓存大约是5 MB.由于我们有3个方面和30个服务,因此共有90个实例共存储了450MB的数据.
在检查了缓存的内容后,我们意识到它包含了WAR中存在的所有类的Java反射方法实例,即使是那些不属于my.package.service.business包的类.修改了切点表达式后还有附加within条款:
@Pointcut("execution(public * my.package.service.business.*BusinessServiceImpl.*(..)) &&
within(my.package.service.business..*)")
public void methodsToBeLogged() {
}
Run Code Online (Sandbox Code Playgroud)
内存使用量再次降至正常水平.并且所有AspectJExpressionPointcut实例总共花费不到1MB.
有人可以解释为什么会这样吗?为什么第一点切割表达还不够?为什么AspectJExpressionPointcut不共享缓存?
小智 9
AspectJExpressionPointcut使用缓存(shadowMatchCache),根据切入点表达式,加速决定是否应将AOP应用于某个方法调用.此缓存可能会消耗大量内存.
另外,在提供特定bean的所有方法以查看是否存在切入点表达式匹配之前,Spring首先通过调用AspectJExpressionPointcut.matches(Class targetClass)来检查bean类是否可能匹配.此方法委托AspectJ的PointcutExpressionImpl.couldPossiblyMatch()方法.这将快速检查一个类是否"可能"匹配切入点表达式或永远不会"定义"匹配.根据AspectJ开发人员使用内部切入点,结果更明确没有.他们还建议永远不要使用独立的切入点(执行,调用,获取,设置),而是将它们与内部结合使用.
但是,无法共享shadowMatchCache,因为它包含匹配结果或每个切入点表达式不匹配.
但至少你可以限制缓存的内容.我还认为,一旦applicationContext启动,Spring就可以通过不保留整个缓存来改进这一点.当新的bean在已经启动后动态添加到applicationContext时,他们可能会抛弃所有不匹配,而牺牲重做一些匹配.
AspectJExpressionPointcut类中另一个可能的内存是pointCutParser.可以在applicationContext中的所有AspectJExpressionPointcuts中共享此解析器.在JIRA机票SPR-7678上获取战利品.