设计模式 代理模式(静态代理 动态代理) 与 Spring Aop源码分析 具体是如何创建Aop代理的

代理模式

代理模式是一种结构型设计模式,它通过创建一个代理对象来控制对真实对象的访问。这种模式可以用于提供额外的功能操作,或者扩展目标对象的功能。
在代理模式中,代理对象与真实对象实现相同的接口,以便在任何地方都可以使用相同的接口来调用真实对象的方法。这样做的好处是可以在不改变原始代码的情况下,增加或修改代码的行为。

根据创建代理对象的方式和时机,代理模式可以被分为静态代理、动态代理等类型。其中,静态代理是由程序员在编译时期就定义好的代理类,而动态代理则是在程序运行时期通过Java反射机制动态生成的。

在实际生活中,有许多应用了代理模式的场景,例如租房、卖房、家政等业务,通常由中介机构作为代理来进行操作。

静态代理

静态代理在编译期间就已经确定代理类的代码。具体来说,要实现静态代理需要手动编写代理类的代码,因此这种方式的灵活性相对较差,但由于代理类是直接编写的,所以其运行效率较高。

首先定义购房者的行为

java 复制代码
/**
 * 购房者
 *
 * @author LionLi
 */
public interface Homebuyer {

    /**
     * 需求
     */
    String need();

    /**
     * 购买
     */
    void buy();
}

定义真实购房者

java 复制代码
/**
 * 购房者 张三
 *
 * @author LionLi
 */
public class Zhangsan implements Homebuyer {

    /**
     * 需求
     */
    @Override
    public String need() {
        String need = "100平以上三室两厅两卫";
        System.out.println("张三: " + need);
        return need;
    }

    /**
     * 购买
     */
    @Override
    public void buy() {
        System.out.println("张三: 我已付款");
    }
}
java 复制代码
/**
 * 购房者 王五
 *
 * @author LionLi
 */
public class Wangwu implements Homebuyer {

    /**
     * 需求
     */
    @Override
    public String need() {
        String need = "70平左右两室一厅";
        System.out.println("王五: " + need);
        return need;
    }

    /**
     * 购买
     */
    @Override
    public void buy() {
        System.out.println("张三: 我已付款");
    }
}

定义房产中介

java 复制代码
/**
 * 房产中介代理人
 *
 * @author LionLi
 */
public class HouseAgentProxy implements Homebuyer {
    private Homebuyer homebuyer;

    public HouseAgentProxy(Homebuyer homebuyer) {
        this.homebuyer = homebuyer;
    }

    @Override
    public String need() {
        System.out.println("中介: 你对房子有什么需求 放心交给我");
        String need = homebuyer.need();
        System.out.println("中介: 寻找房源中........");
        System.out.println("中介: 寻找房源中........");
        System.out.println("中介: 寻找房源中........");
        String str = "中介: 为您找到" + need + "的房子";
        System.out.println(str);
        return str;
    }

    @Override
    public void buy() {
        System.out.println("中介: 请支付购买房子");
        homebuyer.buy();
        System.out.println("中介: 合同生效中.....");
        System.out.println("中介: 房证办理中.....");
        System.out.println("中介: 恭喜您 这套房子属于您了");
    }
}

测试

java 复制代码
/**
 * @author LionLi
 */
public class Test {

    public static void main(String[] args) {
        Homebuyer zhangsan = new Zhangsan();
        HouseAgentProxy agent1 = new HouseAgentProxy(zhangsan);
        agent1.need();
        agent1.buy();
        System.out.println("-----------------------------");
        Homebuyer wangwu = new Wangwu();
        HouseAgentProxy agent2 = new HouseAgentProxy(wangwu);
        agent2.need();
        agent2.buy();
    }
}

两位购房者分别根据需求在中介的带领下买到了房子 真是可喜可贺啊

动态代理

动态代理允许在运行时动态地创建代理对象。代理对象可以在调用实际对象的方法前后执行一些额外的操作,比如日志记录、权限检查等。
动态代理的实现方式有两种:基于接口和基于继承。基于接口的方式是最常用的,它使用Java的反射机制来实现代理对象。基于继承的方式则需要创建一个实现了目标类接口的子类,并重写其中的方法。
优点: 可以降低系统的耦合度,提高代码的可维护性和可扩展性。

缺点: 需要使用反射机制,性能比静态代理略低。

首先定义购房者的行为与实际购房者

使用上方代码不变

定义房产中介

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态房产中介代理人
 *
 * @author LionLi
 */
public class DynamicHouseAgentProxy implements InvocationHandler {
    private Homebuyer homebuyer;

    public Homebuyer getInstance(Homebuyer homebuyer) {
        this.homebuyer = homebuyer;
        return (Homebuyer) Proxy.newProxyInstance(homebuyer.getClass().getClassLoader(), homebuyer.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("need")) {
            System.out.println("中介: 你对房子有什么需求 放心交给我");
            String need = (String) method.invoke(homebuyer, args);
            System.out.println("中介: 寻找房源中........");
            System.out.println("中介: 寻找房源中........");
            System.out.println("中介: 寻找房源中........");
            String str = "中介: 为您找到" + need + "的房子";
            System.out.println(str);
            return str;
        } else if (method.getName().equals("buy")) {
            System.out.println("中介: 请支付购买房子");
            Object invoke = method.invoke(homebuyer, args);
            System.out.println("中介: 合同生效中.....");
            System.out.println("中介: 房证办理中.....");
            System.out.println("中介: 恭喜您 这套房子属于您了");
            return invoke;
        }
        return null;
    }
}

测试

java 复制代码
/**
 * @author LionLi
 */
public class Test {

    public static void main(String[] args) {
        DynamicHouseAgentProxy agent = new DynamicHouseAgentProxy();
        Homebuyer zhangsan = new Zhangsan();
        Homebuyer proxy1 = agent.getInstance(zhangsan);
        proxy1.need();
        proxy1.buy();
        System.out.println("-----------------------------");
        Homebuyer wangwu = new Wangwu();
        Homebuyer proxy2 = agent.getInstance(wangwu);
        proxy2.need();
        proxy2.buy();
    }

}

结果不变 两位购房者成功买到房子

Cglib动态代理

其他代码不变只变更中介类

java 复制代码
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 动态房产中介代理人
 *
 * 这里由于cglib已经不支持jdk17了 所以我们使用spring内部自带的cglib工具
 *
 * @author LionLi
 */
public class DynamicHouseAgentProxy implements MethodInterceptor {

    public Homebuyer getInstance(Homebuyer homebuyer) {
        Enhancer enhancer = new Enhancer();
        // 设置继承父类
        enhancer.setSuperclass(homebuyer.getClass());
        // 设置回调
        enhancer.setCallback(this);
        return (Homebuyer) enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        if (method.getName().equals("need")) {
            System.out.println("中介: 你对房子有什么需求 放心交给我");
            String need = (String) proxy.invokeSuper(obj, args);
            System.out.println("中介: 寻找房源中........");
            System.out.println("中介: 寻找房源中........");
            System.out.println("中介: 寻找房源中........");
            String str = "中介: 为您找到" + need + "的房子";
            System.out.println(str);
            return str;
        } else if (method.getName().equals("buy")) {
            System.out.println("中介: 请支付购买房子");
            Object invoke = proxy.invokeSuper(obj, args);
            System.out.println("中介: 合同生效中.....");
            System.out.println("中介: 房证办理中.....");
            System.out.println("中介: 恭喜您 这套房子属于您了");
            return invoke;
        }
        return null;
    }
}

Spring中代理模式的应用

要说起Spring中的代理模式 要首当其冲的肯定是AOP了 接下来我们来看看在AOP中是如何使用代理模式的

这里涉及到一个注解 学过AOP的都知道 如果需要开启AOP那么需要增加这个注解

通过搜索找到 AspectJAutoProxyRegistrar 类, 该方法的作用就是往Spring容器中添加一个 BeanDefinition 类型为 AnnotationAwareAspectJAutoProxyCreator 用于创建代理对象


接下来我们进入 AnnotationAwareAspectJAutoProxyCreator 看看是如何创建代理的

由于 AnnotationAwareAspectJAutoProxyCreator 中并没有创建代理的方法 那么我们只能向上去父类里找, 通过不断的探索在 AnnotationAwareAspectJAutoProxyCreator -> AspectJAwareAdvisorAutoProxyCreator -> AbstractAdvisorAutoProxyCreator -> AbstractAutoProxyCreator 抽象类 AbstractAutoProxyCreator 中找到了 createProxy 方法

此方法是bean初始化的前置处理器 postProcessBeforeInstantiation 中使用的, 也就是说bean在初始化之前, 代理对象就已经创建好了

进入 createProxy 方法

进入 buildProxy 方法


这里我们可以看出 实际的代理对象是通过 ProxyFactory 工厂的 getProxyClassgetProxy 两个方法创建的

我们来看一下这两个方法具体实现

通过 getProxyClass 方法一直往下点 找到最终创建方法 DefaultAopProxyFactory#createAopProxy 为止


最后我们来分析最终是如何创建代理对象的

相关推荐
晨米酱5 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
数据智能老司机10 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机11 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机11 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机11 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
使一颗心免于哀伤11 小时前
《设计模式之禅》笔记摘录 - 21.状态模式
笔记·设计模式
数据智能老司机1 天前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
烛阴1 天前
【TS 设计模式完全指南】懒加载、缓存与权限控制:代理模式在 TypeScript 中的三大妙用
javascript·设计模式·typescript
李广坤1 天前
工厂模式
设计模式