7.4Spring AOP概念及示例

AOP:Aspect-Oriented Programming。AOP是OOP的补充,是GOF的延续。我们知道设计模式是对于面向对象设计中经验的总结,它孜孜不断追求的就是调用者与被调用者之间的解耦。有了设计模式我们可以更有效的利用面向对象的特性,使得整个软件设计更加灵活、优雅。但是设计模式是基于面向对象的思想而形成的,更多的时候关注的是对象层次的东西,在解决对象行为内部问题方面却有些不足。AOP的出现恰恰就是对面向对象思想做出了完美的补充。

说到AOP,我们就不得不来提一下软件的纵向和横向问题。从纵向结构来看就是我们软件系统的各个模块,它主要负责处理我们的核心业务(例如商品订购、购物车查看);而从横向结构来看,我们几乎每个系统又包含一些公共模块(例如权限、日志模块等)。这些公共模块分布于我们各个核心业务之中(例如订购和查看商品明细的过程都需要检查用户权限、记录系统日志等)。这样一来不仅在开发过程中要处处关注公共模块的处理而且开发后维护起来也是十分麻烦。而有了AOP之后将应用程序中的商业逻辑同对其提供支持的通用服务进行分离,使得开发人员可以更多的关注核心业务开发。

AOP的主要应用场景

AOP在系统开发中应用非常广泛,常见场景如下:

  • 事务处理
  • 日志处理
  • 异常处理
  • 权限控制
  • 系统性能监控
  • 其他

AOP的核心概念

1、横切关注点
对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点

2、切面(aspect)
类是对物体特征的抽象,切面就是对横切关注点的抽象

3、连接点(joinpoint)
被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器

4、切入点(pointcut)
对连接点进行拦截的定义

5、通知(advice)
所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类

6、目标对象代理的目标对象

7、织入(weave)
将切面应用到目标对象并导致代理对象创建的过程

8、引入(introduction)
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段

Spring对AOP的支持

Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:

1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了

2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB

AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:

  • 1、定义普通业务组件
  • 2、定义切入点,一个切入点可能横切多个业务组件
  • 3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作
    所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。

基于Spring的AOP简单实现

这里以注解的方式来实现AOP,更贴近现在的使用

pom.xml添加依赖

 <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.3.3.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
        </dependency>
    </dependencies>

这里面需要引用spring的几个jar包,包括core、beans、context、aop,还要引用aspectjweaver这个

定义要切入的业务类,这里简单定义一个新增方法即可

@Service
public class UserService {

    public void add() {
        System.out.println("新增数据成功");
    }
}

applicationContext.xml

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       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.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <context:annotation-config/>
    <!-- spring从该包下面自动扫描组件 -->
    <context:component-scan base-package="com.critc"/>
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <bean class="com.critc.aop.LogAspect"/>

</beans>

这里面最核心的两句是

   <aop:aspectj-autoproxy proxy-target-class="true"/>
    <bean class="com.critc.aop.LogAspect"/>

启用AOP,且定义一个切入类是com.critc.aop.LogAspect

定义切面程序LogAspect.java

@Aspect
public class LogAspect {

    /**
     * 方法开始前执行
     */
    @Before("execution(* com.critc.service..*.*(..)) ")
    private void beforeMethod() {
        System.out.println("the Method begins........");
    }

    /**
     * 方法结束后执行
     */
    @After("execution(* com.critc.service..*.*(..)) ")
    private void afterMethod() {
        // TODO Auto-generated method stub
        System.out.println("The Method after ................");
    }

    /**
     * 返回后执行
     * @param joinPoint
     * @param result
     */
    @AfterReturning(value = "execution(* com.critc.service..*.*(..)) ", returning = "result")
    public void AfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("The Method after ................" + result);
    }

    /**
     * 抛出异常执行
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(value = "execution(* com.critc.service..*.*(..)) ", throwing = "e")
    public void AfterThrowing(JoinPoint joinPoint, Exception e) {
        System.out.println("The Method afterThrowing................"
                + e.getMessage().toString());
    }

    /**
     * 环绕执行
     * @param pjp
     * @return
     */
    @Around(value = "execution(* com.critc.service..*.*(..)) ")
    public Object aroundTest(ProceedingJoinPoint pjp) {
        String methodName = pjp.getSignature().getName();
        Object object = null;
        try {
            // 前置通知
            System.out.println("The Method " + methodName + "before................");
            // object = pjp.proceed();
            object = "view/index";
            // 返回通知
            System.out.println(object);
        } catch (Throwable e) {
            // TODO Auto-generated catch block
            // 异常通知
            System.out.println(e.getMessage().toString());
        }
        System.out.println("The Method " + methodName + "after................");
        return object;
    }
}

上面这个例子把aop的大概例子讲了一下,后面我会详细讲述Spring AOP在实际中的应用,比如异常处理、日志处理、权限控制。

源码下载

本工程详细源码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 团队开发框架实战—面向切面的编程 AOP 引言 软件开发的目标是要对世界的部分元素或者信息流建立模型,实现软件系统...
    Bobby0322阅读 9,703评论 4 49
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,282评论 19 139
  • 本章内容: 面向切面编程的基本原理 通过POJO创建切面 使用@AspectJ注解 为AspectJ切面注入依赖 ...
    谢随安阅读 8,546评论 0 9
  • 什么是Spring Spring是一个开源的Java EE开发框架。Spring框架的核心功能可以应用在任何Jav...
    jemmm阅读 16,733评论 1 133
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,593评论 11 349

友情链接更多精彩内容