Java代理方式——静态代理和动态代理详解

来源:互联网 发布:淘宝在线云客服入口 编辑:程序博客网 时间:2024/06/08 09:11

Java代理方式——动态代理和静态代理详解

在学习spring的时候,我们知道Spring主要有两大思想:一个是IoC ,另一个就是AOP。对于IOC,主要的就是依赖注入(在这里就不说了),而对于Spring的核心AOP来说,其主要的原理就是Java的动态代理机制。因为,本篇主要是对java的动态代理做一个分析。

 

什么是代理?

说到代理我们就联想到了生活中的代理商。我们生活中有时候买东西直接去的就是代理商处买东西(比如微商),在买东西的过程中,我们不知道背后的商家究竟是谁,我们面对的是代理商而不是直接的厂家。因此,我们相当于与厂家之间没有直接的联系。因此代理有以下的两个好处:

第一:可以隐藏背后的实现类(厂家)的具体实现形式;

第二:可以实现客户与实现类之间的解耦。在不修改实现类代码的情况下能够做一些额外的处理。

 

         Java中的代理机制分为静态代理和动态代理。

         静态代理:代理类在程序运行之前就已经存在,代理类中的Java代码是我们自己事先写好的。通常情况下,静态代理中的代理类和委托类会事先同一接口或者是派生自相同的父类。


代码实现静态代理:

1.创建一个接口:Car


2.接口的实现类


3. 代理类ProxyTexi


上面这幅图是代理类的代码实现:

1.      代理类中也是对接口Car的实现,实现了Car接口中的方法sell()和add();

2.      Car中新增了其他类的方法Document,也就是说代理带是对实现类和其他类的结合。

3.      在代理类中,我们增加了一个判断语句(可以理解为,当卖车时,只要满足车主是admin时才能进行卖车)。因此,这些判断(或者其他方法)只需要在代理类中进行实现,而在实现类texi中并不需要做任何修改。所以,这就满足了第二个优点:可以实现客户与实现类之间的解耦。在不修改实现类代码的情况下能够做一些额外的处理


动态代理:在程序运行时创建的代理方式。也就是说,在这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成。相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。下面通过代码进行说明一下:



1. Salary接口

public interface Salary {public void showSalary();}

2. 接口实现类:

public class showSalaryImpl implements Salary {public void showSalary() {System.out.println("Show salary...");}}

3. 中介类(代理类定义)


/** * 创建动态代理对象的类 * @author Administrator * */public class SalaryManager implements InvocationHandler {private Object object;//目标对象private Security security;//安全类private Longer longer;//打印日志的类private Privilege privilege;//用户权限的类public SalaryManager(Object object, Security security, Longer longer, Privilege privilege) {super();this.object = object;this.security = security;this.longer = longer;this.privilege = privilege;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//安全认证this.security.security();//启动日志this.longer.longer();//权限认证if(this.privilege.getPassword().equals("admin")){System.out.println("登录成功!");}else {System.out.println("登录失败...");}method.invoke(object, args);return null;}}


注:动态代理只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类。


4. 代理类实现功能
public class SalaryTest {@Testpublic void Test(){Longer longer = new Longer();Security security = new Security();Privilege privilege = new Privilege();privilege.setPassword("admin1");//代理对象Salary salary = new showSalaryImpl();//创建中介类实例:将需要的代理对象传进去,最后是需要改对象调用其方法的SalaryManager salaryManager = new SalaryManager(salary, security, longer, privilege);/** * 通过Proxy的newProxyInstance方法来创建我们的代理对象。其中的三个参数: * 第一个参数:salary.getClass().getClassLoader(),这里使用handler这个类的ClassLoader对象 * 来加载我们的代理对象 * 第二个参数:salary.getClass().getInterfaces(),这里我们为代理对象提供的接口是真是对象所实行的接口, * 表示我们要代理的对象是该真实对象,这样我们就可以调用这组接口中的方法了 * 第三个参数:salaryManager。这是我们将这个代理对象关联到中介类上 */Salary showSalaryImpl = (Salary)Proxy.newProxyInstance(salary.getClass().getClassLoader(), salary.getClass().getInterfaces(), salaryManager);//调用代理类对象方法showSalaryImpl.showSalary();}}

我们可以看到,我们可以通过中介类SalaryManager代理不同类型的对象,如果我们把对外的接口都通过动态代理来实现,那么所有的函数调用最终会通过invoke函数的转发。因此我们就可以在这里做一些自己想做的操作。比如日志系统、事务、拦截器、权限控制等。这也就是AOP(面向切面编程的基本原理)

 

插曲AOPAspectOrientedProgramming):将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码---解耦。


动态代理优点:

 

动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强

 

总结:

 

其实所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。

 

代理对象就是把被代理对象包装一层,在其内部做一些额外的工作,比如用户需要上facebook,而普通网络无法直接访问,网络代理帮助用户先翻墙,然后再访问facebook。这就是代理的作用了。

 

纵观静态代理与动态代理,它们都能实现相同的功能,而我们看从静态代理到动态代理的这个过程,我们会发现其实动态代理只是对类做了进一步抽象和封装,使其复用性和易用性得到进一步提升而这不仅仅符合了面向对象的设计理念,其中还有AOP的身影,这也提供给我们对类抽象的一种参考。关于动态代理与AOP的关系,个人觉得AOP是一种思想,而动态代理是一种AOP思想的实现!



原创粉丝点击