AOP主要用于日志记录,性能统计,安全控制(权限控制),事务处理,异常处理等。将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,经过对这些行为的分离,咱们但愿能够将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
Spring AOP织入加强(Advice)的方式有两种 若是链接点实现了接口采用jdk自带的动态代理的形式实现织入,若是链接点没有实现接口则采用动态字节码生成技术(CGLIB)实现织入。git
加强程序执行的某个特定位置(要在哪一个地方作加强操做)。Spring仅支持方法的链接点,既仅能在方法调用前,方法调用后,方法抛出异常时等这些程序执行点进行织入加强。github
切点是一组链接点的集合。AOP经过“切点”定位特定的链接点。经过数据库查询的概念来理解切点和链接点的关系再适合不过了:链接点至关于数据库中的记录,而切点至关于查询条件。正则表达式
加强是织入到目标类链接点上的一段程序代码。表示要在链接点上作的操做。spring
切面由切点和加强(引介)组成(能够包含多个切点和多个加强),它既包括了横切逻辑的定义,也包括了链接点的定义,SpringAOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。数据库
@Aspect public class LogAspect { @Pointcut("execution(* com.ctj.service.*.*(..))") public void pointcutName(){} @Before("pointcutName()") public void performance(){ System.out.println("Spring AOP"); } }
咱们如何在定义切点(Pointcut)的时候指定一类Joinpoint呢?有两种方式 简单的方法名指定以及正则表达式两种方式。编程
Spring AOP仅支持方法执行类型的Joinpoint 因此execution将会是咱们用的最多的标志符,用它来帮咱们匹配拥有指定方法前面的Joinpoint。匹配规则以下:
execution(modifiers-pattern? return-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern)安全
方法的返回类型 方法名及参数部分的匹配模式是必须指定的 其余部分能够省略。
咱们还能够在表达式中使用两种通配符:*和..
第一:*能够用于任何部分的匹配模式中,匹配相邻的多个字符,即一个Work 。若是放在了方法参数的位置标示参数是任何类型的。
例如:execution(* *(String))
第二:..通配符能够在两个位置使用 一个是declaring-type-pattern的位置,一个是在方法参数匹配模式的位置。
若是是放在了方法类型的位置,能够指定多个层次的类型声明。例如:
execution(void cn.spring.*.doSomething(*)) 指定到cn.spring下的全部类型。
若是是放在了方法参数的匹配位置,则表示该方法能够有0到多个参数。例如:
execution(void *.doSomething(..))框架
within标志符只接受类型声明,它将匹配指定类型下全部的Joinpoint。
例如:within(cn.spring.aop.target.*) 将会匹配 cn.spring.aop.target包下全部类型的方法级别的Joinpoint。性能
使用@annotation标志符会检查系统中全部对象的全部方法级别Joinpoint,若是被检测的方法标注有@annotation标志符所指定的注解类型,那么当前方法所在的Joinpoint将被Pointcut表达式匹配。例如:@pointcut("@annotation(com.test.aop.log.ALog)") 匹配全部使用了ALog注解的方法。spa
匹配表达式的维度有不少 上面只是一小部分经常使用的,而且这些维度是能够组合的 使用||或者$$等等
例如:@around("within(com.test.finance..*) && @annotation(com.test.finance.platform.intf.base.db.ReadOnly)")
在定义Advice的时候 咱们匹配的维度能够直接写定义有@pointcut的方法名称 也能够直接使用定义@joinpoint的那一套东西来直接定义要在哪些地方织入(能够直接在Advice上指定匹配哪些方法)
定义完切面以后咱们要在spring中注册这个切面类,为了让spring能自动帮咱们实现织入 咱们还须要开启自动注入 在spring配置文件中:<aop:aspectj-autoproxy proxy-target-class="true"/> 这样spring就能在IOC容器找到全部要织入的方法 动态帮咱们织入。
业务类代码:
package com.ctj.service; import org.springframework.stereotype.Service; @Service public class BusinessService { public void say(){ System.out.println("Business Code"); } }
切面类定义:
package com.ctj.aspect; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class LogAspect { @Pointcut("execution(* com.ctj.service.*.*(..))") public void pointcutName(){} @Before("pointcutName()") public void performance(){ System.out.println("Spring AOP"); } }
spring-aop.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd"> <aop:aspectj-autoproxy proxy-target-class="true"/> <bean id="logAspect" class="com.ctj.aspect.LogAspect"> </bean> </beans>
基于注解的Spring AOP须要JDK1.5版本之后才能使用,以前的版本须要使用基于Schema也就是配置文件的形式来实现,若是jdk版本高的话 建议仍是使用注解的形式。