美文网首页
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