一、代理概念
动态代理技术使整个java技术中最重要的一个技术,他是学习java框架的家畜,不会动态代理技术,那么再学习Spring这些框架是学不明白的。
动态代理技术就是用来产生一个对象的代理对象的。在开发中为什么需要为一个对象产生代理对象呢?
例子: 明星都有一个经纪人,其实代理就是这个经纪人,别人想要找刘德华,必须要找其经纪人来商谈。代理不让你直接和明星对话。
代理对象应该就有和目标对象相同的方法。
首先我们应该明确代理对象的两个概念:
1、代理对象存在的价值主要用于拦截对真实业务对象的访问。
2、代理对象应该具有和目标对象(真实业务对象)相同的方法。
二、java中的代理
2.1 “java.lang.reflect.Proxy”类介绍
现在要生成某一个对象的代理对象,这个代理对象通常也要编写一个类来生成,
所以首先要编写用于生成代理对象的类。在java中如何用程序去程序生成一个对象的代理对象呢,java在jdk1.5之后提供了一个“java.lang.reflect.Proxy”,t通过“Proxy”类提供的一个 newProxyInstance 方法用来创建一个对象的代理对象,如下所示。
static Obeject newProxyInstance(ClassLoader loader,Class<?>[] interfaces,invocationHandler h)
newProxyInstance方法用来返回一个代理对象,这个方法总共有3个参数,ClassLoader loader 用来指明生成代理对象使用哪个类装载器,Class<?>[] 用来指明生成哪个对象的代理对象,通过接口指定,InvocationHandler h用来指明产生的这个代理对象要做什么事情。所以我们只需要调用newProxyInstance方法就可以得到某一个对象的代理对象了。
编写生成代理对象的类
在java中规定,要想产生一个对象的代理对象,那么这个对象必须要有一个接口,所以我们首先就是要设计这个对象的接口,在接口中定义这个对象所具有的方法(行为)
1 //首先定义对象的行为接口 2 3 public interface person{ 4 5 String sing(String name); 6 String dance(String name); 7 8 } 9 10 //定义目标业务对象类 11 12 public class LiuDeHua implements Person{ 13 14 public String sing(String name){ 15 System.out.println("刘德华唱"+name+"歌"); 16 return "歌唱完了,谢谢"; 17 } 18 public String sing(String name){ 19 System.out.println("刘德华跳"+name+"舞"); 20 return "舞跳完了,谢谢" 21 } 22 23 24 } 25 26 27 //创建生成代理对象的代理类 28 public class LiuDeHuaProxy{ 29 30 //设计一个类变量记住代理类要代理的目标对象 31 private Person ldh = new LiuDeHua(); 32 33 /* 34 设计一个方法生成代理对象 35 36 37 */ 38 39 public Person getProxy(){ 40 41 //使用Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)返回某个对象的代理对象 42 43 return (Person)Proxy.newProxyInstance(LiuDeHuaProxy.class.getClassLoader(),ldh.getClass().getInterfaces(),new InvocationHandler(){ 44 45 /* 46 InvocationHandler 接口只定义了一个 invoke方法,因此对于这样的接口,我们不用单独去定义一个类来实现该接口,而是直接使用一个匿名内部类来实现接口,new InvocationHandler(){}就是针对InvocationHandler接口的匿名实现类 47 在 invoke 方法编码指定返回的代理对象干的工作 48 proxy: 把代理对象自己传递进来 49 method:把代理对象当前调用的方法传递进来 50 args:把 方法参数传递进来 51 当代哦用代理对象的 person.sing("冰雨");或者 person.dance("舞蹈");方法的时候 52 实际上执行的都是invoke 方法里的代码,因此我们可以在invoke方法中使用 method.getName()就可以知道对象调用的是哪个方法 53 54 */ 55 @Override 56 public Object invoke(Object proxy,Method method, Object[] args ) throws Throwable{ 57 //如果调用的事代理对象的sing方法 58 if(method.getName().equals("sing")){ 59 //返回刘德华唱歌,就是代理对象会调用真是目标对象的sing方法去 60 处理用户请求 61 return method.invoke(ldh,args); 62 63 } 64 65 if(method.getName().equals("dance")){ 66 return method.invoke(ldh,args); 67 } 68 69 return null; 70 } 71 72 }); 73 74 75 } 76 77 }
//测试代码
public class ProxyTest{ public static void main(String[] args){ LiuDeHuaProxy proxy = new LiuDeHuaProxy(); //获得代理对象 Person p = proxy.getProxy(); //调用代理对象的sing方法 String retValue = p.sing("冰雨"); System.out.println(retValue); //String value = p.dance("江南style"); System.out.println(value); } }
动态代理应用:
可以编写字符过滤器
处理get请求 通过代理模式