文章目录
Aop作用
面向切面编程,以无侵入的方式,使一组类共享相同的行为。
- 相关术语:
- Aspect切面: 多个位置的同一功能,每个切面都侧重于一个特定的横切功能。
- Joinpoint连接点: 横切功能的执行点
- Advice通知: 横切面执行的具体功能,前置、后置、环绕、异常、最终通知
- Pointcut切点: 用以匹配连接点的正则表达式。每当任何连接点匹配一个切入点时,就执行该切入点相关联的指定通知。
- Weaving织入: 链接切面和目标对象来创建一个通知对象的过程。
- Joinpoint连接点: 横切功能的执行点
- Aspect切面: 多个位置的同一功能,每个切面都侧重于一个特定的横切功能。
JDK动态代理: Spring AOP的首选方法,在Spring中的对象实现某一接口,就会使用JDK动态代理。利用反射机制生成一个实现代理接口的匿名类。
CGLIB代理: 当对象没有实现接口时,使用此动态代理方式。将对象的class文件加载进来,修改其字节码生成子类,相当于继承。
- 在Spring中,使用Aspect注解
@Aspect @Component class LogAspect{ 1.within表达式匹配包类型 //匹配类中所有的方法 @Pointcut("within(com.zp.ProductServiceImpl)") public void matchClass(){} //匹配包中所有类的全部方法 @Pointcut("within(com.zp.daoPackage..)") public void matchPackage(){} 2.this、target、bean表达式匹配对象类型 //匹配以 AOP对象的目标对象 为 指定类型 的方法 //如ShopServiceImpl的 @Pointcut("this(com.zp.ShopServiceImpl)") public void matchThis(){} //匹配实现该接口的目标对象 @Pointcut("target(com.zp.ShopService)") public void matchTarget(){} //匹配所有以Service结尾的bean的全部方法 @Pointcut("bean(*Service)") public void matchBean(){} 3.使用args表达式匹配参数,用于获取方法中的参数。 //匹配第一个参数为Long类型的方法,将 @Pointcut("args(Long,*)") public void matchArgs(){} 4.使用匹配注解 //匹配注解了@test的方法 @Pointcut("@annotation(com.zp.annotation.test)") public void matchAnno(){} //匹配注解了@test的类的所有方法,要求级别为CLASS @Pointcut("@within(com.zp.annotation.test)") public void matchAnnoWithin(){} //匹配注解了@test的类下的所有方法,要求级别为RUNTIME @Pointcut("@target(com.zp.annotation.test)") public void matchAnnoTarget(){}; //匹配传入的参数 注解了@test 的方法 @Pointcut("@args(com.zp.annotation.test)") public void matchAnnoArgs(){} 5.使用Execution表达式 //execution(modifier-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?) //modifier-pattern 访问修饰符 可省 //ret-type-pattern 返回值类型 *所有类型、全路径类名、普通类型 不可省 //declaring-type-pattern 类路径 可省 //name-pattern 方法名 *所有方法、set*或*set模糊匹配 不可省 //param-pattern 参数类型 具体类型,多个类型用“,“隔开;*一个任意类型参数;..表示0个或多个任意类型参数。不可省 //throws-pattern 异常类型匹配 可省 @Pointcut("execution(public * com.zp.ShopServiceImpl *(String,*) *)") public void matchExecution(){} 通知Advice //@After 切点正常运行结束后执行,若切点抛出异常,则在抛出异常前执行。 //@AfterThrowing 切点抛出异常后,执行。 //@AfterReturning 切点正常结束后执行,若切点异常则不执行。 //@Around 可以在切入点执行前后自定义一些操作。环绕通知需要负责决定是继续处理join point(调用ProceedingJoinPoint的proceed方法)还是中断执行。在执行ProceedingJoinPoint对象的proceed方法前相当于Before前置通知;执行proceed方法相当于运行切入点(同时可以获取参数);在方法执行之后相当于After后置通知,如果运行切入点抛出异常,则catch中的内容相当于AfterThrowing异常通知;finally中的内容无论切入点是否抛出异常,都将执行 //@Before 运行前执行 @Before("matchExecution()") public void doBefore(JoinPoint jp){ .... } @Around("matchAll()") public Object around(ProceedingJoinPoint joinPoint) { Object result = null; authService.checkAccess(); System.out.println("befor 在切入点执行前运行"); try{ result = joinPoint.proceed(joinPoint.getArgs());//获取参数 System.out.println("after 在切入点执行后运行,result = " + result); } catch (Throwable e) { System.out.println("after 在切入点执行后抛出exception运行"); e.printStackTrace(); } finally { System.out.println("finally......"); } return result; } }
- XML配置方式
//JoinPoint连接对象
class AopAspect{
public void doBefore(JoinPoint jp){
System.out.println("前置通知");
}
public void doAfterReturning(JoinPoint jp,String result){
System.out.println("执行后,后置通知");
}
public void doAfterThrowing(JoinPoint jp,Excetion ex){
System.out.println("产生异常后执行");
}
public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("前置通知");
//调用proceed()执行切入点方法执行
Object result = pjp.proceed();
System.out.println("后置通知");
return result;
}
public void doAfter(JoinPoint jp){
System.out.println("最终通知");
}
}
<beans>
<bean id="aopAspect" class="AopAspect" />
<aop:config>
<aop:aspect ref="aopAspect">
<aop:pointcut id="pointcut" expression="execution(public * com.zp.ShopService.. *(..))" />
<aop:before method="doBefore" pointcut-ref="pointcut" />
<aop:after method="doAfter" pointcut-ref="pointcut" />
<aop:after-returning method="doAfterReturning" pointcut-ref="point-cut" return="result" />
<aop:after-throwing method="doAfterThrowing" pointcut-ref="pointcut"
throwing="ex" />
<aop:around method="doAround" pointcut-ref="pointcut" />
</aop:aspect>
</aop:config>
</beans>
- JoinPoint:包装了切面方法的相关信息。
interface JoinPoint{
//完成Method和Advice的执行
Object proceed() throws Throwable;
//获取代理的对象
Object getThis();
//获取代理的静态部分(代理的方法)
AccessibleObject getStaticPart();
}
- Spring AOP与AspectJ
Spring AOP是AOP的简单实现,只能在Spring框架中使用。AspectJ是完整的AOP实现方式且有自己的织入编译器。
Spring Aop可以使用AspectJ的注解功能,但实质上的底层的实现是Spring Aop。- Spring AOP织入方式:运行时织入,故此效率低。JDK动态代理时需要实现特定的接口;CGLIB代理时,不能织入使用final与static修饰的类和方法。
- AspectJ织入方式:编译时织入,AspectJ编译器同时加载切面代码和源程序生成一个织入后的文件输出;编译后织入,即二进制织入,用以编织现有的类文件和JAR文件与切面;加载时织入,与二进制织入一样,不同的是织入延后,直到类加载器加载到JVM。
故此,AaspectJ比Spring Aop快的多