zoukankan      html  css  js  c++  java
  • 0047 Spring的AOP入门基础--切面组件--通知--切入点

    AOP的全称是Aspect Oriented Programming,面向切面编程。

    切面是什么呢,就是一个Java类。之所以叫切面,就是说在调用其他一些类的方法的某个时候(之前,之后,抛异常等),调用这个类里的某个方法,因为要对很多类的很多方法进行相同的作用,就像一刀切一样。

    aop涉及到三个要素:将哪个类的哪个方法,在什么时候,切入到哪个类的哪个方法上。依次对应了切面组件Aspect、通知Advice、切入点pointcut

    看下面的示例,一个Controller组件,一个Service组件,两个Aspect组件,一个测试类,代码如下:

    //Controller组件
    package net.sonng.controller;
    
    import javax.annotation.Resource;
    
    import net.sonng.service.TestService;
    
    import org.springframework.stereotype.Controller;
    
    @Controller
    public class TestController {
        @Resource
        private TestService ts;
        public void testA(){
            System.out.println("Controller的testA方法开始执行");
            ts.testA();
            ts.testB();
        }
        
        public void testB(){
            System.out.println("Controller的testB方法开始执行");
        }
    }
    
    
    
    //Service组件
    package net.sonng.service;
    
    import org.springframework.stereotype.Service;
    
    @Service
    public class TestService {
        public void testA (){
            System.out.println("TestService的TestA方法开始执行");
        }
        
        public void testB(){
            System.out.println("TestService的TestB方法开始执行");
        }
    }
    
    
    //切面A
    package net.sonng.aspect;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.stereotype.Component;
    
    @Component
    public class TestLogA {
        public void log(){
            System.out.println("TestLogA是切面组件,切入点是Controller的方法前面");
        }
    }
    
    
    //切面B
    package net.sonng.aspect;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    
    @Component
    @Aspect
    public class TestLogB {
        
        @Before("execution(* net.sonng.service.TestService.testA(..))")   //方法限定表达式
        public void log(){
            System.out.println("TestLogB是切面组件,在调用Service方法前调用");
        }
    }
    
    
    //测试类
    package net.sonng.test;
    
    import net.sonng.controller.TestController;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
        public static void main(String[] args){
            ApplicationContext ac=new ClassPathXmlApplicationContext("ac.xml");
            TestController tc=ac.getBean("testController",TestController.class);
            tc.testA();
            tc.testB();
            
        }
    }
    
    

    采用xml配置,TestLogA的log方法在Controller组件的所有方法调用前调用

    ac.xml配置如下:

    <mvc:annotation-driven />   <!-- 开启注解扫描 -->
    <context:component-scan base-package="net.sonng" />  <!-- 开启组件扫描 -->
    <aop:aspectj-autoproxy />                            <!-- 开启AOP注解扫描 -->
    
    <bean id="log" class="net.sonng.aspect.TestLogA"></bean>  <!-- 声明切面组件 -->
    <aop:config>
        <aop:aspect ref="log" >                               <!-- 以log为切面组件 -->
            <aop:before method="log" pointcut="within(net.sonng.controller.TestController)"/>
        </aop:aspect>    <!-- aop:before是前置通知;method表示要调用的切面的方法;pointcut表示切入点,可以用类型/方法限定表达式 -->
    </aop:config> 
    <!-- 这个xml配置表示:在net.sonng.controller.TestController下的所有方法被调用前,先调用net.sonng.aspect.TestLogA的log方法 -->
    

    用注解配置,TestLogB的log方法在TestService的testA()方法调用前调用

    注解配置见代码,要点如下:
    1. 用@Aspect声明TestLogB是一个切面组件
    2. 在log方法前添加@Before注解,这是前置通知
    3. 在@Before注解的属性中指定切入点,这里用的是方法限定表达式

    测试类输出如下:

    TestLogA是切面组件,切入点是Controller的方法前面 //TestLogA的log方法在Controller的testA()方法前调用
    Controller的testA方法开始执行
    TestLogB是切面组件,在调用Service方法前调用 //TestLogB的log方法在Service的testA()方法前调用
    TestService的TestA方法开始执行
    TestService的TestB方法开始执行 //因为TestLogB的log方法指定了只在testA前调用,在testB前不调用
    TestLogA是切面组件,切入点是Controller的方法前面 //TestLogA的log方法在Controller的testB()方法前调用
    Controller的testB方法开始执行

    切面组件Aspect

    切面组件一般是登录检查、日志记录、事务管理等
    xml配置中先声明bean,再在aop:config的aop:aspect中指定为切面
    或者用@Aspect注解指定

    通知advice

    通知就是:在调用目标方法的什么时候调用切面组件的方法,可以是:
    前置通知:@Before,方法调用之前
    后置通知:@AfterReturning,方法正常返回
    异常通知:@AfterThrowing,方法调用过程中出现异常
    最终通知:@After,不管方法是正常返回还是出现异常,这个通知都会调用,因此必须这两种可能的情况
    环绕通知:@Around,

    切入点

    切入点就是要在哪些类的哪些方法上进行切入,可以限定一些类下的所有方法,或者不同类下的一些方法,或者指定类下的指定方法
    方法限定表达式:
        基本模式:execution([修饰符] 返回值类型 方法名(参数) [异常类型])。具体见Spring Reference 4.3.6版第223页
        execution(public * * (..)):所有 的public方法
        execution(* set(..)):以set打头的任意方法
        execution(
    com.xyz.service.SomeService.(..):SomeService类下的任意方法
        execution(
    com.xyz.service..(..)):service包下的任意类的任意方法
    类型限定表达式:
        within(com.xyz.service.):service包下的任意类下的任意方法,不包含子包
        within(com.xyz.service..
    ):包含子包

  • 相关阅读:
    Hibernate Validator
    RocketMQ之八:重试队列,死信队列,消息轨迹
    使用hibernate validator出现
    Hibernate Validator--创建自己的约束规则
    Java应用中使用ShutdownHook友好地清理现场、退出JVM的2种方法
    笔者带你剖析轻量级Sharding中间件——Kratos1.x
    [caffe]深度学习之图像分类模型VGG解读
    类的载入机制
    机器人api(图灵机器人)
    回文串问题总结
  • 原文地址:https://www.cnblogs.com/sonng/p/6596510.html
Copyright © 2011-2022 走看看