zoukankan      html  css  js  c++  java
  • AOP小结

    一. AOP 底层原理

    AOP 底层使用动态代理,分为两种情况:

    • 有接口,使用 JDK 动态代理
    • 无接口,使用 CGLIB 动态代理

    二. AOP 术语

    1. 连接点:类中可以被增强的方法
    2. 切入点:实际被增强的方法
    3. 通知(增强):实际增强的逻辑部分。分为前置通知、后置通知、环绕通知、异常通知、最终通知
    4. 切面:把通知应用到切入点的过程

    三. AOP 操作

    Spring 一般基于 AspectJ 实现 AOP 操作,可基于 xml 实现,也可基于注解实现(常用)

    1. 切入点表达式

    语法结构:execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))

    // 例一:对 Book 类的 add 方法进行增强,*表示任意修饰符(public,private...),返回类型可以省略
    execution(* com.dao.Book.add(..))
    // 例二:对 Book 类所有方法进行增强
    execution(* com.dao.Book.*(..))
    // 例三:对 dao 包里所有的所有方法进行增强
    execution(* com.dao.*.*(..))
    

    2. 基于注解(重点)

    基本步骤

    (1)在spring 配置文件中开启注解扫描

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!--开启注解扫描-->
        <context:component-scan base-package="com.aop.anno"/>
    
    </beans>
    

    (2)使用注解加载类的 bean,并在增强类上添加 @Aspect 注解

    package com.aop.anno;
    
    import org.springframework.stereotype.Component;
    
    // 被增强的类
    @Component
    public class User {
    
        void add() {
            System.out.println("增加了一个用户");
        }
    }
    
    package com.aop.anno;
    
    import org.springframework.stereotype.Component;
    
    // 增强类
    @Component
    @Aspect  // 生成代理对象
    public class UserProxy {
    
        @Before("execution(* com.aop.anno.User.add(..))")
        public void before() {
            System.out.println("before...");
        }
        
        // 最终通知,发生异常也执行
        @After("execution(* com.aop.anno.User.add(..))")
        public void after() {
            System.out.println("after...");
        }
        
        // 后置(返回)通知,触发 afterThrowing 不执行
        @AfterReturning("execution(* com.aop.anno.User.add(..))")
        public void afterReturning() {
            System.out.println("afterReturning...");
        }
        
        @Around("execution(* com.aop.anno.User.add(..))")
        public void around(ProceedingJoinPoint pj) throw Throwable {
            System.out.println("环绕前");
            pj.process();
            // try {
            //    pj.proceed();
            // } catch (Throwable throwable) {
            //    throwable.printStackTrace();
            // }
            System.out.println("环绕后");
            
        }
        
        // 有异常才执行
        @AfterThrowing("execution(* com.aop.anno.User.add(..))")
        public void afterThrowing() {
            System.out.println("afterThrowing...");
        }
        
    }
    

    (3) 在 spring 配置文件中开启生成代理对象

    <aop:aspectj-autoproxy/>
    

    (4) 测试

    public void text() {
    	ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        User user = context.getBean("user", User.class);
        user.add();	  // 先输出 before...,再输出 hhh 
    }
    

    执行结果

    环绕前
    before......
    增加了一个用户
    环绕后
    after........
    afterReturning
    

    如果在 add 方法中引发了异常,则执行结果为:

    环绕前
    before......
    after........
    afterThrowing......
    

    注意如果在 around 方法中异常没有被抛出而是在方法体内被处理,则不会执行 afterThrowing 方法,此时执行结果为:

    环绕前
    before......
    环绕后
    after........
    afterReturning
    

    如果将上面的 around 方法注释掉,则引发异常后结果为:

    before......
    after........
    afterThrowing......
    

    相同切入点抽取

    @Pointcut("execution(* com.kuang.service.UserServiceImpl.*(..))")
    public void pointdemo() {}
    
    @Before("pointdemo()")
    public void before() {
        System.out.println("before......");
    }
    
    @After("pointdemo()")
    public void after() {
        System.out.println("after........");
    }
    

    多个增强类的优先级

    在增强类上添加 Order(int v) 注解,v 越小优先级越高

    完全注解开发

    创建配置类,不需要 xml 配置文件

    @Configuration
    @Component(basePackages = {"com.pojo"})
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class ConfigAop{}
    

    使用和 IOC 的完全注解开发一样

    3. 基于配置文件

    <!--增强类-->
    <bean id="diy" class="com.kuang.diy.DiyPointCut"/>
    
    <aop:config>
        <!--   切入点   -->
        <aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
            
        <!--  自定义切面,ref 为增强类   -->
        <aop:aspect ref="diy">
            <!--  通知  -->
            <aop:before method="before111" pointcut-ref="point"/>
            <aop:after method="after111" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
    
    你只有十分努力,才能看上去毫不费力。
  • 相关阅读:
    Android音视频学习第7章:使用OpenSL ES进行音频解码
    使用cordova+Ionic+AngularJs进行Hybird App开发的环境搭建手冊
    简单脱壳教程笔记(8)---手脱EZIP壳
    linux CentOS安装telnet
    【H.264/AVC视频编解码技术具体解释】十三、熵编码算法(4):H.264使用CAVLC解析宏块的残差数据
    C# 爬取网页上的数据
    ML(1): 入门理论
    ES(6): access elasticsearch via curl
    ES(5): ES Cluster modules settings
    ES(4): ES Cluster Security Settings
  • 原文地址:https://www.cnblogs.com/214txdy/p/15024961.html
Copyright © 2011-2022 走看看