代理模式:为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用。
假设一个场景:明星需要出演活动(比如唱歌),那么他需要签合同,收款等工作。但是对于明星来讲,这都是琐碎的事情,而且亲自来做,比较掉价,所以明星们一般都会设置一个代理(也就是经纪人),经纪人负责签合同,收款等这些琐碎的工作,明星本人只需要专注于唱歌这一件事情就可以了。
使用代理模式的好处:
- 被代理类可以更加专注于主要功能的实现
- 代理类可以在被代理类已经存在的功能上添加新的功能
我们用代码来模拟这个过程。
静态代理:
写一个Star接口
1 package top.bigking.proxy.staticProxy; 2 3 /** 4 * @Author ABKing 5 * @Date 2020/2/14 下午9:33 6 **/ 7 public interface Star { 8 /** 9 * 签合同 10 */ 11 public void signContract(); 12 /** 13 * 唱歌 14 */ 15 public void sing(); 16 /** 17 * 收尾款 18 */ 19 public void collectMoney(); 20 }
让明星RealStar类实现这个接口:
1 package top.bigking.proxy.staticProxy; 2 3 /** 4 * @Author ABKing 5 * @Date 2020/2/14 下午10:01 6 **/ 7 public class RealStar implements Star { 8 @Override 9 public void signContract() { 10 System.out.println("ReadStar.signContract"); 11 } 12 13 @Override 14 public void sing() { 15 System.out.println("蔡徐坤本人唱歌"); 16 } 17 18 @Override 19 public void collectMoney() { 20 System.out.println("ReadStar.collectMoney"); 21 } 22 }
让代理ProxyStar类实现这个接口:
1 package top.bigking.proxy.staticProxy; 2 3 /** 4 * @Author ABKing 5 * @Date 2020/2/14 下午10:02 6 **/ 7 public class ProxyStar implements Star { 8 private Star star; 9 10 public ProxyStar(Star star) { 11 this.star = star; 12 } 13 14 @Override 15 public void signContract() { 16 System.out.println("ProxyStar.signContract"); 17 } 18 19 @Override 20 public void sing() { 21 star.sing(); 22 } 23 24 @Override 25 public void collectMoney() { 26 System.out.println("ProxyStar.collectMoney"); 27 } 28 }
进行JUnit测试:
1 package top.bigking.proxy.staticProxy; 2 3 import org.junit.Test; 4 5 /** 6 * @Author ABKing 7 * @Date 2020/2/14 下午10:04 8 **/ 9 public class TestStaticProxy { 10 @Test 11 public void testStaticProxy(){ 12 Star realStar = new RealStar(); 13 Star proxyStar = new ProxyStar(realStar); 14 proxyStar.signContract(); 15 proxyStar.sing(); 16 proxyStar.collectMoney(); 17 } 18 }
结果如下:
ProxyStar.signContract 蔡徐坤本人唱歌 ProxyStar.collectMoney
动态代理:
JDK动态代理:
Star接口和RealStar类不变
写一个StarHandler类:
1 package top.bigking.proxy.dynamicProxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 /** 7 * @Author ABKing 8 * @Date 2020/2/14 下午11:16 9 **/ 10 public class StarHandler implements InvocationHandler { 11 private Star star; 12 13 public StarHandler(Star star) { 14 this.star = star; 15 } 16 17 @Override 18 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 19 if(method.getName().equals("sing")) { 20 method.invoke(star, args); 21 } 22 System.out.println(method.getName()); 23 return null; 24 } 25 }
执行JUnit单元测试:
1 package top.bigking.proxy.dynamicProxy; 2 3 import org.junit.Test; 4 5 import java.lang.reflect.Proxy; 6 7 /** 8 * @Author ABKing 9 * @Date 2020/2/14 下午11:22 10 **/ 11 public class TestDynamicProxy { 12 @Test 13 public void testDynamicProxy(){ 14 Star realStar = new RealStar(); 15 StarHandler starHandler = new StarHandler(realStar); 16 Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), 17 new Class[]{Star.class}, starHandler); 18 proxy.signContract(); 19 proxy.sing(); 20 proxy.collectMoney(); 21 } 22 }
运行结果如下:
signContract
蔡徐坤本人唱歌sing
collectMoney
开发框架中应用场景:
- Struts2中拦截器的实现
- 数据库连接池关闭处理
- Hibernate中延时加载的实现
- mybatis中实现拦截器插件
- AspectJ的实现
- spring中AOP的实现:日志拦截,声明式事务处理
- web service
- RMI远程方法调用