Spring框架 AOP(三)

AOP理论概述

Aspect Oriented Programming 面向切面编程

业界 AOP 实际上 OOP (面向对象编程 ) 延伸 —- OOP编程语言、 AOP设计思想

AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存

横向抽取代码复用,基于代理技术,在不修改原有对象代码情况下,对原有对象方法功能进行增强! ———- AOP 思想

Spring框架如何实现AOP

Spring1.2 版本开始 开始支持AOP技术 (传统Spring AOP )

Spring2.0之后,为了简化AOP开发,开始支持 AspectJ (第三方框架)AOP 框架

学习重点: AspectJ AOP开发

1.3.AOP相关术语

1.Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.

2.Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.

3.Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)

4.Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.

5.Target(目标对象):代理的目标对象

6.Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程.

7.spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入

8.Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

9.Aspect(切面): 是切入点和通知(引介)的结合

AOP底层实现

Spring AOP 代理实现有两种: JDK动态代理 和 Cglib框架动态代理

JDK动态代理

JDK API 内置 —- 通过 Proxy类,为目标对象创建代理 (必须面向接口代理 )

public class JdkProxyFactory implements InvocationHandler {
    // 被代理对象
    private Object target;

    // 在构造方法对象时,传入被代理对象
    public JdkProxyFactory(Object target) {
        this.target = target;
    }

    // 创建代理
    public Object createProxy() {
        // 三个参数: 类加载器、 实现接口、 invocationhandler
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("记录日志!!!!!!");
        // 调用目标真实方法
        // target 被代理对象, args 方法参数 , method 被调用的方法
        return method.invoke(target, args);
    }
}

缺点: 使用Jdk动态代理,必须要求target目标对象,实现接口 ,如果没有接口,不能使用Jdk动态代理 。

Cglib 动态代理

CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。

Cglib 不但可以对接口进行代理,也可以对目标类对象,实现代理 (解决了 Jdk 只能对接口代理问题 )

下载网址: http://sourceforge.net/projects/cglib/files/

——- 在spring3.2版本 core包中内置cglib 类

public class CglibProxyFactory implements MethodInterceptor {
    // 被代理目标对象
    private Object target;

    // 在构造工厂时传入被代理对象
    public CglibProxyFactory(Object target) {
        this.target = target;
    }

    // 创建代理对象方法
    public Object createProxy() {
        // 1、 创建Enhancer对象
        Enhancer enhancer = new Enhancer();

        // 2、 cglib创建代理,对目标对象,创建子类对象
        enhancer.setSuperclass(target.getClass());

        // 3、传入 callback对象,对目标增强
        enhancer.setCallback(this);

        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("记录日志......");
        // 按照JDK编程
        return method.invoke(target, args);
    }
}

Cglib 创建代理思想: 对目标类创建子类对象

设置 superClass 对哪个类创建子类 (类似 JDK代理 接口)

设置 callback 实现增强代码 (类似 JDK代理 InvocationHandler )

在cglib的callback函数中,要执行被代理对象的方法

method.invoke(target, args); 等价于 methodProxy.invokeSuper(proxy, args);

优先对接口代理 (使用JDK代理),如果目标没有接口,才会使用cglib代理 !

Spring AOP 编程

传统SpringAOP 通知类型(Spring1.2版本 开始)

首先: AOP联盟定义 Advice 通知接口

org.aopalliance.aop.Interface.Advice

然后: Spring AOP 在Advice 接口基础上,扩充为五种通知类型

通过AspectJ 引入Pointcut切点定义

第一步: 实现aop编程,在项目引入 jar包

?com.springsource.org.aopalliance-1.0.0.jar AOP联盟定义规范jar包

?spring-aop-3.2.0.RELEASE.jar Spring对象AOP Advice扩展

?com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar AspectJ框架jar包

?spring-aspects-3.2.0.RELEASE.jar Spring对AspectJ支持 jar包

第二步: 配置文件 ,引入aop名称空间

<?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.xsd">

第三步: 编写Advice

/**
 * 自定义环绕通知 (传统spring AOP Advice)
 *
 * @author seawind
 *
 */
public class MyMehtodInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("环绕前增强====================");
        // 调用目标方法
        Object result = methodInvocation.proceed();
        System.out.println("环绕后增强====================");
        return result;
    }
}

第四步: 定义PointCut 切面

execution(* cn.itcast.service...(..)) 拦截service包包含子包下所有类所有方法

execution(* .s(..)) 拦截以s开头的方法

<!-- 配置目标对象 -->
    <bean id="orderService" class="cn.itcast.spring.c_aop.OrderServiceImpl" />

    <!-- 配置自定义Advice(传统) -->
    <bean id="mymethodadvice" class="cn.itcast.spring.c_aop.MyMehtodInterceptor" />

    <!-- 配置切面 -->
    <!-- 进行aop相关配置 -->
    <aop:config>
        <!--
            aop:advisor: 定义spring传统AOP的切面的, 只支持一个PointCut和 一个Advice
            aop:aspect : 定义AspectJ框架切面的 ,可以包含多个PointCut 和 多个Advice
            aop:pointcut : 切点定义
         -->
         <aop:pointcut expression="execution(* cn.itcast.spring.c_aop.OrderServiceImpl.*(..))" id="mypointcut"/>
         <aop:advisor advice-ref="mymethodadvice" pointcut-ref="mypointcut"/>
    </aop:config>

总结:

AOP Advisor ==== 传统Spring AOP Advice(一个) + 切点(一个)

AspectJ AOP 编程

AspectJ 是一个框架 (第三方AOP框架 ),提供切面编程 ,编写一个Aspect 支持多个Advice和多个PointCut 。

AspectJ 通知类型

相比Spring通知类型,多了一种 After 最终通知

Before前置通知

在目标方法执行前 进行增强代码

AspectJ 提供Advice无需实现任何借口, 可以将很多通知代码 写入一个类 (切面类)

前置通知定义方法: 无返回值,可以传入参数 JoinPoint 连接点

public class MyAspect {
    public void before1() {
        System.out.println("前置通知 1.....");
    }

细节:

1、 默认不能阻止目标方法执行,如果抛出异常,目标方法无法执行

2、 可以传入JoinPoint 连接点参数 , 通过该参数可以获得当前拦截对象和方法信息

    <!-- 配置目标 -->
    <bean id="customerService" class="cn.itcast.spring.d_aspectj.CustomerService" />

    <!-- 配置切面Bean -->
    <bean id="myAspect" class="cn.itcast.spring.d_aspectj.MyAspect" />

    <!-- AOP切面配置 -->
    <aop:config>
        <!-- ref 引用定义切面类  -->
        <aop:aspect ref="myAspect">
            <aop:pointcut expression="execution(* cn.itcast.spring.d_aspectj.CustomerService.*(..))" id="mypointcut2"/>
            <aop:before method="before1" pointcut-ref="mypointcut2"/>
            <aop:before method="before2" pointcut-ref="mypointcut2"/>
        </aop:aspect>
    </aop:config>

AfterReturning 后置通知

在目标业务方法执行后,进行代码增强

// 可以在后置通知传入两个参数 1、 连接点对象 2、目标方法返回值
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("后置通知.... 目标方法运行返回值 :" + result);
    }
<!-- returning参数,定义后置通知 接收目标方法返回值 参数名称 -->
<aop:after-returning method="afterReturning" returning="result2" pointcut-ref="mypointcut2"/>

细节:

后置通知 可以获得方法的返回值 , 在配置文件定义返回值参数名 必须要和方法参数名一致 。

Around 环绕通知

在目标方法执行前后,进行代码增强 (阻止目标方法的执行 )

环绕通知实现任何通知效果

// 环绕通知 (需要将目标方法 返回值 返回), 传入参数 可执行的连接点
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知  方法前执行 ....");
        Object result = proceedingJoinPoint.proceed(); // 执行目标方法
        System.out.println("环绕通知 方法后执行.... 方法返回值:" + result);
        return result;
    }
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="mypointcut2" />

AfterThrowing 抛出通知

在目标方法出现异常后,通知方法会得到执行 —– 错误日志记录

// 日志记录器
    private static final Logger LOG = Logger.getLogger(MyAspect.class);

    // 抛出通知
    // 第一个参数 JointPoint 连接点
    // 第二个参数 目标方法出现异常后,捕获到异常对象
    public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
        System.out.println("哪个方法出现异常:" + joinPoint.toLongString());
        // 调用日志记录API,将异常对象 写入日志文件
        LOG.error(ex.getMessage(), ex);
    }

方法接收两个参数 连接点和异常对象

<!-- 异常通知 -->
            <!-- throwing属性,配置发生异常后,捕获的异常对象参数名称 (和方法一致) -->
            <aop:after-throwing method="afterThrowing" throwing="ex" pointcut-ref="mypointcut2"/>

After 最终通知

无论目标方法是否出现异常,该通知都会执行 —— 类似 finally 代码块

应用场景 : 释放资源

// 最终通知
    public void after(JoinPoint joinPoint) {
        System.out.println("最终通知... 释放资源.... ");
    }
<!-- 最终通知 -->
            <aop:after method="after" pointcut-ref="mypointcut2" />
时间: 2024-10-25 21:44:54

Spring框架 AOP(三)的相关文章

跟着刚哥学习Spring框架--AOP(五)

AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入封装.继承.多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合.不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能.日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性.异常处理和透明的持续性也都是如此,这种散布在各

Spring框架AOP源码剖析

今天我要和大家分享的是 AOP(Aspect-Oriented Programming)这个东西的源码剖析,作为多年的开发者,想必大家在面试的时候都被问过,你知道Spring框架AOP的底层实现机制吗,这可是很简单的噢,我们会说,如果某个类有接口就使用JDK动态代理,没有接口就用CGLIB动态代理,并且Spring也提供了可配置开关,不管有无接口都一律使用CGLIB动态代理,例如 <aop:aspectj-autoproxy proxy-target-class="true"/&

spring框架 AOP核心详解

AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知 (2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用 (3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

Spring框架AOP的使用及个人对底层原理的理解

Spring框架AOP的使用及个人对底层原理的理解**** 前言: AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础.它是一种面向切面编程的思想.关于AOP的基础知识,相信多数童鞋都已经了如指掌,今天要给大家分享的是Spring框架AOP的使用,以及我个人对底层原理的一些理解. Aop使用步骤 配置aop信息 <aop:config> 相当于aop的根节点 配置切入点 <aop:piontcut> 切入点 可以理解为需要增强的方法

【spring框架】(三)面向切面编程(AOP)

1.AOP概念  AOP(Aspect-Oriented Programming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善. OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心

Spring框架第三天

html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption

Spring框架Aop详解

一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnblogs.com/xrq730/p/4919025.html AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入封装.继承.多态等概念来建立一种对象层次

Spring 框架(三)

1 spring l AOP :切面编程 切面:切入点 和 通知 结合 l spring aop 编程 <aop:config> 方法1: <aop:pointcut expression="切入点表达式" id=""> <aop:advisor  advice-ref="通知引用" pointcut-ref="切入点的引用"> 方法2: <aop:advisor  advice-re

Spring框架--AOP

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