模拟实现 Spring AOP

这篇具有很好参考价值的文章主要介绍了模拟实现 Spring AOP。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

Spring 是一种 Java 开发框架,其主要功能有两个:IoC(DI)和AOP。《模拟实现Spring AOP》是本人的一个编程训练项目,为了提升本人的编程能力、JAVA 编程思想,基于框架的角度出发,对 Spring AOP有一个更深层次的认识,动态代理模式的底层实现逻辑有更深的理解。

博主本人初入 Java 不久,能力有限,只将 Spring AOP完成到:实现了基于代理机制的拦截器链以及基于正则的配置;

Spring AOP

AOP(面向切面编程),通过预编译方式和运行期动态代理来实现程序功能的统一与扩展的技术。

Spring AOP 概述

AOP(Aspect Oriented Programming,面向切面编程)是一种编程思想,它的主要目的是将通用功能从业务逻辑中抽离出来,以达到代码复用和模块化的目的。AOP的基本概念包括:

  • 切面(Aspect):切面是一个模块化的关注点,通常包含一个或多个通知(Advice)和切入点(Pointcut)的组合。切面的作用是将横切关注点模块化,以便于重用和维护。
  • 通知(Advice):通知是切面中执行的具体操作。通知有五种类型:前置通知(Before)、后置通知(After)、返回通知(AfterReturning)、异常通知(AfterThrowing)和环绕通知(Around)。
  • 切入点(Pointcut):切入点是一个表达式,用于定义在哪些方法上应用通知。切入点可以使用通配符匹配方法名、参数类型和返回值类型。
  • 连接点(JoinPoint):连接点是程序执行过程中的某个特定的点,例如方法执行、异常抛出等。切面可以在连接点附近织入通知。
  • 织入(Weaving):织入是将切面代码插入到目标类中的过程。织入可以在编译期(Compile-time)、类加载期(Load-time)或运行期(Runtime)完成。
模拟实现 Spring AOP

AOP可以对业务逻辑部分进行隔离,从而使业务逻辑耦合降低,提高代码复用和开发效率。是基于动态代理实现的,如果目标对象实现了接口,就用 JDK 动态代理,未实现接口就用 CGLIB 动态代理。通过 AOP 技术,在不修改源代码的情况下,为程序添加了新的功能,是对程序的非侵入式扩展。

Spring IoC 技术难点

  • 拦截器的实现(代理模式的应用)
  • 基于正则的配置

Spring IoC 框架思考

需求分析

  • 代理对象的获取

    • JDKProxy 代理模式实现

      public class JDKProxy {
      	private static IntercepterChain chain;
      
      	public JDKProxy() {
      	}
      	
      	public void addIntercepter(String targetMethod, IIntercepter intercepter) {
      		JDKProxy.chain.addIntercepter(targetMethod, intercepter);
      	}
      
      	public <T> T getProxy(Object object) {
      		Class<?> klass = object.getClass();
      		ClassLoader loader = klass.getClassLoader();
      		Class<?>[] interfaces = klass.getInterfaces();
      		
      		InvocationHandler h = new InvocationHandler() {
      			@Override
      			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      				return JDKProxy.chain.doInvoker(object, method, args);
      			}
      		};
      		
      		@SuppressWarnings("unchecked")
      		T proxy = (T) Proxy.newProxyInstance(loader, interfaces, h);
      		
      		return proxy;
      	}
      }
      
    • CGLibProxy 代理模式实现

      public class CGLibProxy {
      
      	public CGLibProxy() {
      	}
      
      	@SuppressWarnings("unchecked")
      	public <T> T getProxy(Object object) {
      		Class<?> klass = object.getClass();
      		Enhancer enhancer = new Enhancer();
      		enhancer.setSuperclass(klass);
      		
      		enhancer.setCallback(new InvocationHandler() {
      			@Override
      			public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
      				return null;
      			}
      		});
      		
      		return (T) enhancer.create();
      	}
      }
      
  • 切点的匹配以及拦截器链的实现

  • 对代理对象执行方法的参数以及结果的获取与处理

Spring IoC 技术难点实现

  • 拦截器的实现(代理模式的应用)

    拦截器:是一种可以在方法执行前、后、异常发生时执行的逻辑,并且,这些逻辑可以“堆叠”,形成拦截器链,或者,拦截器堆栈。

    可以通过“增加拦截器”或者“删除拦截器”的方式,对拦截器进行编辑;拦截器应该是针对某个、某些方法的。

    无论如何,拦截器技术是基于代理机制的。那么,必须提供“取得代理对象”的方法。

    前置拦截器:前置拦截器可以决定是否继续执行目标方法,也就是说,前置拦截器应该允许返回逻辑值,以确定是否继续执行目标方法;而且,对于由多个拦截器组成的拦截器链,任何一个拦截器返回值若为 false,则,所有其后的前置拦截器,以及方法本身,都不再执行!这可以称为:方法的中断。

    通常情况下,前置拦截器按照拦截器添加顺序执行(即,队列模式————先进先服务);后置拦截器按照添加逆序执行(即,堆栈模式————先进后服务)。

    public class IntercepterChain {
    	private Intercepter intercepter;
    	private IntercepterChain next;
    	
    	public IntercepterChain() {
    		this.intercepter = null;
    		this.next = null;
    	}
    	//增加拦截器
    	public void addIntercepter(String targetMethod, IIntercepter intercepter) {
    		if (this.intercepter == null) {
    			this.intercepter = new Intercepter(targetMethod, intercepter);
    			return;
    		}
    		
    		if (this.next == null) {
    			this.next = new IntercepterChain();
    		}
    		this.next.addIntercepter(targetMethod, intercepter);
    	}
    	//反射执行方法
    	public Object doInvoker(Object object, Method method, Object[] args) throws Throwable {
    		Object result = null;
    		
    		if (this.intercepter == null) {
    			return method.invoke(object, args);
    		}
    		
    		if (this.intercepter.before(method, args)) {
    			if (this.next != null) {
    				result = this.next.doInvoker(object, method, args);
    			}
    			
    			if (this.next == null) {
    				result = method.invoke(object, args);
    			}
    			
    			result = this.intercepter.after(method, result);		
    		}	
    		return result;
    	}
    }
    
模拟实现 Spring AOP
  • 基于正则的配置

    由于想匹配到切点就必须提供方法的全类名以及参数的全类名,对于使用者来说很不方便,采用正则表达式来处理匹配切点。用户只需要提供一个普通的类名、或方法名及参数,对于其他的不确定的地方使用‘*’来代替,当用户调用到添加拦截器时,对于用户传入的简单切点名进行转化,MethodInvoker 类中提供了处理用户提交的普通的类名与参数名的 toRegex 方法,此方法把简单的字符串转换为正则表达式,从而找到符合的切面的切点。完成切点的匹配。

    /**
         * 用户提供切点名,*.ClassName.methodName(*)
         * 例:*.MyInterface.*(*String,*int) 表示任意长度的前一个字符,前面必须有字符
         *  故 .* 表示任意字符
         *  用户只需输入简单的参数以及方法名,不确定的地方用*代替
         *  .*IMyInterface..*\(.*String,.*int\)
         *
         */
        private String toRegex(String methodName) {
            StringBuffer stringBuffer = new StringBuffer();
            //将不确定的地方替换为.*表示匹配任意字符
            String buffer = methodName.replace("*", ".*");
     
            int left =buffer.indexOf("(");
            int right = buffer.indexOf(")");
            //得到类名与方法名
            stringBuffer.append(".*").append(buffer.substring(0, left)).append("\\(");
     
            //按照逗号分割出参数字符串数组
            String[] args = buffer.substring(left + 1, right).split(",");
            for(int i = 0; i < args.length; i++) {
                stringBuffer.append((i == 0 ? "" : ",")).append(".*").append(args[i]);
            }
            stringBuffer.append("\\)");
            return stringBuffer.toString();
        }
    

模拟实现 AOP 具体代码

为了在目标方法前后执行新的方法,且不对源代码进行修改,所以要用动态代理,让代理去执行目标方法,然后在执行方法前进行前置拦截,在执行方法后进行后置拦截。

  • JDK 动态代理

    public class JDKProxy {
    	private static IntercepterChain chain;
    
    	public JDKProxy() {
    	}
    	
    	public void addIntercepter(String targetMethod, IIntercepter intercepter) {
    		JDKProxy.chain.addIntercepter(targetMethod, intercepter);
    	}
    
    	public <T> T getProxy(Object object) {
    		Class<?> klass = object.getClass();
    		ClassLoader loader = klass.getClassLoader();
    		Class<?>[] interfaces = klass.getInterfaces();
    		
    		InvocationHandler h = new InvocationHandler() {
    			@Override
    			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    				return JDKProxy.chain.doInvoker(object, method, args);
    			}
    		};
    		
    		@SuppressWarnings("unchecked")
    		T proxy = (T) Proxy.newProxyInstance(loader, interfaces, h);
    		
    		return proxy;
    	}
    }
    
  • Result 类

    public class Result {
    	private static Object result;
    	
    	Result() {
    	}
    	……getter、setter
    }
    
  • 拦截器链实现

    public class IntercepterChain {
    	private Intercepter intercepter;
    	private IntercepterChain next;
    	
    	public IntercepterChain() {
    		this.intercepter = null;
    		this.next = null;
    	}
    	//增加拦截器
    	public void addIntercepter(String targetMethod, IIntercepter intercepter) {
    		if (this.intercepter == null) {
    			this.intercepter = new Intercepter(targetMethod, intercepter);
    			return;
    		}
    		
    		if (this.next == null) {
    			this.next = new IntercepterChain();
    		}
    		this.next.addIntercepter(targetMethod, intercepter);
    	}
    	//反射执行方法
    	public Object doInvoker(Object object, Method method, Object[] args) throws Throwable {
    		Object result = null;
    		
    		if (this.intercepter == null) {
    			return method.invoke(object, args);
    		}
    		
    		if (this.intercepter.before(method, args)) {
    			if (this.next != null) {
    				result = this.next.doInvoker(object, method, args);
    			}
    			
    			if (this.next == null) {
    				result = method.invoke(object, args);
    			}
    			
    			result = this.intercepter.after(method, result);		
    		}	
    		return result;
    	}
    }
    
    
  • 接口

    public interface IIntercepter {
    	boolean before();	//前置拦截
    	void after();		//后置拦截
    }
    
  • 拦截器

    //获取代理对象,并且在before()内部采用正则表达式来有选择的进行拦截处理。
    //当before()方法返回值为true时,则可以正常执行目标方法,否则不执行。
    public class Intercepter {
    	private String targetMethod;		//拦截目标
    	private IIntercepter intercepter;	
    	
    	Intercepter(String targetMethod, IIntercepter intercepter) {
    		this.targetMethod = targetMethod;
    		this.intercepter = intercepter;
    	}
    	//前置拦截:如果返回值为false则为不允许执行下面的方法
    	boolean before(Method method, Object[] args) {
    		// 正则,TODO
    		if (!method.toString().equals(this.targetMethod)) {
    			return true;
    		}
    		
    		Arguments.setArgs(args);
    		return this.intercepter.before();
    	}
    	后置拦截主要针对于方法执行的结果
    	Object after(Method method, Object result) {
    		// 正则,TODO
    		if (!method.toString().equals(this.targetMethod)) {
    			return result;
    		}
    		
    		Result.setResult(result);
    		this.intercepter.after();
    		
    		return Result.getResult();
    	}	
    }
    

这里只是作为本人训练项目,简单的实现了 Spring AOP 中的核心功能,还需要进行更深入的学习相关知识,有问题处望大佬指出。文章来源地址https://www.toymoban.com/news/detail-477985.html

到了这里,关于模拟实现 Spring AOP的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring教程16】Spring框架实战:详解解读AOP配置管理中AOP切入点表达式和通知类型

    欢迎大家回到《 Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《 如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《 AOP的工作流程和AOP的核心概念》 前面的案例中,有涉及到如下内容: 对于

    2024年02月04日
    浏览(40)
  • 【Spring教程21】Spring框架实战:Spring事务简介、AOP事务管理、代码示例全面详解

    欢迎大家回到《Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《AOP(面对切面编程)知识总结》 事务作用:在数据层保障一系列的数据库

    2024年02月04日
    浏览(44)
  • 【Spring教程18】Spring框架实战:利用Aop测定业务层接口执行效率代码实例详解

    欢迎大家回到《Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《详解解读AOP通知类型的使用》 这个需求也比较简单,前面我们在介绍AOP的

    2024年02月05日
    浏览(42)
  • 全面掌握Spring框架:深入解析IOC、AOP、事务管理与注解使用

    探索Spring框架的深层次知识,包括Spring IOC容器的初始化流程、AOP的实现机制、事务管理的细节、循环依赖问题的处理、条件注解的应用、JavaConfig的使用方法、PostProcessor的角色、@Autowired和@Value注解的高级应用,以及${}与#{}的区别。

    2024年03月13日
    浏览(196)
  • Spring AOP(AOP概念、组成、Spring AOP实现及实现原理)

    学习 Spring AOP 之前,先要了解 AOP 是什么 AOP(Aspect Oriented Programming):面向切面编程,它和 OOP(面向对象编程)类似。 它是一种思想, 是对某一类事情的集中处理。 比如用户登录权限的效验,在学习 AOP 之前,在需要判断用户登录的页面,都要各自实现或调用用户验证的方

    2024年02月02日
    浏览(39)
  • Spring 使用注解开发、代理模式、AOP

    在Spring4之后,要使用注解开发,必须要保证AOP的包导入了 项目搭建: 在配置文件中导入约束,增加注解支持 bean 实体类 @Component 注解 xml配置 测试: 属性如何注入 衍生的注解 @Component 有几个衍生的注解,我们在web开发中,会按照MVC三层架构分层 dao层: @Repository 等价于poj

    2024年02月13日
    浏览(51)
  • Spring AOP(AOP概念,组成成分,实现,原理)

    目录 1. 什么是Spring AOP? 2. 为什么要用AOP? 3. AOP该怎么学习? 3.1 AOP的组成 (1)切面(Aspect) (2)连接点(join point) (3)切点(Pointcut) (4)通知(Advice)  4. Spring AOP实现 4.1 添加 AOP 框架支持 ​编辑  4.2 定义切面 4.3 定义切点 4.4 定义通知 4.5 切点表达式说明 AspectJ

    2024年02月13日
    浏览(44)
  • 【Spring】javaBean、依赖注入、面向切面AOP、使用注解开发

    有一定规范的Java实体类,类内提供了一些公共方法以便外界对该对象的内部属性进行操作 所有属性都是private,所有的属性都可以通过get/set方法进行访问,同时还需要有一个无参构造(默认就有) 高内聚,低耦合是现代软件的开发的设计模式 之前编写的图书管理系统具有高

    2024年02月08日
    浏览(72)
  • 【Spring AOP学习】AOP的组成 && SpringAOP的实现和实现原理

    目录 一、认识SpringAOP 1、AOP是什么? 2、AOP的功能 3、AOP的组成(重要) 二、SpringAOP的实现 🌷1、添加Spring AOP框架支持 🌷2、定义切面和切点 🌷 3、定义通知 3.1 完成代码实现 3.2 具体通知分析 🌷4、小练习:使用AOP统计UserController每个方法的执行时间。  三、SpringAOP的实现

    2024年02月15日
    浏览(32)
  • Spring AOP实现原理

    从入口  org.springframework.context.support.AbstractApplicationContext#refresh  开始看 找到Bean的创建方法进入: 再进入详细方法:  找到getBean(beanName): 找到doGetBean(xxx,xxx,xxx,xxx);   找到实际的Bean创建方法createBean(beanName, mdb, args);可以非常明显的看到,Bean就是通过Proxy的方式获取的。   继续

    2023年04月25日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包