代理模式是给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用,通俗的来讲代理模式就是我们生活中常见的中介。
Spring 的AOP面向切面就是使用动态代理模式来实现的;
打个比方说:我要买房,但是我对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人(中介)去帮我找,此处的代理就是这个意思。
代理类分为静态代理类和动态代理类:
首先看下静态代理类,代码如下:
接口:
publicinterfaceSource{voidmethod();}
委托类:
/**
* 委托类
*/publicclassRealSubjectimplementsSource{@Overridepublicvoidmethod(){ System.out.println("我要去买房了"); }}
1、静态代理类:
/**
* 静态代理类
*/publicclassProxySubjectimplementsSource{privateRealSubject realSubject;publicProxySubject(){this.realSubject =newRealSubject(); }@Overridepublicvoidmethod(){ before(); realSubject.method(); after(); }voidbefore(){ System.out.println("找房"); }voidafter(){ System.out.println("买房后装修"); }}
测试类:
publicclassText {publicstaticvoidmain(String[] args) {Sourcesource=newProxySubject();source.method(); }}
输出结果:
找房
我要去买房了
买房后装修
静态代理总结:
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们得为每一个服务都创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
2、动态代理类
动态代理类中我们不需要手动的创建代理类,我们只需要手动的编写一个动态处理器就可以了,真正的代理对象由JDK在运行时为我们动态的进行创建;
Dynamic代理模式相对于静态代理,大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度;
动态代理的实现依靠于InvocationHandler接口和Proxy类来实现的,每一个动态代理类中都必须要实现InvocationHandler接口,该接口中有唯一的invoke()方法;
该方法的作用就是得到一个动态的代理对象,其接收三个参数:
loader: 第一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载interfaces: 第二个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了h: 第三个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
我们来看一下代码:
首先定义一个接口,有两个方法
publicinterfaceSource{voiddescribe();voidbuyHourse();}
给该接口定义一个实现类,其实就是我们的委托对象
publicclassSourceImplimplementsSource{@Overridepublicvoiddescribe(){ System.out.println("中國風"); }@OverridepublicvoidbuyHourse(){ System.out.println("购房"); }}
定义动态代理类,注意一定要实现接口 InvocationHandler
publicclassDynamicProxyimplementsInvocationHandler{/**这个就是要代理的委托对象,使用Object类型,可以代理不同类型的对象,便于复用*/privateObjectsource;/**构造器,给要代理的对象赋值*/publicDynamicProxy(Objectsource) {this.source=source; }/*
我的理解:当我们通过动态代理对象调用委托对象的方法时会执行该方法
*/@OverridepublicObject invoke(Object proxy, Method method, Object[] args)throwsThrowable { before();/*当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用*/method.invoke(source,args); after();returnnull; }voidbefore(){ System.out.println("调用对象方法前执行的业务逻辑"); }voidafter(){ System.out.println("调用对象方法后执行的业务逻辑"); }}
测试类
publicclassTest {publicstaticvoidmain(String[] args) {//要代理的真实对象SourcerealSource =newSourceImpl();//创建handler实例,我们要代理哪个对象就把该对象传进去,最后通过该真是对象来调用其方法InvocationHandler handler =newDynamicProxy(realSource);/**
* 通过Proxy.newProxyInstance方法来创建代理对象,
* 第一个参数是目标对象的类加载器,获取方法为geiClassLoader()
* 第二个参数是一个Interface对象的数组,表示的是将要给需要代理的对象提供一组什么借口,
* 如果我提供了一组接口给它,那么这个代理对象就可以实现该接口(多态),
* 这样就能调用这组接口中的方法了
* 这里我们为代理对象提供的接口是真实对象所实行的接口,表示要代理的是该真是对象,
* 这样就可以调用这组接口中的方法了
* 第三个参数handler,指定的动态代理处理器,将该动态处理器传入真实的代理对象,即委托类对象
*/Sourcesource= (Source) Proxy.newProxyInstance(Source.class.getClassLoader(), realSource.getClass().getInterfaces(),handler);source.describe(); System.out.println("");source.buyHourse(); }}
输出结果
调用对象方法前执行的业务逻辑
中國風
调用对象方法后执行的业务逻辑
调用对象方法前执行的业务逻辑
购房
调用对象方法后执行的业务逻辑
如果你想学好JAVA这门技术,也想在IT行业拿高薪,可以参加我们的训练营课程,选择最适合自己的课程学习,技术大牛亲授,8个月后,进入名企拿高薪。我们的课程内容有:Java工程化、高性能及分布式、高性能、深入浅出。高架构。性能调优、Spring,MyBatis,Netty源码分析和大数据等多个知识点。如果你想拿高薪的,想学习的,想就业前景好的,想跟别人竞争能取得优势的,想进阿里面试但担心面试不过的,你都可以来,q群号为:180705916 进群免费领取学习资料。