zoukankan      html  css  js  c++  java
  • Spring(二)——AOP

    1.概念

    面向切面编程 即 新加的代码不会影响原来的,像切入一样。

    2.AspectJ导入包

    com.springsoure.net.sf.cglib

    com.springsoure.org.aopalliance

    com.springsoure.org.aspectj.weaver

    spring-aop

    spring-aspects

    3.五种通知

    • before:前置通知,在一个方法执行前被调用,@Before
    • after: 在方法执行之后调用的通知,无论方法执行是否成功,即最终通知,@After
    • after-returning: 仅当方法成功完成后执行的通知,@AfterReturning
    • after-throwing: 在方法抛出异常退出时执行的通知,@AfterThrowing
    • around: 在方法执行之前和之后调用的通知,@Around

    实现条件,用@Aspect修饰通知(切面)类,被通知类和通知类 都用@Component修饰,在XML文件里用扫描包全部扫一下就好了

    使用@Aspect注解需要添加aop命名空间,然后用<aop:aspectj-autoproxy /> 开启自动代理功能。

    对于要织入的通知需要用上面5种注解之一来织入,对于同一个方法可以有多个通知,注解的属性value 需要指明 修饰符-返回值-哪个包下的哪个类的哪个方法名-参数类型。解析切入点,例如

    @Before(value = "execution(public void com.atguigu.spring.aop.Dog.say(int))")

    @before修饰的是切面类里要织入的方法,而不是被通知的方法。

    这类切面编程需要加载配置文件,通过IOC来实现,不可以直接new对象。

    看一下代码:

    package com.atguigu.spring.aop;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    @Component
    @Aspect
    public class MyAOP {
        //将方法指定为前置通知,需要加这个属性
        @Before(value = "execution(public void com.atguigu.spring.aop.Dog.say(int))")
        public void before() {
            System.out.println("前置通知");
        }
    }

    切面类MyAOP,用@Aspect修饰,表明切面编程,@Componet修饰表示用了IOC技术,在配置文件里能加载。

    package com.atguigu.spring.aop;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    
    @Component
    public class Dog {
        public void say(int x) {
            System.out.println("狗叫"+x+"次");
        }
    }

    被通知类Dog,用@Componet修饰表示用了IOC技术,在配置文件里能加载。

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     4      
     5     xmlns:p="http://www.springframework.org/schema/p"
     6     xmlns:util="http://www.springframework.org/schema/util"
     7     xmlns:context="http://www.springframework.org/schema/context"
     8     xmlns:aop="http://www.springframework.org/schema/aop"
     9     xsi:schemaLocation="
    10     http://www.springframework.org/schema/beans 
    11      http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
    12      
    13      http://www.springframework.org/schema/util
    14      http://www.springframework.org/schema/util/spring-util.xsd
    15      
    16      http://www.springframework.org/schema/context 
    17      http://www.springframework.org/schema/context/spring-context-4.3.xsd
    18      
    19      http://www.springframework.org/schema/aop
    20      http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
    21      
    22      ">
    23      
    24      <context:component-scan base-package="com.atguigu.spring.aop" ></context:component-scan>
    25     <!-- 开启自动代理功能,即启动注解声明功能-->
    26     <aop:aspectj-autoproxy /> 
    27     
    28     
    29     
    30 </beans>

    配置文件aop.xml中第8,19,20行是aop命名空间需要配置的东西。24行是扫描包,26行是启动注解声明功能。

    package com.atguigu.spring.aop;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
    
        public static void main(String[] args) {
            Dog dog=new Dog();
            dog.say(11);
            ApplicationContext ac=new ClassPathXmlApplicationContext("aop.xml");
            Dog dog2=ac.getBean("dog",Dog.class);
            dog2.say(110);
        }
    }
    /*通知
    狗叫11次
    前置通知
    狗叫110次
    */

    测试类Test的main方法用new和IOC的方法执行 类 被前置通知的方法,效果不同,其他通知类似如此。

    4.切入点表达式

    一个通知方法作用于很多个类或者多个方法,可以用*匹配。

    例如@Before(value = "execution(* com.atguigu.spring.aop.*.*(..))");

    修饰符和返回值合并成1个*,不可以用2个,所有类可以用一个*,所有方法可以用一个*,所有参数类型用[..]匹配。

    可重用的切入点表达式是 在切面类里 使用一个返回值为void,方法体为空的方法例如myPointCut()来命名切入点,被通知方法需要加上@Before("myPointCut()")这样的注解,可以通过加JoinPoint类型的参数来查看被通知的类是哪个,被通知的方法是哪个。

    示例如下:

    package com.atguigu.spring.aop;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    @Component
    @Aspect
    public class MyAOP {
        @Pointcut(value = "execution(* com.atguigu.spring.aop.*.*(..))")
        private void myPointCut() {
        }
    
        @Before(value = "myPointCut()")
        public void before() {
            System.out.println("这是前置通知");
        }
        
        @AfterThrowing(value="myPointCut()",throwing="e")
        public void afterThrowing(JoinPoint joinPoint,Throwable e) {
            System.out.println("被通知的类是:"+joinPoint.getTarget());
            System.out.println("被通知的方法是:"+joinPoint.getSignature().getName());
            System.out.println("异常了,这是异常通知"+e.getMessage());
        }
    }

    获取参数名:Object[] args=joinPoint.getArgs();

    对于异常通知,参数类型也可以是Exception或者具体异常类型,但是要匹配。

    对于环绕通知,参数类型必须是ProceedingJoinPoint,它是JoinPoint的子类。

    5.切面优先级

    对于同一连接点应用不止一个切面类时,除非明确确定,否则他们的优先级是不确定的。可以通过@Order(x)注解来指定,对于x越小的,优先级越高

    6.通过XML配置文件声明切面类和通知方法

    即不同在Java文件里写@Aspect,@Before之类的注解,全都在XML里写,例如

        <aop:config>
            <aop:aspect ref="MyAOP">
                <aop:pointcut expression="execution(* com.atguigu.spring.aop.*.*(..))" id="myPointCut"/>
                    <aop:before method="myBefore" pointcut-ref="myPointCut"/>
            </aop:aspect>
            
        </aop:config>

    看着都麻烦,还是用注解吧。


    学习资源:B站尚硅谷Spring视频。

  • 相关阅读:
    单调队列+二分 G
    dp cf 1700 最近几天的刷题
    dp 20190618
    dp 20190617
    dp cf 20190615
    dp cf 20190614
    powercli
    zabbix docker-weixin
    cenetos-大文件排序
    esxcli命令
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/12737739.html
Copyright © 2011-2022 走看看