Spring中AOP概念与两种动态代理模式原理详解

目录
  • 1.概念
    • 1.AOP技术简介
    • 2.AOP的优势
    • 3.Spring AOP术语
    • 4.AOP 开发明确的事项
  • 2.AOP底层实现
    • 1.AOP 的动态代理技术:
    • 3.基于cglib的动态代理代码
  • 总结

1.概念

1.AOP技术简介

AOP 为Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

2.AOP的优势

作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强优势:减少重复代码,提高开发效率,并且便于维护

3.Spring AOP术语

Spring 的 AOP 实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。在正式讲解 AOP 的操作之前,我们必须理解 AOP 的相关术语,常用的术语如下:

Target(目标对象):代理的目标对象Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.(可能被增强的方法)Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义(被增强的方法)Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知(对目标对象增强的方法)Aspect(切面):是切入点和通知(引介)的结合(目标方法+增强=切面)Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。 spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入.(一个动作,切点和通知结合的过程=织入)

4.AOP 开发明确的事项

需要编写的内容 编写核心业务代码(目标类的目标方法)编写切面类,切面类中有通知(增强功能方法)在配置文件中,配置织入关系,即将哪些通知与哪些连接点进行结合 AOP 技术实现的内容 Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。 AOP 底层使用哪种代理方式 在 spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。

2.AOP底层实现

实际上, AOP 的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间, Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。

1.AOP 的动态代理技术:

常用的动态代理技术

  • JDK 代理 : 基于接口的动态代理技术
  • cglib 代理:基于父类的动态代理技术

2.基于jdk的动态代理代码

//---------接口1------------
package com.itspring.proxy.jdk;

public interface TargetInterface1 {
    void save();
}

//---------接口2------------
package com.itspring.proxy.jdk;

public interface TargetInterface2 {
    void update();
}

//---------接口1,接口2实现类(目标类)------------
package com.itspring.proxy.jdk;

//目标类(被增强的类)
public class Target implements TargetInterface1 ,TargetInterface2{
    public void save() {
        System.out.println("save running...");
    }

    public void update() {
        System.out.println("update running...");
    }
}
//---------通知类(方法增强类)------------
package com.itspring.proxy.jdk;

//通知类(增强类)
public class Advice {

    public void before() {
        System.out.println("前置增强...");
    }

    public void afterRunning() {
        System.out.println("后置增强...");
    }
}
//---------测试代码------------
package com.itspring.proxy.jdk;

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {

    @Test
    public void test1() {

        final Target target = new Target();

        final Advice advice = new Advice();

        //返回值就是动态生成的代理对象
        TargetInterface1 proxy1 = (TargetInterface1) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),  //目标类的类加载器
                target.getClass().getInterfaces(),  //目标类实现的接口(可能有多个)
                new InvocationHandler() {
                    //调用代理对象的任何方法,实质上都是调用invoke方法
                    public Object invoke(Object proxy,  //代理对象
                                         Method method,  //目标方法对象
                                         Object[] args  //目标方法的参数
                    ) throws Throwable {
                        System.out.println("正在执行的方法:" + method.getName());
                        advice.before();  //前置增强
                        Object invoke = method.invoke(target, args);  //执行目标方法
                        advice.afterRunning();  //后置增强
                        return invoke;
                    }
                }
        );

        proxy1.save();

        //返回值就是动态生成的代理对象
        TargetInterface2 proxy2 = (TargetInterface2) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),  //目标类的类加载器
                target.getClass().getInterfaces(),  //目标类实现的接口(可能有多个)
                new InvocationHandler() {
                    //调用代理对象的任何方法,实质上都是调用invoke方法
                    public Object invoke(Object proxy,  //代理对象
                                         Method method,  //目标方法对象
                                         Object[] args  //目标方法的参数
                    ) throws Throwable {
                        System.out.println("正在执行的方法:" + method.getName());
                        advice.before();
                        Object invoke = method.invoke(target, args);  //执行目标方法
                        advice.afterRunning();
                        return invoke;
                    }
                }
        );

        proxy2.update();
    }
}

3.基于cglib的动态代理代码

cglib是第三方的库,spring集成了cglib.

//---------目标类-------------
package com.itspring.proxy.cglib;

import com.itspring.proxy.jdk.TargetInterface1;
import com.itspring.proxy.jdk.TargetInterface2;

//目标类(被增强的类)
public class Target {
    public void save() {
        System.out.println("save running...");
    }

    public void update() {
        System.out.println("update running...");
    }
}
//---------通知类(增强类)-------------
package com.itspring.proxy.cglib;

//通知类(增强类)
public class Advice {

    public void before() {
        System.out.println("前置增强...");
    }

    public void afterRunning() {
        System.out.println("后置增强...");
    }
}
//---------测试代码-------------
package com.itspring.proxy.cglib;

import com.itspring.proxy.jdk.TargetInterface1;
import com.itspring.proxy.jdk.TargetInterface2;
import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {

    @Test
    public void test1() {
        //目标对象
        final Target target = new Target();

        //增强对象
        final Advice advice = new Advice();

        //基于cglib生成动态代理对象
        //1.创建增强器
        Enhancer enhancer = new Enhancer();
        //2.创建父类
        enhancer.setSuperclass(Target.class);
        //3.设置回调
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object proxy,  //代理对象
                                    Method method,  //目标方法
                                    Object[] objects,  //目标方法的参数
                                    MethodProxy methodProxy)  //目标方法的代理
                    throws Throwable {
                //前置增强
                advice.before();
                //目标方法
                Object invoke = method.invoke(target, objects);
                //后置增强
                advice.afterRunning();
                return invoke;
            }
        });
        //4.生成代理对象
        Target target1 = (Target) enhancer.create();
        //5.测试
        target1.save();
        target1.update();

    }
}

总结

到此这篇关于Spring中AOP概念与两种动态代理模式原理的文章就介绍到这了,更多相关Spring动态代理模式原理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring AOP手动实现简单动态代理的代码

    什么是AOP我们先来看一张图 图中A就是通知,比如你要给每个方法前都加一个before()方法,目标类的每一个方法叫joinpoint(切入点),每个切入点都会用到通知,把通知和切入点连起来,点成线,线成面,这就是切面,也就是AOP,下面我们来简单写个小例子来实现一下 目标类的接口 public interface UserService { public void addUser() ; public void updateUser(); public void deleteUser(); }

  • spring基础概念AOP与动态代理理解

    一.代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 以简单模拟事务的执行过程说明各种代理区别 1.1 静态代理 由程序员创建或由特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. public interface PersonDao { vo

  • Spring中AOP概念与两种动态代理模式原理详解

    目录 1.概念 1.AOP技术简介 2.AOP的优势 3.Spring AOP术语 4.AOP 开发明确的事项 2.AOP底层实现 1.AOP 的动态代理技术: 3.基于cglib的动态代理代码 总结 1.概念 1.AOP技术简介 AOP 为Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一

  • 对Python中创建进程的两种方式以及进程池详解

    在Python中创建进程有两种方式,第一种是: from multiprocessing import Process import time def test(): while True: print('---test---') time.sleep(1) if __name__ == '__main__': p=Process(target=test) p.start() while True: print('---main---') time.sleep(1) 上面这段代码是在window

  • Java实现JDK动态代理的原理详解

    目录 概念 案例 静态代理 JDK动态代理模式 原理分析 真相大白 概念 代理:为控制A对象,而创建出新B对象,由B对象代替执行A对象所有操作,称之为代理.一个代理体系建立涉及到3个参与角色:真实对象(A),代理对象(B),客户端. 其中的代理对象(B)起到中介作用,连通真实对象(A)与客户端,如果进一步拓展,代理对象可以实现更加复杂逻辑,比如对真实对象进行访问控制. 案例 需求:员工业务层接口调用save需要admin权限,调用list不需要权限,没权限调用时抛出异常提示. 静态代理 /**

  • ThinkPHP中Widget扩展的两种写法及调用方法详解

    本文实例讲述了ThinkPHP中Widget扩展的两种写法及调用方法.分享给大家供大家参考,具体如下: Widget扩展一般用于页面组件的扩展,在页面根据需要输出不同的内容,下面介绍一下ThinkPHP中Widget的两种写法及调用 写法一: ArticlWidget.class.php文件: class ArticleWidget extends Widget { /** * * @param array $data * @return type * 调用方法:{:W('ArticleList

  • webstorm中配置Eslint的两种方式及差异比较详解

    写在前面 这两种方式的配置基本相同,都是配一下node地址,Eslint执行文件的地址,Eslint的配置文件(就是.eslintrc)等,而且网上很方便就可以搜索到,就不多说了. 之所以要比较一下两者的差异,就是因为对于没有配置过的同学来说,看了诸如"怎么在webstorm下配置Eslint"的问题下面的回答,既有说用方式1,又有说方式2的,然后这两种方式配置项还差不多(都是在webstorm的一个setting页面里面设置三四个项目,然后勾上enable复选框),就容易混淆. 再加

  • SpringBoot/Spring AOP默认动态代理方式实例详解

    目录 1. springboot 2.x 及以上版本 2. Springboot 1.x 3.SpringBoot 2.x 为何默认使用 Cglib 总结: Spring 5.x中AOP默认依旧使用JDK动态代理 SpringBoot 2.x开始,AOP为了解决使用JDK动态代理可能导致的类型转换异常,而使用CGLIB. 在SpringBoot 2.x中,AOP如果需要替换使用JDK动态代理可以通过配置项spring.aop.proxy-target-class=false来进行修改,proxy

  • Java中的引用和动态代理的实现详解

    我们知道,动态代理(这里指JDK的动态代理)与静态代理的区别在于,其真实的代理类是动态生成的.但具体是怎么生成,生成的代理类包含了哪些内容,以什么形式存在,它为什么一定要以接口为基础? 如果去看动态代理的源代码(java.lang.reflect.Proxy),会发现其原理很简单(真正二进制类文件的生成是在本地方法中完成,源代码中没有),但其中用到了一个缓冲类java.lang.reflect.WeakCache<ClassLoader,Class<?>[],Class<?>

  • Spring JDK动态代理实现过程详解

    这篇文章主要介绍了Spring JDK动态代理实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1. 创建项目 在 MyEclipse 中创建一个名称为 springDemo03 的 Web 项目,将 Spring 支持和依赖的 JAR 包复制到 Web 项目的 WEB-INF/lib 目录中,并发布到类路径下. 2. 创建接口 CustomerDao 在项目的 src 目录下创建一个名为 com.mengma.dao 的包,在该包下

  • R语言常用两种并行方法之snowfall详解

    上一篇博客(R中两种常用并行方法之parallel)中已经介绍了R中常见的一种并行包:parallel,其有着简单便捷等优势,其实缺点也是非常明显,就是很不稳定.很多时候我们将大量的计算任务挂到服务器上进行运行时,更看重的是其稳定性. 这时就要介绍R中的另一个并行利器--snowfall,这也是在平时做模拟时用的最多的一种方法. 针对上篇中的简单例子 首先是一个最简单的并行的例子,这个例子不需要载入任何依赖库.函数.对象等.相对也比较简单: library(snowfall) # 载入snowf

  • R语言常用两种并行方法之parallel详解

    目录 并行计算 在模拟时什么地方可以用到并行? 怎么在R中看我们可以使用并行? parallel(简单) 由于最近在进行一些论文的模拟,所以尝试了两种并行的方法:parallel与snowfall,这两种方法各有优缺,但还是推荐snowfall,整体较为稳定,不容易因为内存不足或者并行线程过多等原因而报错. 并行计算 并行计算: 简单来讲,就是同时使用多个计算资源来解决一个计算问题,是提高计算机系统计算速度和处理能力的一种有效手段.(参考:并行计算简介) 一个问题被分解成为一系列可以并发执行的离

随机推荐