Spring AOP面向切面编程详解

前言

AOP即面向切面编程,是一种编程思想,OOP的延续。在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等等。在阅读本文前希望您已经对Spring有一定的了解

注:在能对代码进行添加注解方式实现AOP的话,并不推荐使用XML方式。换言之在XML方式配置更适用于不能对代码添加注解的情况下(注解配置方式推荐值>XML配置方式推荐值)

AOP相关术语

1.通知(Advice):在切面的某个特定的连接点上执行的动作,即当程序到达一个执行点后会执行相对应的一段代码,也称为增强处理。通知共有如下5种类型[前置通知 后置通知 返回通知 环绕通知 抛出异常后通知]

2.连接点(JoinPoint):程序执行的某个特定位置,例如类初始化前,类初始化后,方法执行前,方法执行后,方法抛出异常时等,Spring只支持方法级别的连接点,即方法执行前,方法执行后,方法抛出异常时

3.切入点(Pointcut):切入点是一个筛选连接点的过程,因为在你的工程中可能有很多连接点,你只是想让其中几个,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法

4.切面(Aspect):切面通常是指一个类,是通知和切入点的结合。到这里会发现连接点就是为了让你好理解切点产生的。通俗来说切面的配置可以理解为:什么时候在什么地方做什么事。切入点说明了在哪里干(指定到方法),通知说明了什么时候干什么

5.引入(Introduction):引入允许我们向现有的类添加新方法或属性

6.织入(Weaving):把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:
    (1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器
    (2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码
    (3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术

基于XML方式配置AOP

正常通知

1.编写业务类

public class HelloWorldBusiness {
    public String sayHelloWorld(String language) {
        String result = "Hello World " + language;
        System.out.println("真正的业务方法执行啦~~~");
        return result;
    }
}

2.编写切面类

public class HelloWorldBusinessAspect {
    public void beforeSayHelloWorld(String language) {
        System.out.println("执行方法前运行,参数为:" + language);
    }

    public void afterSayHelloWorld(String language) {
        System.out.println("执行方法后运行,参数为:" + language);
    }

    public void afterReturningSayHelloWorld(String language, String result) {
        System.out.println("执行方法返回后运行,参数为:" + language + " 方法返回值为:" + result);
    }

    public void afterThrowingHelloWorld(String language, Throwable e) {
        System.out.println("执行方法抛出异常后运行,参数为:" + language + "异常为:" + e);
    }
}

3.编写配置文件

<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <!-- 配置业务Bean -->
    <bean id="helloWorldBusiness" class="roberto.growth.process.aop.HelloWorldBusiness" />

    <!-- 配置切面Bean -->
    <bean id="helloWorldBusinessAspect" class="roberto.growth.process.aop.HelloWorldBusinessAspect" />

    <!-- 配置一个切面 -->
    <aop:config>
        <aop:aspect id="helloWorldAspect" ref="helloWorldBusinessAspect">
            <!-- 配置一个切点 -->
            <aop:pointcut id="sayHelloWorldPoint" expression="execution(public * roberto.growth.process.aop.HelloWorldBusiness.sayHelloWorld(..)) and args(language)" />
            <!-- 配置前置通知 -->
            <aop:before pointcut-ref="sayHelloWorldPoint" method="beforeSayHelloWorld" arg-names="language"/>
            <!-- 配置前置通知 -->
            <aop:after pointcut-ref="sayHelloWorldPoint" method="afterSayHelloWorld" arg-names="language"/>
            <!-- 配置后置返回通知 -->
            <aop:after-returning pointcut-ref="sayHelloWorldPoint" method="afterReturningSayHelloWorld" arg-names="language,result" returning="result" />
            <!-- 异常通知 -->
            <aop:after-throwing pointcut-ref="sayHelloWorldPoint" method="afterThrowingHelloWorld" arg-names="language,e" throwing="e" />
        </aop:aspect>
    </aop:config>
</beans>

4.运行HelloWorldBusiness的sayHelloWorld方法输出结果为

执行方法前运行,参数为:JAVA
真正的业务方法执行啦~~~
执行方法后运行,参数为:JAVA
执行方法返回后运行,参数为:JAVA 方法返回值为:Hello World JAVA

环绕通知

1.编写业务类

public class HelloWorldBusiness {
    public String sayHelloWorld(String language) {
        String result = "Hello World " + language;
        System.out.println("真正的业务方法执行啦~~~");
        return result;
    }
}

2.编写切面类

public class HelloWorldBusinessAspect {
    public void aroundSayHelloWorld(ProceedingJoinPoint joinPoint) {
        String language = (String) joinPoint.getArgs()[0];
        try {
            System.out.println("执行方法前运行,参数为:" + language);
            String result = (String) joinPoint.proceed();
            System.out.println("执行方法后运行,参数为:" + language + " 方法返回值为:" + result);
        } catch (Throwable e) {
            System.out.println("执行方法抛出异常后运行,参数为:" + language + "异常为:" + e);
        }
    }
}

3.编写配置文件

<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <!-- 配置业务Bean -->
    <bean id="helloWorldBusiness" class="roberto.growth.process.aop.HelloWorldBusiness" />

    <!-- 配置切面Bean -->
    <bean id="helloWorldBusinessAspect" class="roberto.growth.process.aop.HelloWorldBusinessAspect" />

    <!-- 配置一个切面 -->
    <aop:config>
        <aop:aspect id="helloWorldAspect" ref="helloWorldBusinessAspect">
            <!-- 配置一个切点 -->
            <aop:pointcut id="sayHelloWorldPoint" expression="execution(public * roberto.growth.process.aop.HelloWorldBusiness.sayHelloWorld(..))" />
            <!-- 配置环绕通知 -->
            <aop:around pointcut-ref="sayHelloWorldPoint" method="aroundSayHelloWorld" />
        </aop:aspect>
    </aop:config>
</beans>

4.运行HelloWorldBusiness的sayHelloWorld方法输出结果为

执行方法前运行,参数为:JAVA
真正的业务方法执行啦~~~
执行方法后运行,参数为:JAVA 方法返回值为:Hello World JAVA

使用MethodInterceptor实现AOP

1.编写业务类

public class HelloWorldBusiness {
    public String sayHelloWorld(String language) {
        String result = "Hello World " + language;
        System.out.println("真正的业务方法执行啦~~~");
        return result;
    }
}

2.编写拦截器类 实现MethodInterceptor方法

public class HelloWorldBusinessAspect implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // 获取被增强对象参数列表
        String language = (String) invocation.getArguments()[0];
        // 获取被增强对象的方法
        Method method = invocation.getMethod();
        // 继续执行业务方法
        System.out.println("执行" + method.getName() + "方法前运行,参数为: " + language);
        Object result = invocation.proceed();
        System.out.println("执行方法返回后运行,参数为:" + language + " 方法返回值为:" + result);
        return result;
    }
}

3.编写配置文件

<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

    <!-- 配置业务Bean -->
    <bean id="helloWorldBusiness" class="roberto.growth.process.aop.HelloWorldBusiness" />

    <!-- 配置切面Bean -->
    <bean id="helloWorldBusinessAspect" class="roberto.growth.process.aop.HelloWorldBusinessAspect" />

    <aop:config>
        <!-- 配置一个切点 -->
        <aop:pointcut id="sayHelloWorldPoint" expression="execution(public * roberto.growth.process.aop.HelloWorldBusiness.sayHelloWorld(..))" />

        <!-- 配置通知类 -->
        <aop:advisor advice-ref="helloWorldBusinessAspect" pointcut-ref="sayHelloWorldPoint" />
    </aop:config>
</beans>

4.运行HelloWorldBusiness的sayHelloWorld方法输出结果为

执行sayHelloWorld方法前运行,参数为: JAVA
真正的业务方法执行啦~~~
执行方法返回后运行,参数为:JAVA 方法返回值为:Hello World JAVA

基于注解方式配置AOP

正常通知

1.编写业务类

@Component
public class HelloWorldBusiness {
    public String sayHelloWorld(String language) {
        String result = "Hello World " + language;
        System.out.println("真正的业务方法执行啦~~~");
        return result;
    }
}

2.编写切面类

@Aspect
@Component
public class HelloWorldBusinessAspect {
    @Pointcut("execution(public * roberto.growth.process.aop.HelloWorldBusiness.sayHelloWorld(..)) && args(language)")
    public void sysHelloWorldPointCut(String language) {

    }

    @Before("sysHelloWorldPointCut(language)")
    public void beforeSayHelloWorld(String language) {
        System.out.println("执行方法前运行,参数为:" + language);
    }

    @After("sysHelloWorldPointCut(language)")
    public void afterSayHelloWorld(String language) {
        System.out.println("执行方法后运行,参数为:" + language);
    }

    @AfterReturning(pointcut = "sysHelloWorldPointCut(language)", returning = "result")
    public void afterReturningSayHelloWorld(String language, String result) {
        System.out.println("执行方法返回后运行,参数为:" + language + " 方法返回值为:" + result);
    }

    @AfterThrowing(pointcut = "sysHelloWorldPointCut(language)", throwing = "e")
    public void afterThrowingHelloWorld(String language, Throwable e) {
        System.out.println("执行方法抛出异常后运行,参数为:" + language + "异常为:" + e);
    }
}

3.编写配置类(使用EnableAspectJAutoProxy注解启用自动代理功能,即aspectJ的cglib代理方式)

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "roberto.growth.process")
public class ApplicationConfig {

}

4.运行HelloWorldBusiness的sayHelloWorld方法输出结果为

执行方法前运行,参数为:JAVA
真正的业务方法执行啦~~~
执行方法后运行,参数为:JAVA
执行方法返回后运行,参数为:JAVA 方法返回值为:Hello World JAVA

环绕通知

1.编写业务类

@Component
public class HelloWorldBusiness {
    public String sayHelloWorld(String language) {
        String result = "Hello World " + language;
        System.out.println("真正的业务方法执行啦~~~");
        return result;
    }
}

2.编写切面类

@Aspect
@Component
public class HelloWorldBusinessAspect {
    @Pointcut("execution(public * roberto.growth.process.aop.HelloWorldBusiness.sayHelloWorld(..))")
    public void sysHelloWorldPointCut() {

    }

    @Around("sysHelloWorldPointCut()")
    public void aroundSayHelloWorld(ProceedingJoinPoint joinPoint) {
        String language = (String) joinPoint.getArgs()[0];
        try {
            System.out.println("执行方法前运行,参数为:" + language);
            String result = (String) joinPoint.proceed();
            System.out.println("执行方法后运行,参数为:" + language + " 方法返回值为:" + result);
        } catch (Throwable e) {
            System.out.println("执行方法抛出异常后运行,参数为:" + language + "异常为:" + e);
        }
    }
}

3.编写配置类(使用EnableAspectJAutoProxy注解启用自动代理功能,即aspectJ的cglib代理方式)

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "roberto.growth.process")
public class ApplicationConfig {

}

4.运行HelloWorldBusiness的sayHelloWorld方法输出结果为

执行方法前运行,参数为:JAVA
真正的业务方法执行啦~~~
执行方法后运行,参数为:JAVA 方法返回值为:Hello World JAVA

转载:https://blog.csdn.net/RobertoHuang/article/details/70148474

原文地址:https://www.cnblogs.com/cainiao-Shun666/p/9176843.html

时间: 2024-10-11 12:56:03

Spring AOP面向切面编程详解的相关文章

AOP 面向切面编程详解

引言 对类(class)增强的手段通常分为以下三类 1.继承  子类通过继承父类或者实现接口对类进行增强 2.装饰者模式(Wrapper) 常用于对类的某个方法进行重写,以实现更强大的功能.常用于场合缓冲流,Struct2中StructRequestWarpper类   实现准则:是你还有你,一切全靠你 3.动态代理 一句话概括:获取实现了一组接口的类对象 需提供目标对象,增强建议  三大参数 :ClassLoader Class[] interfaces InvocationHandler  

深入探索spring技术内幕(七): 配置Spring AOP面向切面编程

一. AOP一些概念 Aspect( 切面 ): 指横切性关注点的抽象即为切面, 它与类相似, 只是两者的关注点不一样, 类是对物体特征的抽象, 而切面横切性关注点的抽象. joinpoint( 连接点 ): 指那些被拦截到的点. 在spring中, 这些点指的是方法, 因为spring只支持方法类型的连接点, 实际上joinpoint还可以是field或类构造器) Pointcut( 切入点 ): 指我们要对那些joinpoint进行拦截的定义. Advice( 通知 ): 指拦截到joinp

浅谈Spring AOP 面向切面编程 最通俗易懂的画图理解AOP、AOP通知执行顺序~

简介 我们都知道,Spring 框架作为后端主流框架之一,最有特点的三部分就是IOC控制反转.依赖注入.以及AOP切面.当然AOP作为一个Spring 的重要组成模块,当然IOC是不依赖于Spring框架的,这就说明你有权选择是否要用AOP来完成一些业务. AOP面向切面编程,通过另一种思考的方式,来弥补面向对象编程OOP当中的不足,OOP当中最重要的单元是类,所以万物皆对象,万物皆是 对象类.而在AOP的模块单元中,最基础的单元是切面,切面对切点进行模块化的管理. 最后再提一句:Spring当

Spring AOP 面向切面编程

AOP 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. 在Spring中提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例

spring AOP面向切面编程学习笔记

一.面向切面编程简介: 在调用某些类的方法时,要在方法执行前或后进行预处理或后处理:预处理或后处理的操作被封装在另一个类中.如图中,UserService类在执行addUser()或updateUser方法前开启事务,执行完后要提交事务:而几乎所有数据库操作都是如此,那么就可以将事务操作的方法提取出封装到一个类里.然后再利用代理类进行处理(目标类方法增强),返回代理类对象 二.AOP相关术语 Target:目标类,需要被增强的类. JoinPoint:连接点,目标类上需要被增强的方法.(这些方法

【Spring系列】Spring AOP面向切面编程

前言 接上一篇文章,在上午中使用了切面做防重复控制,本文着重介绍切面AOP. 在开发中,有一些功能行为是通用的,比如.日志管理.安全和事务,它们有一个共同点就是分布于应用中的多处,这种功能被称为横切关注点(cross-cutting concerns). DI(依赖注入)有助于应用对象之间的解耦,而AOP可以实现横切关注点与他们所影响的对象之间的解耦. 面向切面编程在Spring AOP中有4种类型的调用,方法调用的之前.后.异常增加其他方法,方法调用的前和后调用其他方法,将方法中的参数传递给其

十二.Spring AOP面向切面编程

什么是AOP? AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. AOP的第一个案例 要求:使用AOP实现日志记录功能,核心模块和增强单独开发,运行时组装 1.创建接口HelloDao.HelloService. 创建接口类HelloDaoImpl.HelloServiceImpl并实现dao层接口 public interface IHolleDao { public void print

从源码入手,一文带你读懂Spring AOP面向切面编程

之前<零基础带你看Spring源码--IOC控制反转>详细讲了Spring容器的初始化和加载的原理,后面<你真的完全了解Java动态代理吗?看这篇就够了>介绍了下JDK的动态代理. 基于这两者的实现上,这次来探索下Spring的AOP原理.虽然AOP是基于Spring容器和动态代理,但不了解这两者原理也丝毫不影响理解AOP的原理实现,因为大家起码都会用. AOP,Aspect Oriented Programming,面向切面编程.在很多时候我们写一些功能的时候,不需要用到继承这么

Spring AOP(面向切面编程)

AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理.日志管理.权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性. 简单例子:在某个项目里,非管理员不能对某些业务进行操作,代码如下: 从上面的代码我们可以看出这种方式达到了权限验证的功能,但是如果有100个方法的话,就会显得冗余,代码不好维护,这是传统的硬编码方式 我们对代码进行改进(以注解的方式) 1,新建一个切面(Aspect) @Pointcut是切入点,我需要切入那