Spring代理设计模式

代理设计模式

概念

将核心功能与辅助功能(事务、日志、性能监控代码)分离,达到核心业务功能更纯粹、辅助业务功能可复用。

图解:

Spring代理设计模式_第1张图片

静态代理设计模式

通过代理类的对象,为原始类的对象(目标类的对象)添加辅助功能,更容易更换代理实现类、利于维护。

图解:

Spring代理设计模式_第2张图片

  • 代理类 = 实现原始类相同接口 + 添加辅助功能 + 调用原始类的业务方法。

  • 静态代理的问题:

    • 代理类数量过多,不利于项目的管理。
    • 多个代理类的辅助功能代码冗余,修改时,维护性差。

动态代理设计模式

动态创建代理类的对象,为原始类的对象添加辅助功能。

JDK动态代理实现(基于接口)

JDK动态代理实现(基于接口) 代理对象和真实对象的关系 像是兄弟 代理对象 对真实对象进行增强

//目标
final OrderService os = new OrderServiceImpl();
//额外功能
//1.设置回调函数(额外功能代码)
InvocationHandler handler = new InvocationHandler(){
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
        System.out.println("start...");
        method.invoke(os, args);
         System.out.println("end...");
        return null;
    }
};
//2.创建动态代理类
Object proxyObj = Proxy.newProxyInstance(ClassLoader , Interfaces , InvocationHandler);

代码演示:

接口

package com.weige.javaskillpoint.service;

public interface Marry {

    public void marry();

    public void lover();

    public void money(String money1,String money2);

}

真实对象

package com.weige.javaskillpoint.service.impl;

import com.weige.javaskillpoint.service.Marry;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class My implements Marry {
    @Override
    public void marry() {
        log.info("与喜欢的人结婚是人生中最幸福的事,没有之一!");
    }

    @Override
    public void lover() {
        log.info("魏凯爱寒");
    }

    @Override
    public void money(String money1, String money2) {
        log.info("爱情的价格是:" + money1 + "," + money2);
    }

}

封装一个工具类

package com.weige.javaskillpoint.config;

import com.weige.javaskillpoint.service.Marry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.cglib.proxy.Proxy;

import java.lang.reflect.Method;
import java.util.Arrays;

@Slf4j
public class JdkProxy implements InvocationHandler {
    //真实对象   被代理的对象
    private Object target;

    //把真实对象传进来
    public Object getProxy(Object target) {
        this.target = target;
        // 返回代理对象
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }


    //对真实对象的功能增强
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 保证是My对象才能进行增强
        if (target instanceof Marry) {
            // 对My对象的marry方法进行增强
            if(method.getName().equals("marry")){
                log.info("结婚之前的准备工作:拍婚纱照,领结婚证,举行婚礼" );
                Object result = method.invoke(target, args);
                log.info("结婚过后:老婆说什么都是对的" );
                return result;
            }
            // 对My对象的lover方法进行增强
            if(method.getName().equals("lover")){
                // 不进行逻辑操作 直接调用原有方法逻辑
                Object result = method.invoke(target, args);
                return result;
            }
            // 对My对象的money方法进行增强(获取参数 修改参数等)
            if(method.getName().equals("money")){
                log.info("方法参数为:" + Arrays.toString(args));
                // 对My对象中的money方法参数进行修改
                args[1] = "无价!" ;
                return method.invoke(target, args);
            }

        }
        return null;
    }

}

测试

@Test
    public void TestJdkProxy() {
            //真实对象
            My my = new My();
            JdkProxy jdkProxy = new JdkProxy();
            //得到代理对象
            Marry proxy = (Marry) jdkProxy.getProxy(my);

            //调用代理对象的方法
            proxy.marry();
            proxy.lover();
            proxy.money("一个亿!","二个亿!");
    }

结果:

在这里插入图片描述

JDK动态代理实现(基于接口)

CGlib动态代理实现(基于继承) 代理对象和真实对象的关系 就像是 父子

final OrderService os = new OrderServiceImpl();
Enhancer cnh = new Enhancer();//1.创建字节码曾强对象
enh.setSuperclass(os.getClass());//2.设置父类(等价于实现原始类接口)
enh.setCallback(new InvocationHandler(){//3.设置回调函数(额外功能代码)
    @Override
    public Object invoke(Object proxy , Method method, Object[] args) throws Throwable{
        System.out.println("start...");
        Object ret = method.invoke(os,args);
        System.out.println("end...");
        return ret;
    }
});
OrderService proxy = (OrderService)enh.create();//4.创建动态代理类
proxy.createOrder();

代码演示:

接口

package com.weige.javaskillpoint.service;

public interface Marry {

    public void marry();

    public void lover();

    public void money(String money1,String money2);

}

真实对象

package com.weige.javaskillpoint.service.impl;

import com.weige.javaskillpoint.service.Marry;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class My implements Marry {
    @Override
    public void marry() {
        log.info("与喜欢的人结婚是人生中最幸福的事,没有之一!");
    }

    @Override
    public void lover() {
        log.info("魏凯爱寒");
    }

    @Override
    public void money(String money1, String money2) {
        log.info("爱情的价格是:" + money1 + "," + money2);
    }

}

封装一个工具类

package com.weige.javaskillpoint.config;

import com.weige.javaskillpoint.service.Marry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;

import java.lang.reflect.Method;
import java.util.Arrays;
@Slf4j
public class CglibProxy implements InvocationHandler {
    //真实对象
    private Object target;

    //传入真实对象 得到代理对象
    public Object getProxy(Object target){
        this.target = target;
        //1.创建字节码曾强对象
        Enhancer enhancer = new Enhancer();
        //2.设置父类(等价于实现原始类接口)
        enhancer.setSuperclass(target.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //返回代理对象
        return enhancer.create();
    }
    
    //真实对象方法增强
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        // 保证是My对象才能进行增强
        if (target instanceof Marry) {
            // 对My对象的marry方法进行增强
            if(method.getName().equals("marry")){
                log.info("结婚之前的准备工作:拍婚纱照,领结婚证,举行婚礼" );
                Object result = method.invoke(target, objects);
                log.info("结婚过后:老婆说什么都是对的" );
                return result;
            }
            // 对My对象的lover方法进行增强
            if(method.getName().equals("lover")){
                // 不进行逻辑操作 直接调用原有方法逻辑
                Object result = method.invoke(target, objects);
                return result;
            }
            // 对My对象的money方法进行增强(获取参数 修改参数等)
            if(method.getName().equals("money")){
                log.info("方法参数为:" + Arrays.toString(objects));
                // 对My对象中的money方法参数进行修改
                objects[1] = "无价!" ;
                return method.invoke(target, objects);
            }

        }
        return null;
    }
}

测试

@Test
    public void TestCglibProxy () {
        //真实对象
        My my = new My();
        //工具类对象
        CglibProxy cglibProxy = new CglibProxy();
        //得到代理对象
        My proxy = (My) cglibProxy.getProxy(my);

        //调用代理对象的方法
        proxy.marry();
        proxy.lover();
        proxy.money("一个亿!","二个亿!");
    }

结果:

Spring代理设计模式_第3张图片

静态代理和动态代理的对比

  • 灵活性: 动态代理更加灵活,不需要必须实现接口,可以直接代理实现类,并且可以不需要针对每个目标类都创建一个代理类。另外,静态代理中,接口一旦新增加方法,目标对象和代理对象都要进行修改,这是非常麻烦的!
  • JVM 层面 :静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。而动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

JDK 动态代理和 CGLIB 动态代理对比

  • JDK 动态代理只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类。 另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法。
  • 就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。

总结

  • 动态代理解决了静态代理创建过多的代理类导致开发效率降低的问题
  • 动态代理的角色和静态代理的是相同的
  • 动态代理的代理类是动态生成的,静态代理的代理类是我们提前写好的
  • 一个动态代理 , 一般代理某一类业务
  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情
  • 公共的业务由代理来完成,实现了业务的分工
  • 公共业务发生扩展时变得更加集中和方便

你可能感兴趣的:(Spring,Boot,spring,设计模式,java)