代理模式

静态代理


什么是代理?为什么有代理

生活中常见的代理:
1.NIKE公司在中国卖产品,需要个中国区的代理;
2.我们去打官司,需要一个律师来作为我们的代理;
3.公司投标,老总需要一个手下作为代理;
 
程序中的代理有三种情况:
 1.代理对象再调用真实对象前后进行预处理;
 2.通过代理对象处理真实对象抛出的异常;
 3.代理对象全权处理业务不通知真实对象;
  1. publicclassProxyStudentimplementsPerson{
  2. privateStudent student;
  3. @Override
  4. publicvoid study(){
  5. //在此处可以通过代理对象执行一些预处理方法;
  6. try{
  7. student.study();
  8. }catch(Exception e){
  9. // 在此可以对抛出的异常进行捕捉并处理
  10. e.printStackTrace();
  11. }
  12. //在此处可以通过代理对象执行一些善后工作;
  13. }
  14. }
动态代理

说到动态代理,我们先聊聊我们的类是怎么创建对象的;
 由上图我们知道,动态代理就是动态的生成class字节码文件,有了动态生成的字节码文件,就能够实现动态代理.那么问题来了?我们怎么动态生成class文件呢?
常用的有4种方法:
1.jdk的Proxy(动态代理)
2.Cglib
3.javassist
4.asm(第三方字节码生成工具)
这里我们主要来说第一种和第二种:
首先我们来讲解怎么使用jdk的Proxy(动态代理)生成代理对象;
代码:
  1. publicclassTest{
  2. /**
  3. * 通过jdk的Proxy动态代理生成对象
  4. * @param args
  5. */
  6. publicstaticvoid main(String[] args){
  7. // TODO Auto-generated method stub
  8. Class<?>[] interfaces =newClass<?>[]{Singer.class,Student.class};
  9. //MyInvocationHandler handler = new MyInvocationHandler();
  10. Object obj =Proxy.newProxyInstance(Test.class.getClassLoader(), interfaces ,newMyInvocationHandler());
  11. Singer singer =(Singer)obj;
  12. singer.sing("小苹果");
  13. int live = singer.lives();
  14. System.out.println("live="+live);
  15. Student student =(Student) obj;
  16. student.study();
  17. student.doHomework();
  18. }
  19. }
  20. classMyInvocationHandlerimplementsInvocationHandler{
  21. @Override
  22. publicObject invoke(Object proxy,Method method,Object[] args)
  23. throwsThrowable{
  24. // 将字符串转化为枚举类型
  25. MethodName methodName =MethodName.valueOf(method.getName().toUpperCase());
  26. switch(methodName){
  27. case STUDY:
  28. System.out.println("我是苦逼的学生,天天学习,好好向上!");
  29. returnnull;
  30. case DOHOMEWORK:
  31. System.out.println("我是苦逼的学生,我一回家就有写不完的作业!");
  32. returnnull;
  33. case SING:
  34. System.out.println("我是苦逼的学生,我不会唱"+args[0]+",我只会唱让我们荡起双桨!");
  35. returnnull;
  36. case LIVES:
  37. System.out.println("作为一个苦逼的学生党,毫无幸福感可言!");
  38. return0;
  39. }
  40. returnnull;
  41. }
  42. }
  43. enumMethodName{
  44. STUDY,DOHOMEWORK,SING,LIVES;
  45. }
有了代理对象我们怎么把请求通过代理对象处理或者向真实对象转发呢?
请看下面的代码.
  1. publicclassTest2{
  2. publicstaticvoid main(String[] args){
  3. Class<?>[] interfaces =newClass<?>[]{Singer.class,Student.class};
  4. Object obj =Proxy.newProxyInstance(Student.class.getClassLoader(), interfaces ,newJayInvocationHandler(newJay()));
  5. Singer singer =(Singer)obj;
  6. singer.sing("七里香");
  7. int live = singer.lives();
  8. System.out.println("live="+live);
  9. Student student =(Student) obj;
  10. student.study();
  11. student.doHomework();
  12. }
  13. }
  14. classJayInvocationHandlerimplementsInvocationHandler{
  15. privateJay jay;
  16. publicJayInvocationHandler(Jay jay){
  17. super();
  18. this.jay = jay;
  19. }
  20. @Override
  21. publicObject invoke(Object proxy,Method method,Object[] args)
  22. throwsThrowable{
  23. //此处可以对真实对象进行预处理
  24. //此处是通过反射调用,相当于jay.method(args);
  25. Object obj =null;
  26. try{
  27. obj = method.invoke(jay, args);
  28. }catch(Exception e){
  29. // 在此可以对抛出的异常进行捕捉并处理
  30. }
  31. //在此处可以通过代理对象执行一些善后工作;
  32. return obj;
  33. }
  34. }
这是通过JDK自带的proxy实现的动态代理,虽然jdk可以实现动态代理,但是这是有局限性的;我们来看
  1. Class<?>[] interfaces =newClass<?>[]{Singer.class,Student.class};
这一句话,这里要求我们创建一个接口数组,但是如果我们的被代理对象没有实现接口怎么办呢?
这样jdk的代理就不能使用了,这时候我们就用到了一个新的知识点,也就是我们要讲的Cglib动态代理,下面就是CGlib动态代理的实现.
  1. publicclassTest{
  2. publicstaticvoid main(String[] args){
  3. finalJay jay =newJay();
  4. Enhancer enhancer =newEnhancer();
  5. enhancer.setSuperclass(Jay.class);
  6. //匿名内部类;
  7. enhancer.setCallback(newMethodInterceptor(){
  8. @Override
  9. publicObject intercept(Object proxy,Method method,Object[] args,
  10. MethodProxy methodProxy)throwsThrowable{
  11. System.out.println("------------方法执行前----------");
  12. //Object object = methodProxy.invokeSuper(proxy, args);
  13. Object object = method.invoke(jay, args);
  14. System.out.println("------------方法执行后----------");
  15. return object;
  16. }});
  17. Jay jayproxy =(Jay)enhancer.create();
  18. jayproxy.study();
  19. jayproxy.doHomework();
  20. jayproxy.lives();
  21. jayproxy.sing("七里香");
  22. }
  23. }
Cglib的动态代理和jdk的动态代理的异同:
相同点:都实现了动态代理的功能.
不同点:
 
 
 
 





posted @ 2017-03-25 16:24  Mr.xiaobai丶  阅读(322)  评论(0编辑  收藏  举报