java中的代理
简介
在学习spring的时候学习到了代理相关的知识,所以记录一下。代理的作用是帮助业务更加简单专一,而一些公共的东西交给代理来完成。比如:我们写Service的时候,需要在里面编写增删改查四个方法,并且调用这四个方法的时候都需要给出日志,这个时候我们就可以使用代理来完成,让Service中只专注于增删改查,而代理关注于写然日志。java的代理有静态和动态两种,一般使用动态更好。
代理讲解
提出问题
假设我们有一个需求,需要编写一个UserService,里面要有增删改查四个函数,在调用UserService的时候我们需要完成日志的输入。
一般情况下我们是这样实现的,先编写一个UserService的接口:
1 | /** |
然后再实现这个接口,并且在实现里面写一下日志:
1 | /** |
但是这样似乎有一些不好,因为UserService应该专注于增删改查的业务,这种日志方法写在里面,就有一种不纯粹的感觉,所以这个时候我们引入了代理,使用代理来帮助我处理日志问题。
静态代理
更改UserServiceImpl中代码:
1 | /** |
创建对应的代理类UserServiceProxy:
1 | /** |
这样我们在实现UserService时,我们只需要关注业务的部分。但是我们发现这样的静态代理,有一个缺点,那就是类变多了增加了工作量,并且如果又有另外一个service有类似的需求,又需要创建另外一个service相关的接口,再实现另外一个代理类,比较麻烦,所以也就有了我们的动态代理类。
动态代理
这里讲的动态代理是基于jdk动态代理实习,相关的内容为InvocationHandler接口和Proxy类。
InvocationHandler,官方文档说明上介绍:“InvocationHandleris the interface implemented by the invocation handler of a proxy instance.Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the
invokemethod of its invocation handler.”(翻译:InvocationHandler是由代理实例的调用处理程序实现的接口。 每个代理实例都有一个关联的调用处理程序。在代理实例上调用方法时,该方法调用将被编码并分派到其调用处理程序的invoke方法。)InvocationHandler里面有一个方法:1
2Object invoke(Object proxy, Method method, Object[] args)
//Processes a method invocation on a proxy instance and returns the result.处理代理实例上的方法调用并返回结果理解一下就是我们将需要代理的对象、方法、参数传入invoke,然后再invoke里面调用代理实例的处理程序实现代理功能,其实跟上面的静态代理思想类似,比如在
UserServiceProxy中调用代理对象userService相对应的处理程序Proxy,官方文档说明上介绍:“Proxyprovides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.”(翻译:Proxy提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。)Proxy中提供了一个静态方法1
2static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
//Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler. 返回指定接口的代理类的实例,该实例将方法调用分派到指定的调用处理程序。
代码实现上,先创建一个ProxyInvocationHandler实现InvocationHandler:
1 | package com.zhouning.service; |
调用:
1 | public static void main(String[] args) { |
这样我们就实现了动态的代理,似乎来说动态代理比静态代理要复杂一些,那么为什么不用更加简单一些的静态代理呢?首先是我们可以看到动态代理处理上更加简洁,其次是动态代理可以处理一类的业务逻辑,加入说下次有另外一个service需求,我们基本上不需要重写一个代理类,直接使用现在这个动态代理类就行,减少了工作量。
总结
在学习spring_aop之前先学习了一下代理的内容,做个小结养成好习惯。