1.环绕通知
Proceedingjoinpoint 和JoinPoint的区别:
Proceedingjoinpoint 继承了JoinPoint,Proceedingjoinpoint 实际上就是执行中的连接点,例如:
class A {
public void query(){}
public void query2(){}
}
那么query和query2会被增强,那么Proceedingjoinpoint就是用来描述当前正在执行的这个query或者query2.
proceed()这个是aop代理链执行的方法。并扩充实现了proceed()方法,用于继续执行连接点。JoinPoint仅能获取相关参数,无法执行连接点。Proceedingjoinpoint能够调用这个方法没直接执行原方法,比如你增强了query,那么调用了proceed就是调用了原来的query方法。
JoinPoint的方法
1.java.lang.Object[] getArgs():获取连接点方法运行时的入参列表;
2.Signature getSignature() :获取连接点的方法签名对象;
3.java.lang.Object getTarget() :获取连接点所在的目标对象;
所以gettarget拿到的是目标对象,也就是增强之前的对象。
4.java.lang.Object getThis() :获取代理对象本身;我们可以看到,在JoinPoint里面有一个getThis方法,这个方法能够获取到当前对象,没错,就是增强后的,被偷天换日的代理对象了。所以这里又会扯到jdk动态代理和gclib。
在before里面,断点执行一下gettarget,可以得到一个jdk动态代理的对象,足以说明,getthis拿到的是代理后的对象。
proceed()有重载,有个带参数的方法,可以修改目标方法的的参数。
什么意思呢?假设现在要增强的query方法是带参数的query =》 query(String str)
然后proceed你可以这样去调用 =》 proceed() 这样的话,不会传入任何参数,参数会默认取最上层调用者的参数。什么意思?比如你把一个class A交给了spring管理,在某个时间点,你拿出这个A,调用了query方法,传入str=“1”,然后spring去执行这个query,第一个点就是会到达这个proceed这个地方,如果proceed没有使用重载的带参的proceed方法的话,那么参数默认就是str=“1”。如果使用了带参的proceed,可以动态改变其参数。如下:
2.DeclareParents
这个注解的作用实际上就是在不改变原有对象的基础上去新增一些功能
value可以指定一个包名,或者指定一个接口(指定接口需要使用+来指定)。引入指定的包或者指定的接口的所有实现类,
拿到接口Dao的一个实现类IndexDao,把IndexDao里面的方法增强到指定的包或者指定的接口的所有实现类中。
实际上就是给对应的类,去实现那个接口,你实现接口的话,具体的方法的实现,就需要去指定的实现类里面去拿。
3.通知+切点写在一起
通知上面直接写切点,但是感觉不建议这样写,因为一般操作的话,会把连接点和切点写到一个类,把通知写到一个类。
而不会把两个东西揉在一起,复用性不高。
4.多实例切面
有时候,我们的实例是property,但是切面默认却是单例的,这样的话,可能会造成一些问题,所以我们需要对不同的代理对象,切面也要做一个对应的多实例变换。
这样设置之后,当遇到增强的对象是IndexDao,就会生成不同的切面来做增。
这里可以看到,这里设置的是一个切点,也就是一但遇到这些切点,直接生成不同的切面来切入。