spring aop 前置知识(Aop概念与动态代理)

1 AOP概述

Aop 引入了Aspect概念,用来以模块化的形式对系统中的横切关注点进行封装。Aspect相对于Aop,就相当于Class对于OOP(面向对象)。

1.1 aop的实现

  • 静态aop

Asprct 直接以java字节码的形式编译到java类中。

  • 动态aop
    Aop的织入过程在系统运行之后进行,而不是预先编译。

1.2 java Aop 实现机制

  • jdk 动态代理

在运行期间,为相应的接口动态生成对应的代理对象(反射),可以将横切点逻辑封装到动态代理的InvocationHandler,然后在运行器,根据横切点,将横切逻辑织入到相应的代理类中。

spring 默认采用此方案。

  • cglib 动态字节码

在程序运行期间,动态的构建字节码的class文件。我们可以为需要织入横切逻辑的类在运行期间,通过cglib为这些类生成相应子类,讲这些横切逻辑加到子类中,让应用程序在执行期间使用的是动态生成的子类。

spring在无法使用jdk动态代理的情况下,会使用cglib库的动态字节码增强实现aop功能扩展。

1.3 Aop 概念

1.3.1 Joinpoint

aop功能模块在织入oop中需要知道在系统的那些执行点上进行织入操作,我们将要在其之上进行织入操作的系统执行点称为joinpoint。

常见的Joinpoint类型.

  • 方法调用

  • 方法执行

  • 字段设置

  • 字段获取

  • 异常处理

1.3.2 Pointcut

pointcut 的概念是joinpoint的表达方式,将横切逻辑织入当前系统的过程中,需要参照pointcut规定的joinpoint信息,才可以知道应该往系统的那些joinpoint织入横切逻辑。

  • 直接指定

  • 正则表达式

  • 使用特定的pointcut表述语言

1.3.3 Advice

advice 是单一横切关注点逻辑载体,它代表将会织入Joinpoint的横切逻辑,根据advice在joinpoint位置时机的差异,分成多种形式。

  • Before Advice
    是在joinpoint指定位置之前执行的Advice类型。

  • After Advice
    在相应连接点之后执行的Advice类型包括以下三种

  • After Return Advice
    只有当前joinpoint处执行流程正常完成,才会执行

  • Throw Advice
    只有在抛出异常的情况下,才会执行

  • After Advice
    无论执行过程中是否抛出异常,都会执行

  • Around Advice
    可以在Joinpoint之前和之后都指定相应的逻辑,可以完成Before Advice和After Advice

1.3.4 Aspect

Aspect 是对系统中横切点逻辑进行模块化封装的Aop概念实体,包含多个Pointcut以及相关Advice定义
Spring中使用@Aspect的注解并结合普通pojo来声明Aspect

1.3.5 织入和织入器

只有经过织入过程,以Aspect模块化的横切点才会集成到oop现存系统中,而完成织入过程中的类就是织入器,
spring 中ProxyFactory就是织入器

2 Spring Aop 实现机制

2.1 代理模式

代理模式中代理处于访问者与被访问者之间,隔离了这两者之间的直接交互。代理能够处理访问的请求就不需要劳烦被访问者了,减少被访问者负担,此外代理最终要将访问请求转发给真正的被访问者,所以可以在请求之前或者后面加入特定的逻辑

SubjectProxy内部持有SubjectImpl,在进行请求时会将该请求转发给SubjectImpl,不过更多的是对请求添加访问限制。

2.2 jdk动态代理

在使用静态代理时,针对不一样的目标类型,我们要为其单独实现代理对象。而所加的横切逻辑都是一样的,而我们可以使用动态代理,可以为指定的接口在系统运行期间动态的生成代理对象。
其机制需要实现 proxy类和InvocationHandle接口

被代理对象cat


/**
 * @description:  被代理的对象。不同的类型,但是只要横切逻辑一样即可
 */
public class Cat implements ICat{
    @Override
    public void eat() {
        System.out.println("Cat eat fish");
    }

    @Override
    public void saty() {

    }
}

被代理对象 dog

/**
 * @description: 被代理对象。不同的类型,但是只要横切逻辑一样即可
 */
public class Dog implements IDog{
    @Override
    public void eatFood() {
        System.out.println("Dog eat dogfood");
    }

    @Override
    public void play() {
        System.out.println("sdfs");
    }
    
}

实现统一切面逻辑

/**
 * @description: 实现统一切面逻辑
 */
public class EatHandle implements InvocationHandler {
    //被代理对象
    private Object object;
    public EatHandle(Object object){
         this.object=object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //代理逻辑的实现
        if(method.getName().startsWith("eat")){
            eat();
        return method.invoke(object,args);
        }

        return null;
    }
    public void eat(){
        System.out.println("该吃饭了");
    }
}

创建代理对象

 @Test
    public void t9(){
        //创建cat代理对象
        ICat iCatProxy = (ICat) Proxy.newProxyInstance(
                                               Cat.class.getClassLoader(),
                                                new Class[]{ICat.class},
                                                 new EatHandle(new Cat())  );

        iCatProxy.eat();


        //创建 Dog代理对象

        IDog iDogProxy = (IDog) Proxy.newProxyInstance(org.example.Day04.Dog.class.getClassLoader(),
                                               new Class[]{IDog.class},
                                                 new EatHandle(new org.example.Day04.Dog()));

        iDogProxy.eatFood();

    }

jdk 代理机制只能对实现相应Interface的类使用。

2.3 cglib动态字节码

对目标对象进行继承扩展,为其生成相应的子类,将横切逻辑实现放到子类中,然后让系统使用目标对象的子类,我们需要借助cglib动态字节码生成库,在系统运行期间动态为目标对象生成相应的扩展子类。

这里需要实现Callback,我们会直接使用MethodInterceptor接口(扩展了callback接口)

实现切面逻辑

public class TestCallBack implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
       if(method.getName().startsWith("eat")){
           System.out.println("该吃饭了");
		   //此方法并不是反射
          return   methodProxy.invokeSuper(o,objects);
       }
        return null;
    }
}

创建其子类

        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(Cat.class);
        //设置回调函数
        enhancer.setCallback(new TestCallBack());
        //创建子类
        Cat proxy= (Cat) enhancer.create();
        proxy.eat();

通过cglib的enhance为目标对象动态地生成一个子类,并将里面callback中的横切逻辑附加到了需要的对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值