zoukankan      html  css  js  c++  java
  • Spring-AOP

    Spring-AOP

    1. AOP 基本概念

    显示中有一些内容并不是面向对象技术(OOP)可以解决的,比如事务处理。在 JDBC 代码中,最繁琐的问题就是无穷无尽的 try ... catch ... finally ... 语句 和 数据库资源关闭 的问题,而且代码会存在大量的重复,而你又不能不写。

    一个正常执行的 SQL 的逻辑步骤如下:

    1. 打开通过数据库连接池获得数据库链接资源,并做一定的设置工作。
    2. 执行对应的 SQL 语句(通常是增删改),对数据进行操作。
    3. 如果 SQL 执行过程中发生异常,回滚事务。
    4. 如果 SQL 执行过程中没有发生异常,最后提交事物。
    5. 到最后的阶段,需要关闭一些连接资源。

    参看上述流程,你会发现无论是执行什么具体的 SQL,流程都是一样的!即,到了特定时刻一定会执行某个特定操作,并不因 SQL 的不同而不同 !

    在 OOP 中,模块化单元是『类』(Class),而在 AOP 中,模块化的单元是『 切面』(Aspect)。

    AOP 最早由 AOP 联盟的组织提出的,并制定了一套规范。Spring AOP 遵守 AOP 联盟的规范。

    Spring 的 AOP 的底层用到两种代理机制:

    1. JDK 动态代理

      如果目标类遵循某个接口,Spring AOP 底层采用 JDK 方案生成代理对象

    2. Cglib 动态代理

      如果目标类不遵循任何接口,Spring AOP 底层采用 cglib 方案生成代理对象。

    2. 核心概念

    AOP 涉及到如下问题:在 什么类什么方法什么地方,做出 什么样 的增强。AOP 的功能简而言之就是:在不修改方法源文件的情况下,为源文件的特定部位增加新的代码

    2.1. 切入点表达式

    切入点表达式决定了哪些类的哪些方法会被『插入』新代码。它『回答』了对 什么类什么方法 做出增强。

    最常用的切入点表达式是 execution 表达式,其语法格式如下:

    [方法访问修饰符] 方法返回值 包名.类名.方法名(方法的参数)
    

    『方法访问修饰符』部分是可选部分;『其它』部分是必要部分。

    例如:

    execution( * com.demo.dao.EmployeeDao.*(..) )
    
    execution( public * demo.dao.EmployeeDao.*(..) )
    
    execution( public String demo.dao.EmployeeDao.*(..) )
    
    execution( public String demo.dao.EmployeeDao.*(String, ..) )
    
    execution( * demo.dao.*.*(..) )
    
    • 返回值匹配:

      可以为 *,表示任何返回值,全路径的类名等。

    • 方法名匹配:

      指定方法名。

      例如:* 代表所有方法; set*,代表以 set 开头的所有方法.

    • 参数匹配:

      指定方法参数(数量、类型及顺序)。

      例如:(..) 代表所有参数;(*) 代表一个参数; (*, String) 代表第一个参数为任何值,第二个为 String 类型。

    2.2. 通知类型

    通知类型回答了 什么位置 增强 什么样 的代码。

    注解 通知 说明
    @Before 在被代理对象的方法前调用
    @Around 将被代理方法封装起来 环绕通知,它将覆盖原有方法,但是允许通过反射调用原有方法
    @After 在被代理对象方法后调用
    @AfterReturning 在被代理对象正常返回后调用 要求被代理对象的方法执行过程中没有发生异常
    @AfterThrowing 在被代理对象的方法抛出异常后调用 要求被代理对象的方法执行过程中发生异常

    Spring 只支持方法拦截 。

    3. 使用 @AspectJ 注解配置 Spring AOP

    Spring 实现 AOP 功能的方式有两种:@AspectJ 注解 方式,要求会写;XML 配置 方式要求会看。

    补充,AOP 概念并非 Spring 所特有,Spring 也并非支持 AOP 编程的唯一框架。在 Spring 之前提供 AOP 功能的,具有里程碑式的框架叫 AspectJ 框架。AspectJ 框架的使用方式比较独特(不简便),在 Spring AOP 出现后就慢慢被 Spring AOP 所取代。但是,AspectJ 框架设计了一套注解,非常简便和合理,并且被广大 AspectJ 的使用者所熟知,所以 Spring AOP 直接借用这套注解,也就是我们这里所说的 @AspectJ 注解。

    由于 @AspectJ 注解是 Spring『借用』的别人的注解,所以使用时需要引入它。

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
    
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
    

    在 Spring 的配置文件中,也需要引入/声明 AOP 的 namspace :

    <beans
        ...
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="
            ...
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd">
    

    并且,由于 @AspectJ 注解并非 Spring 框架的一部分,所以需要在配置文件中声明 『启用 @AspectJ 注解』 功能,否则,Spring 并『不认识』 @AspectJ 的一系列注解。

    <aop:aspectj-autoproxy />
    
    <!-- 或者使用 @Component 注解 + 包扫描 -->
    <bean id="dept" class="bean.Dept" />
    <bean id="aspect1" class="bean.DeptAspect1" />
    

    再重复一遍,使用 Spring AOP 的核心问题:在 什么类什么方法什么地方,做出 什么样 的增强。

    @Aspect // 注意,不要忘记在切面类的头上加 @Aspect 注解。
    public class DeptAspect1 {
    
        @Before("execution(* bean.Dept.sayHi(..))")
        public void before() {
            System.out.println("before ...");
        }
    
        @After("execution(* bean.Dept.sayHi(..))")
        public void after() {
            System.out.println("after ...");
        }
    
        @Around("execution(* bean.Dept.sayHi(..))")
        public void around(ProceedingJoinPoint jp) {
            System.out.println("hello");
            try {
                jp.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
            }
            System.out.println("world");
        }
    
        @AfterReturning("execution(* bean.Dept.sayHi(..))")
        public void afterReturuing() {
            System.out.println("afterReturning ...");
        }
    
        @AfterThrowing("execution(* bean.Dept.sayHi(..))")
        public void afterThrowing() {
            System.out.println("afterThrowing ...");
        }
    }
    

    可以发现,上述代码中 execution(...) 部分有大量重复现象。为此,可以提供一个 @Pointcut 来进行“缩写”。

    @Aspect
    public class DeptAspect1 {
    
        @Pointcut("execution(* bean.Dept.sayHi(..))")
        public void xxx() {  // 这个方法是空的。需要的不是它的内容,需要的是它的名字。
        }
    
        @Before("xxx()")
        public void before() { ... }
    
        @After("xxx()")
        public void after() { ... }
    
        @Around("xxx()")
        public void around() { ... }
    
        @AfterReturning("xxx())")
        public void afterReturning() { ... }
    
        @AfterThrowing("xxx())")
        public void afterThrowing() { ... }
    }
    

    另外,有时你要拦截/增强的方法是有参数的,例如:

    public void sayHi(String name, int age) { ... }
    

    为此,你也可以在增强方法中获得这些参数,

    @Pointcut("execution(* bean.Dept.sayHi(..))")
    public void xxx() {}
    
    @Before("execution(* bean.Dept.sayHi(..)) && args(name, age)")
    public void before(String name, int age) {
        ...
    }
    
    @After("xxx() && args(name, age)")
    public void after(String name, int age) {
        ...
    }
    

    4. 使用 XML 配置 Spring AOP

    通过 XML 配置 Spring AOP 功能,在 XML 文件中出现的各种『要素』本质上和 @AspectJ 注解中出现过的内容本质上并没有两样。

    public class DeptAspect2 {
        public void before() { ... }
        public void after() { ... }
        public void around(ProceedingJoinPoint jp) { ... }
        public void afterReturuing() { ... }
        public void afterThrowing() { ... }
    }
    
    <bean id="dept" class="bean.Dept" />
    <bean id="aspect2" class="bean.DeptAspect2" />
    
    <aop:config>
        <aop:aspect ref="aspect2">
            <aop:before method="before" pointcut="execution(* bean.Dept.sayHi(..)) and args(name, int)"/>
            <aop:after method="after" pointcut="execution(* bean.Dept.sayHi(..)) and args(name, int)"/>
        </aop:aspect>
    </aop:config>
    
  • 相关阅读:
    hive与hbase整合
    待重写
    hive DML
    【知识强化】第六章 总线 6.1 总线概述
    【知识强化】第五章 中央处理器 5.1 CPU的功能和基本结构
    【知识强化】第四章 指令系统 4.3 CISC和RISC的基本概念
    【知识强化】第四章 指令系统 4.2 指令寻址方式
    【知识强化】第四章 指令系统 4.1 指令格式
    【知识强化】第三章 存储系统 3.6 高速缓冲存储器
    【知识强化】第三章 存储系统 3.5 双口RAM和多模块存储器
  • 原文地址:https://www.cnblogs.com/whitespaces/p/12442429.html
Copyright © 2011-2022 走看看