美文网首页
spring aop

spring aop

作者: 万物归于简 | 来源:发表于2019-02-19 16:17 被阅读0次

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(){} 

相关文章

网友评论

      本文标题:spring aop

      本文链接:https://www.haomeiwen.com/subject/fazxyqtx.html