首页 > 编程知识 正文

aop原理和机制,aop底层实现原理

时间:2023-05-03 07:27:51 阅读:32270 作者:4891

文章目录1反射2切片导向编程2.1概念理解2.2 AOP中的相关概念2.3特征2.4 AOP代理2.4.1 JDK动态代理2.2

Spring——AOP的详细说明(AOP概要) )

Spring AOP——简单粗暴、酷的棉花糖课

在1反射(reflect )执行状态下,任一类都可以知道该类的属性和方法。 对于任何对象,都可以调用其方法和属性之一。 这种动态获取信息并动态调用对象的方法称为反射。 反射的一般作用如下。

将字符串放在Integer的列表中,该列表生成在运行时确定任意对象所属的类在运行时生成任意类的对象运行时确定一个类具有的成员变量和方法并在运行时调用任意对象的方法动态代理在反射中arraylistintegerlist=newarraylistinteger (; 方法方法=list.getclass ().getmethod )、Object.class ); method.invoke (列表,'我是String ' ); 系统. out.println (list.get (0) ); //打印结果:我对String 2切片导向编程(AOP,Aspect Oriented Programming ) 2.1概念理解AOP是指切片导向编程,在实际开发和工作中是权限控制、全局状态

概念: AOP基于Java反射,可以提取程序中的公共部分来创建断开类。 这样做可以提高代码的重用性。 需求变化后,修改那个代码就可以了。 AOP由包括JDK动态代理和CGLIB代理在内的动态代理实现。 一般说明:在不修改源代码方式的情况下为主干功能添加新功能的含义。 扩展类的功能(在目标对象的方法执行前和执行后添加其他功能)何时会出现面向切片的编程需求? 根据软件重构的思路,当多个类中出现重复代码时,应该考虑定义一个公共抽象类,并将该公共代码提取到抽象类中。 例如,如果Teacher,Student具有username,则可以将username及其关联的getXXX (,setXXX )方法提取到抽象类sysusesename中,但在以下情况下该怎么办如何将性能检查、事务控制添加到所有类方法中? AOP是指,我们希望通过横向切割将它们分布在每个业务逻辑代码中的相同代码提取到一个独立的模块中,使业务逻辑类保持最初的简单性。 在进行事件时,通常会对每个接口进行事件的有效性检查(如是否启动、是否退出等),以及该接口是否需要用户登录。 按照常规逻辑,可以这样做。 这涉及到有多少个接口,需要多少次代码复制。 对于“懒惰”,这是不能容忍的。 是的,我建议公开方法。 每个接口都调用这个接口。 这里有点乌冬面的味道。 有同样的问题。 我每次都可以不用复印代码,但每个接口都必须调用这个方法吧。 于是就有了切面的概念。 在接口调用的某个地方注入方法。 红框的地方是向着切面编程的。 这样,接口就只关心特定的业务,而不需要关心该接口不关心的其他逻辑或处理。 2.2 AOP中的相关概念接头点(连接点)表示程序正在运行的某个动作,如方法调用、类成员访问、异常处理程序块的执行等,其自身也可以嵌套其他接头点Pointcut (接点) :每个程序的接点点有多个,如何定位到感兴趣的接点点,需要在Pointcut上定位,它定义了相应Advice发生的位置。 增强(advice ):advice是组织在目标对象的关节点(pointcut )中的程序代码,根据before、after和around的不同,每个视点“预通知”(Before advice ) :在一个“连接点”(JoinPoint )之前运行的通知,但该通知不能阻止在连接点之前运行。 在ApplicationContext中,使用aop:aspect中的aop:before元素进行声明。 后通知(After advice ) :在一个连接点终止时发出的通知(无论是恢复正常还是异常终止)。 在ApplicationContext中,使用aop:aspect中的aop:after元素进行声明。 返回后通知(After return advice ) :在某个连接点成功完成后执行的通知,不包括抛出异常的情况。 在应用程序上下文中,在aop:aspect中使用after-returning元素声明。 动态观察通知:围绕连接点的通知。 可以在调用方法之前和之后完成定制行为,也可以不执行。 应用上下文在aop:aspect中使用aop:around

>元素进行声明。抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。 ApplicationContext中在<aop:aspect>里面使用<aop:after-throwing>元素进行声明。 Aspect(切面): 切面由 Pointcut 和相应的 Advice 组成,它既包括了横切逻辑的定义,也包括了连接点的定义,Spring AOP就是将切面所定义的增强 织入到切面所制定的连接点中。Target(目标对象):织入 Advice 的对象,也称为被通知的对象。由于在 AOP 里面使用运行时代理,因而目标对象一直是被代理的对象Weaving(织入):织入就是将增强添加到对目标对象的具体连接点上的过程AOP proxy(AOP 代理): 一个类被AOP织入增强后,就产生了一个代理类。在 Spring 框架里一个 AOP 代理指的是 JDK 自身的动态代理或 CGLIB 实现的动态代理。

以数据库的操作为例来说明:

① 获取连接对象② 执行SQL(核心业务代码)③ 如果有异常,回滚事务,无异常则提交事务④ 关闭连接
上述的几个部署,②是核心业务代码,其他都是非核心业务代码,但是我们又必须写。而面向切面编程就是为了解决这样的问题,将这些非核心业务代码抽离,这样开发者只需要关注“核心业务代码”即可。 这样开发效率自然提高。

在 Spring AOP 中 Joint point 指代的是所有方法的执行点, 而 point cut 是一个描述信息, 它修饰的是 Joint point, 通过 point cut, 我们就可以确定哪些 Joint point 可以被织入 Advice

2.3 特点 降低模块之间的耦合度使系统容易扩展更好的代码复用

AOP编程可不是Spring独有的,Spring只是支持AOP编程的框架之一,这一点非常重要,切勿搞反了关系

2.4 AOP代理 2.4.1 JDK动态代理 a、先定义一个接口,这个接口中的方法是“目标方法” package com.brickworkers;public interface Sky { public void rain();} b、接着实现这个接口 package com.brickworkers;public class SkyImpl implements Sky{ @Override public void rain() { System.out.println("it`s raining"); }} c、如果要完成动态代理,首先需要定义一个InvocationHandler接口的子类: package com.brickworkers;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class MyInvocationHandler implements InvocationHandler { //目标对象 private Object obj = null; //获取目标对象的代理对象 public Object getProxy(Object obj){ this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this); } //控制执行目标对象的方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("目标对象方法执行之前"); Object result = method.invoke(obj, args); System.out.println("目标对象方法执行之后"); return result; }} d、JDK动态代理测试类 package com.brickworkers;public class ProxyTest { public static void main(String[] args) { //实例化InvocationHandler MyInvocationHandler myInvocationHandler = new MyInvocationHandler(); //生产代理对象 Sky sky = (Sky) myInvocationHandler.getProxy(new SkyImpl()); sky.rain(); }}//执行结果: 目标对象方法执行之前// it`s raining// 目标对象方法执行之后

看到这里相信大家和我一样就很疑惑,为什么JDK动态代理只能局限于接口呢?对此,笔者查阅了一些技术文档和JDK动态代理的源码,发现在反编译产生的proxyTest.class中,类的定义如下:

import dynamic.proxy.UserService; import java.lang.reflect.*; public final class $ProxyTest extends Proxy implements Sky{ ......}

从反编译的源码可以看出,proxyTest继承了Proxy,然而在Java中只支持单继承,但是可以实现多个接口,所以JDK动态代理只能局限于接口。

那么JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,要实现动态代理要怎么办呢?这个时候就需要CGLib动态代理啦。

2.4.2 CGLib动态代理

CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有分类方法的调用,顺势织入和横切逻辑。— http://blog.csdn.net/pgddxhd5/article/details/9099133/

点击下载编写CGlib动态代理测试所需jar包

a、定义一个目标对象: /** * 目标对象类:被代理的类 */public class TargetObject { /** * 目标方法(即目标操作) */ public void business() { System.out.println("business"); } } b、如果要完成动态代理,首先需要定义一个MethodInterceptor接口的子类 import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;/** * 动态代理-拦截器 */public class MyInterceptor implements MethodInterceptor {//目标对象 private Object target; public MyInterceptor(Object target) { this.target = target; } /** * 返回值是一个代理对象(代理对象是目标对象的子类) */ public Object createProxy() { Enhancer enhancer = new Enhancer();//回调函数 enhancer.setCallback(this); //设置代理对象的父类,可以看到代理对象是目标对象的子类 enhancer.setSuperclass(this.target.getClass()); // 创建代理对象 return enhancer.create(); } /** * objects 目标方法的参数 * method 目标方法 */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { if(true){//不要在意这为什么是恒成立的条件语句,为的是说明一个aop的概念:切入点。 System.out.println("aaaaa");//切面方法a(); //。。。 Object result = method.invoke(this.target, objects);//调用目标类的目标方法 //。。。 System.out.println("bbbbb");//切面方法f(); } return result; }} CGLib动态代理测试类: public class MainTest { public static void main(String[] args) { //目标对象 TargetObject target = new TargetObject(); //拦截器 MyInterceptor myInterceptor = new MyInterceptor(target); //代理对象,调用cglib系统方法自动生成 // 注意:代理类是目标类的子类。 TargetObject proxyObj = (TargetObject) myInterceptor.createProxy(); proxyObj.business(); }}

代理对象的方法 = 目标对象的目标方法 + 所有切面的通知织入:形成代理对象的方法的过程通知:实际上就是切面中的方法。切入点的理解:只有符合切入点的目标方法,才能加载通知。也就是调用切面的通知(方法)啦,看代码也就是说,切入点是控制代理对象内部的切面方法和目标对象的目标方法是否执行的条件。切面可以不止是一个。每个切面里面的通知即切面方法也是可以有很多的。连接点的理解:所谓连接点,也就是目标对象或者代理对象之中的方法。为什么说2个都 可以呢?因为如果是jdk实现的动态代理的话,那么目标对象和代理对象要实现共同的接口,如果是cglib实现的动态代理的话,那么代理对象类是目标对象类的子类。都是一个方法啦。所以这么理解就OK的啦。

最后,还有一点需要注意:因为CGLib动态代理是创建一个子类来实现的,那么对于继承的定义,final类是无法进行代理的哦。

参考:https://blog.csdn.net/u012403290/article/details/64443021
参考:https://blog.csdn.net/q982151756/article/details/80513340(重要)
参考:https://blog.csdn.net/qq_41981107/article/details/87920537
参考:https://lixuekai.blog.csdn.net/article/details/53351403(重要)

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。