嘉明的SSM学习Day1之代理

代理

代理的概念

代理的理解

例子:你需要买一个U盘,现实中大多数情况都是从商家里买,而不是去工厂里面买。
因为商家和厂家的目的都是出于销售U盘(用共同目的),所以商家就成为了我们的代理
客户–商家(代理)–厂家(目标)

代理作用

一、增加功能
比如:
1:商家从厂家进货,商家卖U盘的价格肯定要比厂家贵从而获取利润。价格的提升就是功能增强的体现。
2:客户购买U盘后 商家可以返回优惠卷给客服,这也是增强功能的体现。

二、访问控制
因为如果购买数量不够多,厂家是不愿意当个售卖的,但商家可以一次进货数量很多,所以厂家才愿意出售。而且商家有利润也不一定让你接触到厂家。商家不让你直接接触到厂家,而是要到他那里消费,这是一种控制访问。

代理又分为静态代理和动态代理。

静态代理

静态代理的优缺点:
优点:
1.实现起来简单,理解起来容易

缺点:
1.如果在接口中添加新的方法,代理类和目标类都需要修改很多地方很麻烦(因为继承了接口,接口中的方法就都要实现,否则会报错)
2.当目标类增加,代理类也要成倍增加,导致代理数量过多。后续修改起来麻烦。(比如U盘的厂家多了一个,有3个代理就要增加3个该厂家代理类。数目少还好说,如果数目多,毁灭吧qwq)

静态代理的代码实现

按照上面用U盘举的例子,用代码来实现一下静态代理,便于理解。

1.首先先创建一个接口,用来表示一个U盘的单价

package com.zjm.service;

public interface UsbSell {
    //定义一个sell方法用于售卖usb,里面的功能实现需要厂家和商家实现
    //amount表示购买U盘的数量,返回值表示U盘的价钱。要注意的是厂家和商家出售的单价是不一样的。
    float sell(int amount);
}

2.然后定义一个厂家类(目标类),要实现接口的方法,表明出厂价时多少。

package com.zjm.factory;

import com.zjm.service.UsbSell;

public class UsbFactory implements UsbSell {
    //实现service中的sell方法
    @Override
    public float sell(int amount) {
        //厂家售卖U盘的单价为85元
        System.out.println("厂家售卖U盘的单价为85元");
        return 85.0f;
    }
}

3.然后再定义一个商家类(代理类),通过调用工厂类,增加价格和返回优惠卷(功能增强),需要注意的是,代理类可以有很多个。 为了方便这里只写了一个。例如一个U盘的厂家可以给某宝 、某东、某多多等代理。

package com.zjm.business;

import com.zjm.factory.UsbFactory;
import com.zjm.service.UsbSell;

public class UsbSeller implements UsbSell {
    private UsbFactory factory = new UsbFactory();
    @Override
    public float sell(int amount) {
        //获取厂家U盘的单价
        float price =factory.sell(amount);
        //在厂家售卖单价的基础上增加25元,获取利润(增强功能)
        price = price + 25;
        //返回优惠卷(增强功能)
        System.out.println("恭喜你购买成功,商家返回您一个5元优惠卷,欢迎下次光临");
        //返回商家售卖的价格
        return price;
    }
}

4.最后定义一个购买类,用来表示用户购买的动作(主程序)。

package com.zjm.shop;

import com.zjm.business.UsbSeller;

public class Shopping {
    public static void main(String[] args) {
        UsbSeller seller = new UsbSeller();
        float usbPrice = seller.sell(1);
        System.out.println("客户从商家购买U盘的单价为:" + usbPrice);
    }
}
    

5.运行结果
在这里插入图片描述
从上面的过程可以大致了解代理在程序中的作用就是调用目标类增强功能。

再来声明一下静态代理的缺点

缺点:
1.如果在接口中添加新的方法,代理类和目标类都需要修改很多地方很麻烦(因为继承了接口,接口中的方法就都要实现,否则会报错)
2.当目标类增加,代理类也要成倍增加,导致代理数量过多。后续修改起来麻烦。(比如U盘的厂家多了一个或者多了一个产品,有3个代理就要增加3个该厂家代理类。数目少还好说,如果数目多,毁灭吧qwq)

因为静态代理的缺点在现代的程序中还是比较致命的。
于是动态代理就出现了!!!

动态代理

动态代理的概念

上面说到静态代理虽然很好理解,但是缺点还是比较致命的,所以我们为了简化开发就要使用动态代理。

先来介绍一下动态代理。
1.什么是动态代理 ?
使用jdk的反射机制,创建对象的能力, 创建的是代理类的对象。 而不用你创建类文件。不用写java文件。
动态:在程序执行时,调用jdk提供的方法才能创建代理类的对象。

动态代理的优缺点

优点:
1.动态代理的是运用JDK的反射机制来自动创建目标类的代理,因此在动态代理中,我们只需要提供相关的目标参数就可以执行程序了,不需要再创建代理类。

2.动态代理中目标类即使很多, 代理类数量可以很少,当你修改了接口中的方法时,不会影响代理类。
缺点:
理解起来比较困难。如果利用JDK实现动态代理的话,反射恰是JAVA中比较难理解的一个知识点,所以需要一定的基础才能实现动态代理。

动态代理的实现

1.jdk动态代理: 使用java反射包中的类和接口实现动态代理的功能。
反射包 java.lang.reflect , 里面有三个类 : InvocationHandler , Method, Proxy。

2.cglib动态代理: cglib是第三方的工具库, 创建代理对象。
cglib的原理是继承, cglib通过继承目标类,创建它的子类,在子类中重写父类中同名的方法, 实现功能的修改。因为cglib是继承,重写方法,所以要求目标类不能是final的, 方法也不能是final的。
cglib的要求目标类比较宽松, 只要能继承就可以了。cglib在很多的框架中使用, 比如 mybatis ,spring框架中都有使用。

这次我们要使用的就是JDK反射机制实现动态代理。

JDK反射机制的介绍

用JDK反射机制实现动态代理,需要用到起反射包java.lang.reflect,里面有三个类是需要我们理解的InvocationHandler,Method,proxy
1.InvocationHandler接口(调用处理器):就一个方法invoke()
invoke():表示代理对象要执行的功能代码。你的代理类要完成的功能就写在invoke()方法中。
public Object invoke(Object proxy, Method method, Object[] args)
参数: Object proxy:jdk创建的代理对象,无需赋值。
Method method:目标类中的方法,jdk提供method对象的
Object[] args:目标类中方法的参数,jdk提供的。

2.Method类:表示方法的,确切的说就是目标类中的方法。这个可以通过对InvocationHandler接口重写来实现调用。
作用:通过Method可以执行某个目标类的方法,Method.invoke();
method.invoke(目标对象,方法的参数)

3.Proxy类:核心的对象,创建代理对象。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h) 参数:1.ClassLoader loader 类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader,比如类a , a.getCalss().getClassLoader(),目标对象的类加载器 2. Class<?>[] interfaces: 接口, 目标对象实现的接口,也是反射获取的。
3. InvocationHandler h : 我们自己写的,代理类要完成的功能。 也就是重写InvocationHandler接口的那个类

动态代理的代码实现

1.创建接口实现目标类功能

package com.zjm.service;

public interface UsbSell {
    //定义一个sell方法用于售卖usb,里面的功能实现需要厂家和商家实现
    //amount表示购买U盘的数量,返回值表示U盘的价钱。要注意的是厂家和商家出售的单价是不一样的。
    float sell(int amount);
}

2.创建目标类

package com.zjm.factory;

import com.zjm.service.UsbSell;

public class UsbFactory implements UsbSell {
    //实现service中的sell方法
    @Override
    public float sell(int amount) {
        //厂家售卖U盘的单价为85元
        System.out.println("厂家售卖U盘的单价为85元");
        return 85.0f;
    }
}

3.创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能

package com.zjm.handler;

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

public class MyHandler implements InvocationHandler {
    private Object target;
    public MyHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //通过method里的invoke调用类中方法
        Object res = null;
        res = method.invoke(target,args);
        if (res != null){
            float price = (Float)res;
            price = price + 25;
            res = price;
        }
        System.out.println("谢谢惠顾,现返回您一个5元优惠卷,欢迎下次光临");
        //返回价格
        return res;
    }
}

4.使用Proxy类的静态方法,创建代理对象。并把返回值转为接口类型。(注意最后要转变为接口类型!!!)

package com.zjm.main;

import com.zjm.factory.UsbFactory;
import com.zjm.handler.MyHandler;
import com.zjm.service.UsbSell;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Shop {
    public static void main(String[] args)  {
        //创建目标对象
        UsbSell factory = new UsbFactory();
        //创建InvocationHandler对象
        InvocationHandler handler = new MyHandler(factory);
        //创建代理对象
        UsbSell proxy = (UsbSell) Proxy.newProxyInstance(
                factory.getClass().getClassLoader(),
                factory.getClass().getInterfaces(),
                handler);

        float price = proxy.sell(1);
        System.out.println("通过动态代理的返回值为:"+price);
    }
}

运行结果:
在这里插入图片描述

总结

代理在SSM框架中是十分重要的,因此在学习框架之前要打好基础。特别是动态代理中通过JDK反射机制实现动态代理需要我们稍微的去理解,其实无非就是三样东西InvocationHandler接口(调用处理器)、Method类、.Proxy类,只要理解好这种动态代理的方式其实也不算特别难。学习编程并非一蹴而就,而是需要我们日积月累。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值