磨人的动态代理

为什么一把年纪的我还在坚持学习?因为贫穷。

1 代理

Java 中的代理和生活的代理是很相似的,毕竟软件是用来描述生活的。好比租房子,可以自己找房源,也可以通过中介找。

2 静态代理

每种业务对应一个接口,每个接口对应一个实实在在存在的代理类

(1)IRentingHouse 租房接口

/**
 * 接口:租房
 * 接口用来定义要做什么事
 */
public interface IRentingHouse {

    void rentHosue();

}

(2)RentingHouseImpl

/**
 * 自己找房源就要实现这个接口
 */
public class RentingHouseImpl implements IRentingHouse {
    
    @Override
    public void rentHosue() {
        System.out.println("我要租用一室一厅的房子");
    }
    
}

(3)租房代理类 RentingHouseProxy

/**
 * 中介去实现接口
 * 租房接口对应存在一个的租房代理类,
 * 租车接口对应存在一个租车的代理类,
 * 每种业务都对应一个代理类,代理类里写增强逻辑,使用的时候都要去new一个代理对象,
 * 称为静态代理
 */
public class RentingHouseProxy implements IRentingHouse {

    private IRentingHouse rentingHouse;

    public RentingHouseProxy(IRentingHouse rentingHouse) {
        this.rentingHouse = rentingHouse;
    }

    @Override
    public void rentHosue() {
        // 除了原接口的租房方法,还增强了功能,租房前后都可以干点别的事情
        System.out.println("中介(代理)收取服务费3000元");
        rentingHouse.rentHosue();
        System.out.println("客户信息卖了3毛钱");
    }
}

(4)测试

public class Test {

    public static void main(String[] args) {
        // 明确自己的需求
        IRentingHouse rentingHouse = new RentingHouseImpl();
        // 自己去租用一个一室一厅的房子
        // rentingHouse.rentHosue();

        // 带着需求去找中介
        RentingHouseProxy rentingHouseProxy = new RentingHouseProxy(rentingHouse);
        // 抛头露面的是代理对象了,而不是自己了
        rentingHouseProxy.rentHosue();
    }
}

3 动态代理

不再需要为每个业务创建代理类

3.1 公共部分

(1)IRentingHouse 接口

/**
 * 接口:租房
 * jdk动态代理/cglib动态代理
 */
public interface IRentingHouse {

    void rentHosue();

}

(2)RentingHouseImpl 接口实现类

/**
 * 委托方(委托对象)
 */
public class RentingHouseImpl implements IRentingHouse {

    @Override
    public void rentHosue() {
        System.out.println("我要租用一室一厅的房子");
    }

}

3.2 JDK 动态代理

要求委托对象必须实现接口,因为创建Jdk代理对象需要传参:委托对象的接口

public class JdkProxy {

    public static void main(String[] args) {

        IRentingHouse rentingHouse = new RentingHouseImpl();  // 委托对象---委托方

        // 通过 JDK 动态代理生成代理对象,需要提供委托方对象,委托方想要执行的方法,方法的参数
        IRentingHouse jdkProxy = (IRentingHouse) Proxy.newProxyInstance(rentingHouse.getClass().getClassLoader(), rentingHouse.getClass().getInterfaces(),
            (proxy, method, args1) -> {
                // 增强逻辑
                System.out.println("中介(代理)收取服务费3000元");
                // 调用原有业务逻辑
                Object result = method.invoke(rentingHouse);
                System.out.println("客户信息卖了3毛钱");
                return result;
            });
        // 从代理对象工厂获取代理对象
        //IRentingHouse jdkProxy = (IRentingHouse) ProxyFactory.getInstance().getJdkProxy(rentingHouse);
        // 帮委托方执行方法
        jdkProxy.rentHosue();
    }
}

代理看似没省代码?只有一个业务,确实没省。如果是上千百万个业务,那就棒棒的了。

3.3 Cglib 动态代理 

需要引入 cglib 依赖

<!--引入cglib依赖-->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.1_2</version>
</dependency>

不要求委托对象必须实现接口,因为创建Cglib代理对象时不需要用到接口

public class CglibProxy {

    public static void main(String[] args) {
        // 委托对象
        IRentingHouse rentingHouse = new RentingHouseImpl();  

        // 获取rentingHouse对象的代理对象,
        // Enhancer类似于JDK动态代理中的Proxy,Enhancer 增强器
        // 通过实现接口MethodInterceptor能够对各个方法进行拦截增强,类似于JDK动态代理中的InvocationHandler
        IRentingHouse cglibProxy = (IRentingHouse) Enhancer.create(rentingHouse.getClass(), (MethodInterceptor) (o, method, objects, methodProxy) -> {
            Object result;
            System.out.println("中介(代理)收取服务费3000元");
            result = method.invoke(rentingHouse, objects);
            System.out.println("客户信息卖了3毛钱");
            return result;
        });
        // 使用工厂来获取代理对象
        // IRentingHouse cglibProxy = (RentingHouseImpl) ProxyFactory.getInstance().getCglibProxy(rentingHouse);
        cglibProxy.rentHosue();
    }

3.4 通过工厂生成代理对象

/**
 * 代理对象工厂:生成代理对象的
 */

public class ProxyFactory {

    // 构造函数私有化
    private ProxyFactory(){}

    // 创建静态工厂对象
    private static ProxyFactory proxyFactory = new ProxyFactory();

    public static ProxyFactory getInstance() {
        return proxyFactory;
    }

    /**
     * Jdk动态代理
     * @param obj  委托对象
     * @return   代理对象
     */
    public Object getJdkProxy(Object obj) {

        // 获取代理对像,第 3 个参数为 InvocationHandler接口,采用了匿名内部类去实例化
        // 第 2 个参数为委托对象的接口,所以委托对象必须实现接口,这是其与cglib的区别之一
        return  Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
            (proxy, method, args) -> {
                Object result;
                // 写增强逻辑
                System.out.println("中介(代理)收取服务费3000元");
                // 调用原有业务逻辑
                result = method.invoke(obj,args);
                System.out.println("客户信息卖了3毛钱");
                return result;
            });
    }

    /**
     * 使用cglib动态代理生成代理对象
     * @param obj 委托对象
     * @return 代理对象
     */
    public Object getCglibProxy(Object obj) {
        // 参数只需获取委托对象的class,不需要委托对象实现接口
        return  Enhancer.create(obj.getClass(), (MethodInterceptor) (o, method, objects, methodProxy) -> {
            Object result;
            System.out.println("中介(代理)收取服务费3000元");
            result = method.invoke(obj,objects);
            System.out.println("客户信息卖了3毛钱");
            return result;
        });
    }
}

4 代理模式在 MyBatis 中的体现

代理模式是 MyBatis 的核心使用模式,正式由于这个模式,我们只需编写 Mapper.java 接口,不需要编写实现类,直接由 MyBatis 后台帮我们完成具体的 SQL 的执行。

当我们使用 Configuration 的 getMapper 方法时,会调用 mapperRegistry.getMapper

5 代理模式在事务中的使用

方法内部调用的方法的事务会失效,与动态代理有关

 

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值