在前面讲静态代理的时候说道它有一个缺陷:必须为每一个你想要进行代理的接口都设计一个静态的代理类。
那么,有没有一种更加灵活的方案呢?这就是动态代理,即在运行时为特定接口动态的生成一个代理类对象。
与动态代理密切相关的有两个东西:java.lang.reflect.InvocationHandler与java.lang.reflect.Proxy
实现一个动态代理只需要做两个步骤的工作:①设计一个Handler类让其实现InvocationHandler接口;②调用Proxy.newProxyInstance(...)方法来得到一个代理类对象;
第一步:
package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Date; public class RequestProxyHandler implements InvocationHandler { private Object proxied; public RequestProxyHandler(Object proxied) { this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //针对request方法作特殊处理:如果请求的当前时间在00:00:00~05:59:59之间,则不会执行实际的reques(...)方法 if(method.getName().equals("request")){ Date start = new Date(DateUtil.timeOfToday(0, 0, 0)); Date end = new Date(DateUtil.timeOfToday(5, 59, 59)); Date now = new Date(); if(now.after(start)&&now.before(end)){ System.out.println("系统维护时间,禁止请求..."); return null; //不会执行被代理对象的实际方法 } } //使用反射来调用被代理的实际方法 return method.invoke(proxied, args); } }
第二步:
1 package com.proxy; 2 3 import java.lang.reflect.Proxy; 4 5 public class Test { 6 7 public static void main(String[] args) { 8 //创建一个被代理对象 9 ISubject subProxied = new SubjectImpl(); 10 //将被代理对象传递到MyProxyHandler中,创建一个InvocationHandler对象来处理被代理对象 11 ISubject sub = (ISubject) Proxy.newProxyInstance(SubjectImpl.class.getClassLoader(), 12 new Class[]{ISubject.class}, new RequestProxyHandler(subProxied)); 13 14 sub.request(); 15 int res = (int)sub.add(10, 20); 16 System.out.println(res); 17 } 18 19 }
下面是完整的代码:
1 package com.proxy; 2 3 import java.util.Calendar; 4 import java.util.Date; 5 6 public class DateUtil { 7 8 public static long timeOfToday(int hour, int minute, int second){ 9 Calendar calendar = Calendar.getInstance(); 10 calendar.set(Calendar.HOUR_OF_DAY, hour); 11 calendar.set(Calendar.MINUTE, minute); 12 calendar.set(Calendar.SECOND, second); 13 calendar.set(Calendar.MILLISECOND, 0); 14 Date today = calendar.getTime(); 15 return today.getTime(); 16 } 17 }
package com.proxy; public interface ISubject { public void request(); public int add(int a, int b); }
1 package com.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.util.Date; 6 7 public class RequestProxyHandler implements InvocationHandler { 8 9 private Object proxied; 10 public RequestProxyHandler(Object proxied) { 11 this.proxied = proxied; 12 } 13 14 @Override 15 public Object invoke(Object proxy, Method method, Object[] args) 16 throws Throwable { 17 18 //针对request方法作特殊处理:如果请求的当前时间在00:00:00~05:59:59之间,则不会执行实际的reques(...)方法 19 if(method.getName().equals("request")){ 20 Date start = new Date(DateUtil.timeOfToday(0, 0, 0)); 21 Date end = new Date(DateUtil.timeOfToday(5, 59, 59)); 22 Date now = new Date(); 23 if(now.after(start)&&now.before(end)){ 24 System.out.println("系统维护时间,禁止请求..."); 25 return null; //不会执行被代理对象的实际方法 26 } 27 } 28 //使用反射来调用被代理的实际方法 29 return method.invoke(proxied, args); 30 } 31 }
1 package com.proxy; 2 3 public class SubjectImpl implements ISubject { 4 5 @Override 6 public void request() { 7 System.out.println("发送请求..."); 8 } 9 10 @Override 11 public int add(int a, int b) { 12 return a + b; 13 } 14 15 }
1 package com.proxy; 2 3 import java.lang.reflect.Proxy; 4 5 public class Test { 6 7 public static void main(String[] args) { 8 //创建一个被代理对象 9 ISubject subProxied = new SubjectImpl(); 10 //将被代理对象传递到MyProxyHandler中,创建一个InvocationHandler对象来处理被代理对象 11 ISubject sub = (ISubject) Proxy.newProxyInstance(SubjectImpl.class.getClassLoader(), 12 new Class[]{ISubject.class}, new RequestProxyHandler(subProxied)); 13 14 sub.request(); 15 int res = (int)sub.add(10, 20); 16 System.out.println(res); 17 } 18 19 }