AOP核心概念
1、横切关注点
对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
2、切面(aspect)
类是对物体特征的抽象,切面就是对横切关注点的抽象
3、连接点(joinpoint)
被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
4、切入点(pointcut)
对连接点进行拦截的定义
5、通知(advice)
所谓通知指的就是指拦截到连接点之后要执行的代码,通知(advice)分为前置(before)、后置(after)、异常(after throwing)、最终(after return)、环绕(around)通知五类
6、目标对象
代理的目标对象
7、织入(weave)
将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction)
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
Spring对AOP的支持
详看下面的例子:
@Aspect
@Component
public class TestAop {
// 定义切点
@Pointcut("execution(* com.example..*(..))")
public void pointcut1(){}
// 定义带参数名的切点
@Pointcut(value = "execution(* com.example..*(com.example.beans.UserInfo)) && args(userInfo)",argNames = "userInfo")
public void pointcut2(UserInfo userInfo){}
// 定义切点
@Pointcut("!target(com.example.beans.UserInfo+) && execution(* get(..))")
public void pointcut3(){}
// 定义前置advice,使用 pointcut1 ,参数 JoinPoint 可省略,@Before,@After,@AfterReturning,@AfterThrowing 都可以带这个参数
@Before("pointcut1()")
public void testBefore(JoinPoint joinPoint){
// do something...
}
// 定义最终advice(代码应该是在finally块,最终都会执行),使用 pointcut2
@After(value = "pointcut2(orderDTO)",argNames = "orderDTO")
public void testAfter(OrderDTO orderDTO){
// do something...
}
// 定义返回后advice(方法返回时执行),使用pointcut1,带有返回值对象
@AfterReturning(value = "pointcut1()",returning = "response")
public void testAfterReturning(Response response){
// do something...
}
// 定义异常后advice(抛出异常时执行),使用使用pointcut1,带有异常对象
@AfterThrowing(value = "pointcut1()",throwing = "e")
public void testAfterThrowing(GlobalException e){
// do something...
}
// 定义环绕advice,携带参数ProceedingJoinPoint
@Around("pointcut1()")
public Object testAround(ProceedingJoinPoint pjp) throws Throwable {
// do something...
Object retVal = pjp.proceed(); // 真正方法处理过程
// do something...
return retVal;
}
@DeclareParents(value="com.sunjie.User",//为这个类添加接口
defaultImpl=BoySex.class)//默认实现类
public Sex sex; //实现的接口
}
通配符
*:匹配任意字符,只能匹配一个元素
..:匹配任意字符,可以匹配多个元素
+:按类型匹配指定类的所有类,必须在类名后面,继承或者扩展指定类的所有类,也包括本身
逻辑运算符
&&(and):与操作,切点的交集
||(or):或操作,切点的并集
! (not):非操作,切点的反集
//匹配com.sunjie包下所有的get方法
@Before("within(com.sunjie.*) && execution(* get(..))")
//匹配所有get方法,但是其类非User类型
@Before("!target(com.sunjie.User+) && execution(* get(..))")
//匹配所有User类型或者Teacher类型的类的方法
@Before("target(com.sunjie.User+) || target(com.sunjie.Teacher")
类型签名表达式
为了方便类型(如接口、类名、包名)过滤方法,Spring AOP 提供了within关键字。其语法格式如下:
within(<type name>)
type name 则使用包名或者类名替换即可,来点案例吧。
//匹配com.zejian.dao包及其子包中所有类中的所有方法
@Pointcut("within(com.zejian.dao..*)")
//匹配UserDaoImpl类中所有方法
@Pointcut("within(com.zejian.dao.UserDaoImpl)")
//匹配UserDaoImpl类及其子类中所有方法
@Pointcut("within(com.zejian.dao.UserDaoImpl+)")
//匹配所有实现UserDao接口的类的所有方法
@Pointcut("within(com.zejian.dao.UserDao+)")
方法签名表达式
如果想根据方法签名进行过滤,关键字execution可以帮到我们,语法表达式如下
//scope :方法作用域,如public,private,protect,不指定则为 *
//returnt-type:方法返回值类型,所有类型则为 *
//fully-qualified-class-name:方法所在类的完全限定名称
//parameters 方法参数
execution(<scope> <return-type> <fully-qualified-class-name>.*(parameters))
对于给定的作用域、返回值类型、完全限定类名以及参数匹配的方法将会应用切点函数指定的通知,这里给出模型案例:
//匹配UserDaoImpl类中的所有方法
@Pointcut("execution(* com.zejian.dao.UserDaoImpl.*(..))")
//匹配UserDaoImpl类中的所有公共的方法
@Pointcut("execution(public * com.zejian.dao.UserDaoImpl.*(..))")
//匹配UserDaoImpl类中的所有公共方法并且返回值为int类型
@Pointcut("execution(public int com.zejian.dao.UserDaoImpl.*(..))")
//匹配UserDaoImpl类中第一个参数为int类型的所有公共的方法
@Pointcut("execution(public * com.zejian.dao.UserDaoImpl.*(int , ..))")
其他指示符
bean : Spring AOP扩展的,AspectJ没有对于指示符,用于匹配特定名称的Bean对象的执行方法;
//匹配名称中带有后缀Service的Bean。
@Pointcut("bean(*Service)")
private void myPointcut1(){}
this : 用于匹配当前AOP代理对象类型的执行方法;请注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配
//匹配了任意实现了UserDao接口的代理对象的方法进行过滤
@Pointcut("this(com.zejian.spring.springAop.dao.UserDao)")
private void myPointcut2(){}
target : 用于匹配当前目标对象类型的执行方法;
//匹配了任意实现了UserDao接口的目标对象的方法进行过滤
@Pointcut("target(com.zejian.spring.springAop.dao.UserDao)")
private void myPointcut3(){}
@within : 用于匹配所以持有指定注解类型内的方法;请注意与within是有区别的, within是用于匹配指定类型内的方法执行;
//匹配使用了MarkerAnnotation注解的类(注意是类)
@Pointcut("@within(com.zejian.spring.annotation.MarkerAnnotation)")
private void myPointcut4(){}
@annotation : 根据所应用的注解进行方法过滤
//匹配使用了MarkerAnnotation注解的方法(注意是方法)
@Pointcut("@annotation(com.zejian.spring.annotation.MarkerAnnotation)")
private void myPointcut5(){}
ok~,关于表达式指示符就介绍到这,我们主要关心前面几个常用的即可,不常用过印象即可。这里最后说明一点,切点指示符可以使用运算符语法进行表达式的混编,如and、or、not(或者&&、||、!),如下一个简单例子:
//匹配了任意实现了UserDao接口的目标对象的方法并且该接口不在com.zejian.dao包及其子包下
@Pointcut("target(com.zejian.spring.springAop.dao.UserDao) !within(com.zejian.dao..*)")
private void myPointcut6(){}
//匹配了任意实现了UserDao接口的目标对象的方法并且该方法名称为addUser
@Pointcut("target(com.zejian.spring.springAop.dao.UserDao)&&execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..))")
private void myPointcut7(){}
网友评论