背景
AOP在处理一些共性业务的时候提供了十分便利的扩展性,有着十分广泛的应用场景。
在Java中常用的两种框架主要就是Spring AOP和原生的Aspectj,当然Spring AOP本身也借鉴和引用了很多Aspectj中的东西。
虽然AOP本身的使用很便利,但是在使用中主要还是有以下一些注意点,需要在使用Spring AOP(Aspectj由于了解不多暂不讨论)注意一些很容易被忽略的细节点和原因:
- AOP的切面方法,不能用于private的方法,但是aspectj是可以的;
- AOP是基于代理机制的,虽然可以通过xml声明究竟是使用jdk动态代理还是cglib的动态代理,但是是否可能存在一些场景使得代理不生效呢?
- AOP在作用自身类内部的方法调用的时候,为什么会失效呢?
虽然以上都是很简单的细节点,但是有时候忽略的话,会导致我们很难找到问题点从而改变我们的代码。笔者在实际的基于AOP的项目中就遇到了一些类似的问题。
好吧,终于我还是忍不住了,其实我主要就是来安利一个自己写的基于Annotation的AOP缓存插件的,以上问题是在运用插件的时候可能导致不生效的一些原因!所以我把不生效的原因都写这么具体了,你考虑看一下么?(p.s. 看都看了,不考虑试一下么~ 逃~)
所以,重要的事情说三遍,有兴趣的同学请参考基于基于Annotation的AOP缓存插件:
- 基于注解的AOP缓存插件SimpleCache_Annotation
- 基于注解的AOP缓存插件SimpleCache_Annotation
- 基于注解的AOP缓存插件SimpleCache_Annotation
以下是项目说明:
基于AOP注解实现的缓存插件 在需要缓存的地方使用@SimpleCache注解即可实现缓存
- 提供自定义的expiretime
- 提供多种存储实现
- 通过xml bean和AOP的方式来实现,侵入性小
不过既然为了凑字数,还是写到底吧~ 下面是刚刚三个小问题的答案~
为什么spring AOP不能应用于private方法
其实如果单纯说原因的话,可能主要还是基于安全性的考虑,因为私有的方法从本身机制上来说就应该是不可见的。
当然后来由于反射等的出现,特别是cglib直接能修改字节码这种神器,非要能代理到private的方法也是可以实现的(例如aspectj中就可以达到这个目的),但是这还是从根本上破坏了java对private的定义,因此spring可能考略这些因素,对aop的时候做了一些权限的检验限制,如下代码所示
// 有很多对权限做检验的地方
/**
* Implementation of AOP Alliance MethodInvocation used by this AOP proxy.
*/
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
private final MethodProxy methodProxy;
private final boolean publicMethod;
public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
this.methodProxy = methodProxy;
this.publicMethod = Modifier.isPublic(method.getModifiers());
}
/**
* Gives a marginal performance improvement versus using reflection to
* invoke the target when invoking public methods.
*/
@Override
protected Object invokeJoinpoint() throws Throwable {
if (this.publicMethod) {
return this.methodProxy.invoke(this.target, this.arguments);
}
else {
return super.invokeJoinpoint();
}
}
}
所以,在使用spring AOP的时候需要注意,不要切到private这些方法上去了(别问我怎么知道的……)
是否有存在使得代理失效导致AOP不成功的场景
这种情况主要还是出现于动态代理本身出现了问题导致,主要还是需要我们对动态代理的原理有一个比较好的了解(比如哪种代理是基友哪种实现方式的,以及什么场景下可能会导致无法代理):
jdk动态代理,是jvm自身实现的一个代理,最核心的点在于是一种基于接口的代理,所以如果没有实现接口的话……
cglib代理,核心原理是修改字节码,通过继承来实现代理对象,也就是说如果没法继承(如final修饰符),那么……(此刻补充一句题外话,在上面提到的插件里,设计的时候就是基于cglib的,所以如果你在配置文件里面没有设置使用cglib为true的话……请私信我,我考虑优化一下……)
为什么类的内部使用AOP方法会不走AOP流程
对于这个问题的理解主要还是要对代理方法的主要实现有个理解,如下图所示(图来源于Aspect Oriented Programming with Spring,建议有兴趣的同学可以深入看一下):
代理方法直接上是通过对使用对象的做了一个封装之后,别的所有引入都是通过引用了代理类从而实现走了代理的流程的。那么是否内部调用就没有办法走代理的流程了呢?答案当然是否定的,其实只要在内部调用代理类的方法就可以了(虽然最终实现结果看起来有点奇怪),至于在spring中的实现可以参考之前写的这篇文章AOP切面时BeanPostProcessor返回Bean未被CGlib代理
后记
都看到这里,不点进项目链接里面看看么?(逃~)