基本概念
切点(Pointcut)
切点是定位到某个程序方法的条件,一个切点可以匹配多个方法,
连接点(Joinpoint)
每个程序都有多个连接点,连接点是程序中客观存在的事物,
是方法执行前后,等包括方位信息的具体程序执行点,
切点只定位到方法上,要定位到具体连接点上,还需要提供方位信息,就是那些before,after等
切面(Aspect)
切面是由切点是通知(引介)组成,它既包括了横切逻辑的定义,也包括了连接点的定义,
通知(Advice)
是织入到目标类连接点上的一段程序代码目标对象(Target)
通知逻辑的织入目标对象引介(Introduction)
引介是一种特殊的增强,他为类添加一些属性和方法,可以让相关业务动态实现特定的接口,让业务成为接口的实现类
织入(Weaving)
将通知添加到目标类具体连接点的过程根据不同的技术实现,AOP有三种织入方式
编译器织入,要求使用特殊的Java编译器
类装载期织入,这要求使用特殊的类装载器
动态代理织入,在运行期间为目标类,添加通知生成子类的方式
Spring采用动态代理织入,而Aspectj前两种织入
代理(Proxy)
一个类被AOP织入增强后,就产生一个结果类,它是融合了原类和增强逻辑的代理类根据不同的代理方式,代理类既可能是和原生类具有相同的接口的类,也可能是原类的子类,
所以可以采用可原类相同的方式调用代理类
Spring经典AOP框架
当引入声明式和基于注解式的AOP,经典AOP显得过于笨重和复查
切面的配置
基于@Aspectj配置切面(注解切面)
基于Schema配置切面(XML切面)
启用自动代理
<aop:aspectj-autoproxy/>切点配置
通过切点选择连接点切点表达式
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
throws-pattern?)
其中的方法修饰符,方法名修饰符 和 抛出异常是可选的
() 代表没有参数
(*) 代表一个参数,任意类型
(*,String) 代表第一个参数任意类型,第二个是java.lang.String 类型,java.lang包下的可以默认省略包名
(..) 代表任意参数任意个数,任意类型
execution(* com.xyz.service.*.*(..))
the execution of any method defined in the service package:
在 service包下的任意方法
execution(* com.xyz.service..*.*(..))
the execution of any method defined in the service package or a sub-package:
在 service包和它子包下的任意方法
execution(* set*(..))
the execution of any method with a name beginning with "set":
匹配一set开始的方法
within(com.xyz.service.*)
any join point (method execution only in Spring AOP) within the service package:
service包下的所有连接点
bean指示器
bean(*Service)
any join point (method execution only in Spring AOP) on Spring beans having names
匹配bean的名字以Service结尾的beanthat match the wildcard expression *Service:
切点函数
上面有些可以用参数绑定的形式出现
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable {
java.lang.String value();
}
@Auditable(value="xiaoming")
public String getMsg(String str,Integer num){
return str+num;
}
//Auditable是一个自定义注解,getMsg()是目标类的一个方法
@Pointcut("within( com.link..*) && @annotation(auditable) && args(str1,num1)")
private void pointCut(Auditable auditable,String str1,Integer num1){}
@Before(value="pointCut2(auditable2,str2,num2)")
public void before(JoinPoint jp,Auditable auditable2,String str2,Integer num2){
//形参可以使用了
}
args(java.io.Serializable)
execution(* *(java.io.Serializable))
这两个是不同的,args匹配的是函数运行时传入的参数是java.io.Serializable类型
execution匹配的是方法参数声明为java.io.Serializable类型