Spring AOP 之 代理知识

为了让博客内容看着舒服一些,所以我把静态代理和动态代理的代码在最后了哦!

1. 动态代理和静态代理

什么是代理?

  • 为某⼀个对象创建⼀个代理对象,程序不直接用原本的对象,而是由创建的代理对象来控制对原对象,通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间。
  • A ->B-> C (A类是调用方法的类,B类就是代理,C类是真正的方法)

静态代理:
由程序创建或特定工具自动生成源代码,在程序运行前,代理类的.class文件就已经存在。

动态代理:
在程序运行时,运用反射机制动态创建而成,无需手动编写代码。

  • JDK动态代理
  • CGLIB动态代理

2. 静态代理讲解

什么是静态代理?

  • 由程序创建或特定工具自动生成源代码,在程序运行前,代理类的.class文件就已经存在
  • 通过将目标类与代理类实现同⼀个接口,让代理类持有真实类对象,然后在代理类方法中调用真实类方法,再调用真实类方法的前后添加我们所需要的功能扩展代码来达到增强的目的
  • A ->B-> C (A类是调用方法的类,B类就是代理,C类是真正的方法)

优点:

  • 代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可
  • 方便增加功能,拓展业务逻辑

缺点:

  • 代理类中出现大量冗余的代码,非常不利于扩展和维护
  • 如果接口增加⼀个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度

3. AOP的实现策略之JDK动态代理 和 CGLib动态代理

动态代理:

  • 在程序运行时,运用反射机制动态创建而成,无需手动编写代码
  • 动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器⼀个集中的方法中处理,解耦和易维护
  • JDK动态代理与静态代理⼀样,目标类需要实现⼀个代理接口,再通过代理对象调用目标方法
  • CGLib动态代理的原理是对指定的业务类生成⼀个子类,并覆盖其中的业务方法来实现代理

两种动态代理的区别:

  • JDK动态代理是自带的,CGLib需要引入第三方包
  • CGLib动态代理:它是在内存中构建⼀个子类对象从而实现对目标对象功能的扩展
  • CGLib动态代理基于继承来实现代理,所以无法对final类、private方法和static方法实现代理
  • JDK动态代理:要求目标对象实现⼀个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以用CGLib动态代理

Spring AOP中的代理使⽤的默认策略:

  • 如果目标对象实现了接口,则默认采用JDK动态代理
  • 如果目标对象没有实现接口,则采用CGLib进行动态代理
  • 如果目标对象实现了接口,程序里面依旧可以指定使用CGLib动态代理

4. 静态代理及动态代理 之 实现案例

首先在项目中新建一个代理的包,包名为 proxy,
还记得文章开头的ABC吗?
A ->B-> C (A类是调用方法的类,B类就是代理,C类是真正的方法)

A:ProxyTest:调用方法的类
B:StaticProxyPayServiceImpl(静态代理)、JdkProxy(JDK动态代理)、CglibProxy(CGLib动态代理)
C:PayServiceImpl:真正的方法
PayService:该demo要实现的接口
结构如下:
项目结构
该demo要实现的接口 – PayService:

public interface PayService {
    String callback(String outTradeNo);
    int save(int userId, int productId);
}

真正的方法 --PayServiceImpl:

public class PayServiceImpl implements PayService{

    public String callback(String outTradeNo) {
        System.out.println("PayServiceImpl 回调 方法 callback");
        return outTradeNo;
    }

    public int save(int userId, int productId) {
        System.out.println("PayServiceImpl 回调 方法 save");
        return productId;
    }
}

代理模块代码:

4.1 静态代理 – StaticProxyPayServiceImpl:

public class StaticProxyPayServiceImpl implements PayService{

    private PayService payService;

    //通过构造函数的方式注入
    public StaticProxyPayServiceImpl(PayService payService){
        this.payService = payService;
    }

    public String callback(String outTradeNo) {
        System.out.println("StaticProxyPayServiceImpl  callback  begin");
        String result = payService.callback(outTradeNo);
        System.out.println("StaticProxyPayServiceImpl  callback  end");
        return result;
    }

    public int save(int userId, int productId) {
        System.out.println("StaticProxyPayServiceImpl  save  begin");
        int id = payService.save(userId, productId);
        System.out.println("StaticProxyPayServiceImpl  save  end");
        return id;
    }
}

4.2 JDK动态代理 – JdkProxy:

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

public class JdkProxy implements InvocationHandler {

    //目标类
    private Object targetObject;

    //获取代理对象
    public Object newProxyInstance(Object targetObject){
        this.targetObject = targetObject;
        //绑定关系,也就是和具体的哪个实现类关联
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(), this);
    }

    //Object proxy:被代理的对象
    //Method method:要调⽤的⽅法
    //Object[] args:⽅法调⽤时所需要参数
    public Object invoke(Object proxy, Method method, Object[] args) {

        Object result = null;

        try {
            System.out.println("通过JDK动态代理调用"+method.getName()+",打印日志  begin");
            result = method.invoke(targetObject,args);
            System.out.println("通过JDK动态代理调用"+method.getName()+",打印日志  end");
        } catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
}

4.3 CGLib动态代理 – CglibProxy:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {

    //目标类
    private Object targetObject;

    //绑定关系
    public Object newProxyInstance(Object targetObject){
        this.targetObject = targetObject;
        Enhancer enhancer = new Enhancer();
        //设置代理类的⽗类(⽬标类)
        enhancer.setSuperclass(this.targetObject.getClass());

        //设置回调函数
        enhancer.setCallback(this);

        //创建⼦类(代理对象)
        return enhancer.create();
    }

    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object result = null;
        try {
            System.out.println("通过CGLIB动态代理调用"+method.getName()+",打印日志  begin");
            result = methodProxy.invokeSuper(o,args);
            System.out.println("通过CGLIB动态代理调用"+method.getName()+",打印日志  end");
        } catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
}

4.4调用方法的类 – ProxyTest:

想测试哪个,就把哪个的代码打开,这里只打开了CGLib代理的测试!

public class ProxyTest {
    public static void main(String[] args) {
        //正常调用
//        PayService payService = new PayServiceImpl();
//        payService.callback("fdvwtr");

        //使用代理调用
//        PayService payService = new StaticProxyPayServiceImpl(new PayServiceImpl());
//        payService.save(123, 654);
//        payService.callback("fdvwtr");

        //JDK动态代理
//        JdkProxy jdkProxy = new JdkProxy();
//        //获取代理类对象
//        PayService payServiceProxy = (PayService) jdkProxy.newProxyInstance(new PayServiceImpl());
//        //调用目标方法
//        payServiceProxy.callback("151sfds");
//        payServiceProxy.save(1212,5656);

        //CGLiB动态代理
        CglibProxy cglibProxy = new CglibProxy();
        PayService payService = (PayService)cglibProxy.newProxyInstance(new PayServiceImpl());
        payService.callback("dsfasfasd");
        payService.save(555,666);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring AOP(Aspect Oriented Programming)是 Spring 框架中的一个重要组成部分,用于实现面向切面编程。以下是 Spring AOP 知识体系的主要内容: 1. AOP 的概念:介绍 AOP 的基本概念、作用和优势。 2. AOP 的实现方式:主要有基于代理AOP 和基于字节码操作的 AOP 两种实现方式。 3. 切面(Aspect)的概念:切面是 AOP 中的一个重要概念,用于描述一组横切关注点(cross-cutting concern)。 4. 切入点(Pointcut)的概念:切入点是 AOP 中一个非常重要的概念,用于描述在哪些连接点(Join point)上执行切面。 5. 通知(Advice)的概念:通知是切面中的具体行为,用于描述在连接点上执行的具体操作。 6. 引入(Introduction)的概念:引入是 AOP 中一个非常重要的概念,用于在不修改现有代码的情况下为一个对象增加新的属性或方法。 7. 织入(Weaving)的概念:织入是 AOP 中一个非常重要的概念,用于将切面应用到目标对象上,生成代理对象。 8. AOP 的实践应用:介绍 AOP 在实际开发中的应用场景,如日志记录、性能监控、事务管理等。 9. Spring AOP 的具体实现:介绍 Spring AOP 的具体实现方式,如基于代理AOP 和基于注解的 AOP 等。 10. AOP 的局限性和注意事项:介绍 AOP 在实践中可能存在的问题和需要注意的事项,如对 final 方法的限制、对静态方法的限制等。 以上是 Spring AOP 知识体系的主要内容,熟悉这些内容可以帮助开发人员更好地理解和应用 AOP 技术。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二炮

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值