JDK动态代理课程笔记

it2023-11-06  77

1.代理模式        代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介的作用。        例如:有A、B、C三个类,A原来可以调用C类的方法,现在因为某种原因C类不允许A类调用其方法,但B类可以调用C类的方法。A类通过B类调用C类的方法。这里C是C的代理。A通过代理B访问C。

2.使用代理模式的作用 1)功能增强:在你原有的功能上,增加了额外的功能。新增加的功能,叫做功能增强。 2)控制访问:在代理中,控制是否可以调用目标对象的方法。

3.实现代理的方式 (1)静态代理        代理类是自己手工实现的,自己创建一个java类,表示代理类。同时所要代理的目标类是确定的(一个代理类代理一个固定的目标类)。        特点:实现简单;容易理解。

模拟一个用户购买U盘的行为: 用户:客户端 商家:代理,代理某个品牌的U盘 厂家:目标类 三者的关系:用户(客户端)——商家(代理)——厂家(目标) 实现步骤: 1.创建一个接口,定义卖U盘的方法,表示厂家和卖家做的事情; 2.创建厂家类,实现1步骤的接口; 3.创建商家,也即代理,也需要实现1步骤中的接口;(商家类中的卖U盘方法中调用厂家类中的卖U盘方法,然后增加需要功能,如加价) 4.创建客户端类,调用商家的方法买一个U盘。

代理类完成的功能:        - 调用目标方法;        - 在目标方法基础上增强功能。

静态代理的缺点:当你的项目中,目标类和代理类很多的时候,有以下缺点:        - 目标类增加,代理类可能也需要成倍的增加。        - 接口中的功能增加或修改,会影响到实现类,如上面所说的厂家类、商家类都需要进行修改。

(2)动态代理        动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的.java源文件。动态代理能够给不同的目标随时创建代理。        动态代理其实就是JDK运行期间,动态创建class字节码并加载到JVM中。        动态代理的特点:不用创建代理类;可以给不同的目标随时创建代理。        动态代理的实现方式常用的有两种:使用JDK动态代理;通过CGLIB动态代理。

1)jdk的动态代理        jdk动态代理是基于Java的反射机制实现的。使用jdk中接口和类实现代理对象的动态创建。        jdk的动态代理要求目标对象必须实现接口,这是java设计上的要求。        从jdk1.3以来,jaba语言通过java.lang.reflect包提供三个类支持代理模式Proxy、Method、和InvocationHandler。

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

       使用JDK的Proxy实现代理,要求目标类与代理类实现相同的接口。若目标类不存在接口,则无法使用该方式实现。但对于无接口的类,要为其创建动态代理,就要使用CGLIB来实现。

4.InvocationHandler接口        InvocationHandler是调用处理器,里面只有一个方法invoke(),invoke()方法表示代理对象要执行的功能代码,代理类要完成的功能就写在invoke()方法中。        代理类完成的功能:调用目标方法;增加额外的功能。

//方法原型 public Object invoke(Object proxy, Method method, Object[] args)

      参数说明:             Object proxy:JDK创建的代理对象,无需赋值。             Method method:目标类中的方法,无需赋值,JDK提供method对象。             Object[] args:目标类中方法的参数,无需赋值,JDK提供。       怎么用:1)创建类实现接口InvocationHandler;                      2)重写invoke()方法,把原来静态代理中代理类要完成的功能,写在invoke方法中。

5.Method        表示方法,确切的说这里是表示目标类中的方法。其作用是通过Method可以执行某个目标类的方法,使用Method.invoke()执行。(注意:这里Method的invoke方法只是刚好和InvocationHandler中的invoke方法同名而已)

Object 方法返回值 = method.invoke(目标对象,方法的参数);

6.Proxy        用来创建代理对象,之前创建对象都是使用new来创建,现在使用Proxy类中的方法代替new的使用。        方法:静态方法newProxyInstance()        作用是:创建代理对象。

//方法原型 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

       参数说明:               ClassLoader loader:类加载器,负责向内存中加载对象的,可以使用反射获取对象的ClassLoader,如a.getClass().getClassLoader()。这里loader表示目标对象的类加载器。               Class<?>[] interfaces:表示目标对象实现的接口,也是通过反射获取的。               InvocationHandler h:是我们自己写的代理类要完成的功能。        返回值:代理对象。

7.实现动态代理的步骤        1)创建接口,定义目标类要完成的功能;        2)创建目标类实现接口;        3)创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能。(调用目标方法;增强功能)        4)使用Proxy类的静态方法,创建代理对象,并把返回值转为接口类型。

8.动态代理实现

package com.lilanlan.service; //第一步,创建目标接口 public interface UsbSell { float sell(int amount); } package com.lilanlan.factory; import com.lilanlan.service.UsbSell; //第二步,创建目标类 public class UsbKingFactory implements UsbSell { @Override public float sell(int amount) { System.out.println("目标类中,执行了目标方法sell"); return 85.0f; } } package com.lilanlan.handler; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; //第三步,实现InvocationHandler接口,完成代理类要做的功能(调用目标方法;增强功能) public class MySellHandler implements InvocationHandler { private Object target = null; public MySellHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //调用目标方法 Object retValue = method.invoke(target,args); //功能增强 if(retValue!=null){ Float price = (Float)retValue; price = price+25; retValue = price; } return retValue; } } package com.lilanlan; import com.lilanlan.factory.UsbKingFactory; import com.lilanlan.handler.MySellHandler; import com.lilanlan.service.UsbSell; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class MainShop { public static void main(String[] args) { //第四步,创建代理对象,使用proxy //1)创建目标对象 UsbSell factory = new UsbKingFactory(); //2)创建InvocationHandler对象 InvocationHandler handler = new MySellHandler(factory); //3)创建代理对象 UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), handler); float price = proxy.sell(1); System.out.println(price); } }

9.掌握 1)什么是动态代理?        通过使用jdk的反射机制,创建代理类的对象,而不用自己创建类文件。        动态:在程序执行时,调用jdk提供的方法才能创建代理类对象。        jdk动态代理,必须有接口,目标类必须实现接口,没有接口时,需要使用cglib动态代理。

2)动态代理能做什么?        可以在不改变原来目标方法功能的前提下,在代理中增强自己的功能代码。        比如:我所在的项目中,有一个功能是其他人写好的,可以使用。但是发现这个功能还有缺点,不能完全满足我项目的需要,我需要自己再增加代码。这时就可以用代理实现原方法的调用,再增加自己的代码,而不用去修改原来的代码文件。

最新回复(0)