动态代理
在静态代理中,如果接口需要代理,我们需要提前写好代理类,在静态代理中建立好代理类与被代理类的关系,但是如果有多个接口需要同样被代理,就需要为每一个接口写一个代理类,这样会造成代码的大量重复,这个时候我们就可以使用动态代理技术,我们通过动态代理在运行期间动态的生成业务类的代理类。
总的来说,动态代理之所以能节省代码量,在需要代理的时候进行动态代理,主要是因为动态代理的字节码是在程序运行的时候由反射机制进行动态的额生成的,动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java机制可以生成任意类型的动态代理类。
动态代理的流程与上面静态代理的分析流程是一样的,首先需要建立代理对象与真实对象与代理对象之间的联系。然后实现代理逻辑。
在JDK动态代理中,要想实现代理,我们定义的代理类必须实现 InvocationHandler 接口,接口中定义了一个invoke方法,并提供接口数组用下下挂对象。
1 | InvocationHandler接口: |
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
使用JDK的动态代理
使用动态代理依旧需要借助一个接口才能实现代理对象,我们定义接口和实现类。依旧使用上一节中定义过的
UserInfo接口及实现类
1 | public interface UserInfo { |
1 |
|
定义完接口及实现类,下面我们就需要定义一个代理类。
在下面代码中,我们通过一个变量private Object target; 表示要被代理的真实对象,我们通过bind方法来实现本例对象与真实对象之间联系。在这里使用了一个类Proxy。Proxy类的作用就是用来动态创建一个代理类对象的类,它提供了许多的方法,但是我们用的最多的就是newProxyInstance这个方法。下面看一下newProxyInstance这个方法的参数。
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
- loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
- interfaces, :一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就可以称为实现了该接口,这样我就能调用这组接口中的方法了
- h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象
这样建立好联系之后我们就可以使用了。
1 | public class UserDomticProxy implements InvocationHandler { |
调用客户端,传入真正的委托类。
1 |
|
运行结果:
上面就是JDK代理的实现,我们可以看出,动态代理帮我们创建出一个代理,使代理与我们的委托类之间的关联关系进行了解耦,也就是我们需要进行代理的时候再进行代理,而且一次实现代理就可以为多种接口实现代理,这样可以大大的简化我们的代码,需要时再代理就是动态代理的思想。动态代理解决了静态代理中一对一的问题,使用反射可以动态的决定由任意类型的代理去代理实际的实现接口,提高了系统的课扩展性。动态代理和AOP面向切面编程的思想是一致的。
但是动态代理也有缺点,就是每一个被代理的对象都需要时实现接口,也就是说如果如果一个类需要代理它必须是接口的实现,但是一个类没有接口如何使用代理呢,这个时候就引入了CGlib代理技术。