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..
    ):包含子包

  • 相关阅读:
    PythonのTkinter基本原理
    使用 Word (VBA) 分割长图到多页
    如何使用 Shebang Line (Python 虚拟环境)
    将常用的 VBScript 脚本放到任务栏 (Pin VBScript to Taskbar)
    关于 VBScript 中的 CreateObject
    Windows Scripting Host (WSH) 是什么?
    Component Object Model (COM) 是什么?
    IOS 打开中文 html 文件,显示乱码的问题
    科技发展时间线(Technology Timeline)
    列置换密码
  • 原文地址:https://www.cnblogs.com/sonng/p/6596510.html
Copyright © 2011-2022 走看看