• Spring框架之动态代理


    前言

    动态代理是一种常用的设计模式,广泛应用于框架中,Spring框架的AOP特性就是应用动态代理实现的,想要理解AOP的实现原理我们就必须先理解动态代理。

    什么是代理模式

    代理模式是GOF23设计模式之一,代理模式中存在代理者和被代理者,代理者和被代理者都具有相同的功能,并且代理者执行功能时会附加一些额外的操作

    如:手机工厂和代理商都具有卖东西的功能,手机代理商除了帮工厂卖手机外,还能在卖手机前打广告推销,卖手机后还可以进行售后服务。

    代理模式的优点:

    1)符合开闭原则,不用修改被代理者任何的代码,就能扩展新的功能

    2)项目的扩展和维护比较方便

    代理模式分为:静态代理和动态代理

    静态代理

    什么是静态代理

    1)代理者和被代理者都实现了相同的接口(或继承相同的父类)

    2)代理者包含了一个被代理者的对象

    3)调用功能时,代理者会调用被代理者的功能,同时附加新的操作

    /**

    * 卖手机

    */

    public interface SellMobilePhone {

    void sellMobilePhone();

    }

    /**

    * 小米手机工厂

    */

    public class MiPhoneFactory implements SellMobilePhone{

    public void sellMobilePhone() {

    System.out.println("生产了小米9手机,卖出去!!");

    }

    }

    /**

    * 小米代理商

    */

    public class MiPhoneAgent implements SellMobilePhone {

    //被代理者,工厂对象

    private SellMobilePhone factory;

    //通过构造方法传入被代理者

    public MiPhoneAgent(SellMobilePhone factory){

    this.factory = factory;

    }

    public void sellMobilePhone() {

    System.out.println("打广告,做活动~~~~~~~~~~~~~~~~~");

    //调用被代理者的方法

    factory.sellMobilePhone();

    System.out.println("做售后,做推销~~~~~~~~~~~~~~~~~");

    }

    }

    public class TestStaticProxy {

    @Test

    public void testProxy(){

    //创建被代理者

    SellMobilePhone factory = new MiPhoneFactory();

    factory.sellMobilePhone();

    System.out.println("---------------------------------------");

    //创建代理者

    SellMobilePhone agent = new MiPhoneAgent(factory);

    //调用卖手机

    agent.sellMobilePhone();

    }

    }

    静态代理的问题:

    静态代理只能适合一种业务,如果有新的业务,就必须创建新的接口和新的代理,如添加卖电脑的接口和电脑工厂,就要创建新的电脑代理类。

    动态代理

    动态代理的特点:

    1) 在不修改原有类的基础上,为原来类添加新的功能

    2) 不需要依赖某个具体业务

    动态代理分为:JDK动态代理和CGLib动态代理

    区别是:

    JDK动态代理的被代理者必须实现任意接口

    CGLib动态代理不用实现接口,是通过继承实现的

    JDK动态代理

    实现步骤:

    1)代理类需要实现InvocationHandler接口

    2)实现invoke方法

    3)通过Proxy类的newProxyInstance方法来创建代理对象

    /**

    * 动态代理

    */

    public class SalesAgent implements InvocationHandler{

    //被代理者对象

    private Object object;

    /**

    * 创建代理对象

    * @param object 被代理者

    * @return 代理者

    */

    public Object createProxy(Object object){

    this.object = object;

    //Proxy.newProxyInstance创建动态代理的对象,传入被代理对象的类加载器,接口,InvocationHandler对象

    return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);

    }

    /**

    * 调用被代理者方法,同时添加新功能

    */

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    System.out.println("销售之前,打广告~~~~~~");

    //调用被代理者的方法

    Object result = method.invoke(object,args);

    System.out.println("销售之后,做售后~~~~~~");

    return result;

    }

    }

    public class TestInvocationHandler {

    @Test

    public void testInvocation(){

    //创建动态代理对象

    SalesAgent agent = new SalesAgent();

    //被代理对象

    SellMobilePhone sellMobilePhone = new MiPhoneFactory();

    //创建代理对象

    SellMobilePhone phoneProxy = (SellMobilePhone) agent.createProxy(sellMobilePhone);

    phoneProxy.sellMobilePhone();

    }

    }

    CGLib动态代理

    特点:通过继承实现,被代理者必须能被继承,通过被代理类创建子类,子类就是父类的代理。

    /**

    * CGLib动态代理

    *

    */

    public class CGLibProxy implements MethodInterceptor {

    /**

    * 返回代理对象

    * @param object 被代理对象

    * @return 代理对象

    */

    public Object createProxy(Object object){

    //创建加强器

    Enhancer eh = new Enhancer();

    //设置被代理对象的类为父类

    eh.setSuperclass(object.getClass());

    //设置代理对象的回调

    eh.setCallback(this);

    return eh.create();

    }

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

    System.out.println("售前~~~~~~CGLIB");

    //调用父类对象的方法

    Object res = proxy.invokeSuper(obj, args);

    System.out.println("售后~~~~~~CGLIB");

    return res;

    }

    }

    总结

    代理模式分为静态代理和动态代理,静态代理只能代理某一种业务,动态代理可以代理各种业务而不用添加新的代理类,动态代理分为JDK动态代理和CGLib动态代理,JDK动态代理类必须实现某个接口,如果没有实现接口则可以使用CGlib实现。

  • 相关阅读:
    OpenLiveWriter博客工具
    mysql主从复制原理分析
    linux mysql主从复制配置
    linux mysql数据库安装
    linux 下安装maven私服
    eclipse新建maven项目和聚合项目
    入门Kubernetes -基础概念
    Java中5种List的去重方法及它们的效率对比,你用对了吗?
    谈一谈程序员的职业发展路线
    虚拟机中如何Linux系统如何访问PC硬盘中的文件(如何将windows下的文件夹挂载到linux虚拟机下)
  • 原文地址:https://www.cnblogs.com/qfchen/p/11201701.html
Copyright © 2020-2023  润新知