一、概述1、什么是代理?关于微商代理,首先,我们从他们那里买东西,我们通常不知道他们背后的厂家是谁,也就是说,“客户”对我们来说是看不见的;人是目标客户,相当于为厂家“过滤”了客户群。我们进一步抽象微商代理和厂商,前者可以抽象为代理类,后者可以抽象为委托类(代理类)。使用代理,通常有两个好处,可以对应我们提到的微商代理的两个特点:好处一:可以隐藏委托类的实现;优点二:客户端和委托类之间的解决方案可以实现耦合,不需要修改委托类的代码就可以做一些额外的处理。2.静态代理如果代理类在程序运行前就已经存在,那么这种代理方式就称为静态代理。在这种情况下,代理类通常在Java代码中定义。通常,静态代理中的代理类和委托类实现相同的接口或派生自相同的父类。下面我们以Vendor类代表厂商,以BusinessAgent类代表微商代理来介绍静态代理的简单实现。委托类和代理类都实现了Sell接口。Sell接口定义如下:publicinterfaceSell{voidsell();voidad();}Vendor类定义如下:publicclassVendorimplementsSell{publicvoidsell(){System.out.println("Insellmethod");}publicvoidad(){System,out.println("admethod")}}代理类BusinessAgent定义如下:"admethod")}}从BusinessAgent类的定义中,我们可以了解到静态代理可以通过聚合来实现,让代理类持有对委托类的引用。我们考虑一下这个需求:在Vendor类中添加过滤功能,只向大学生销售商品。通过静态代理,我们可以在不修改Vendor类代码的情况下实现,只需要在BusinessAgent类中的sell方法中添加一个判断即可:.sell();}}...}这对应了我们上面提到的使用代理的第二个好处:可以实现客户端和委托类的解耦,而且不需要修改委托类代码就可以做到。一些额外的处理。静态代理的局限性在于必须在运行前编写代理类。接下来重点介绍运行时生成代理类的动态代理方法。二、动态代理1、什么是动态代理?代理类在程序运行时创建的代理方法称为动态代理。也就是说,在这种情况下,代理类并没有在Java代码中定义,而是在运行时根据我们在Java代码中的“指令”动态生成的。与静态代理相比,动态代理的优点是可以方便的统一处理代理类的功能,无需修改各个代理类的功能。这么说比较抽象,下面用一个例子来介绍一下动态代理的这个优势是如何体现的。现在,假设我们要实现这样一个需求:在委托类中的方法执行前输出“before”,执行后输出“after”。我们还是以上面例子中的Vendor类作为委托类,BusinessAgent类作为代理类进行介绍。首先,让我们使用一个静态代理来实现这个需求。相关代码如下:"after");}publicvoidad(){System.out.println("before");mVendor.ad();System.out.println("after");}}从上面的代码我们可以理解通过静态代理实现我们的需求需要我们在每个方法中添加相应的逻辑。这里只有两种方法,所以工作量不会太大。如果Sell接口包含数百个方法呢?这时候使用静态代理会写很多冗余代码。通过使用动态代理,我们可以做一个“统一指令”,统一处理所有代理类的方法,而不用一个一个地修改每个方法。下面介绍一下如何使用动态代理来实现我们的需求。2.使用动态代理(1)InvocationHandler接口在使用动态代理时,我们需要在代理类和委托类之间定义一个中介类。这个中间类需要实现InvocationHandler接口。这个接口的定义如下:publicinterfaceInvocationHandler{Objectinvoke(Objectproxy,Methodmethod,Object[]args);}从名字InvocationHandler我们可以知道实现这个接口的中间类是作为“调用处理程序”使用的。当我们调用代理类对象的方法时,这个“调用”会转到invoke方法中,代理类对象作为代理参数传入,参数method标识我们调用的是代理类的哪个方法,以及args是这个方法参数的方法。这样我们对代理类中所有方法的调用都会变成对invoke的调用,这样我们就可以在invoke方法中加入统一的处理逻辑(也可以根据方法参数对不同的代理类方法做不同的处理)。因此,我们只需要在中间类的invoke方法的实现中输出“before”,然后调用委托类的invoke方法,再输出“after”即可。让我们一步一步地实施它。(2)委托类的定义在动态代理模式下,要求委托类必须实现一定的接口。这里我们实现了Sell接口。委托Vendor类的定义如下:publicclassVendorimplementsSell{publicvoidsell(){System.out.println("Insellmethod");}publicvoidad(){System,out.println("admethod")}}(3)中介上面我们提到的class,中间类必须实现InvocationHandler接口作为调用处理器来“拦截”对代理类方法的调用。中介类定义如下:publicclassDynamicProxyimplementsInvocationHandler{privateObjectobj;//obj为委托类对象;publicDynamicProxy(Objectobj){this.obj=obj;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println("before");Objectresult=method.invoke(obj,args);System.out.println("after");returnresult;}}从上面的代码可以看出,中间类持有委托类对象的引用,在invoke方法中,调用了委托类对象的对应方法(第11行).看到这里是不是觉得似曾相识?通过聚合持有委托类对象引用,最终将外部调用invoke转换为委托类对象。称呼。这不就是我们上面介绍的静态代理的实现吗?实际上,中介类和委托类构成了静态代理关系。在这种关系中,中介类是代理类,委托类是委托类;中介类也构成静态代理关系,其中中介类是委托类,代理类是代理类。也就是说动态代理关系由两组静态代理关系组成,这就是动态代理的原理。下面介绍一下如何“指示”动态生成代理类。(4)动态生成代理类动态生成代理类的相关代码如下:publicclassMain{publicstaticvoidmain(String[]args){//创建一个中间类的实例DynamicProxyinter=newDynamicProxy(newVendor());//加入这句话会生成一个$Proxy0.class文件,这个文件就是动态生成的代理类文件System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");//获取代理classinstancesellSellsell=(Sell)(Proxy.newProxyInstance(Sell.class.getClassLoader(),newClass[]{Sell.class},inter));//通过代理类对象调用代理类方法,实际上会去到invoke方法调用sell.sell();sell.ad();}}在上面的代码中,我们调用了Proxy类的newProxyInstance方法,获取了一个代理类实例。这个代理类实现了我们指定的接口并将方法调用分派给指定的调用处理程序。该方法的声明如下:publicstaticObjectnewProxyInstance(ClassLoaderloader,Class>[]interfaces,InvocationHandlerh)throwsIllegalArgumentException该方法三个参数的含义如下:loader:定义代理类的ClassLoder;interfaces:代理类h:callProcessor实现的接口列表,也就是我们上面定义的实现了InvocationHandler接口的类实例。让我们运行一下,看看我们的动态代理是否可以正常工作。我这里运行后的输出是:说明我们的动态代理确实起作用了。动态代理的原理我们在上面已经简单的讲过了,这里简单总结一下:首先通过newProxyInstance方法获取代理类实例,然后我们可以通过代理类实例调用代理类的方法,调用代理类的方法实际上会调用中介类(调用处理器)的invoke方法。在invoke方法中,我们调用delegate类对应的方法,我们可以添加自己的处理逻辑。
