JAVA关于静态代理和JDK动态代理

关于静态代理和JDK动态代理

  • 什么是代理
  • 静态代理
  • JDK动态代理

什么是代理

代理通俗来说就是代替某人去做一件事情,可以举个例子,假设有个老师今天生病了不能来上课,那么是不是可以请一个代理老师来帮上课,实际意义上来说这两个老师完成的东西是一样的,都是给学生传道受业解惑,但是,代理老师是不是能在原来上课的基础上拓展更多“功能”,比如说代理老师去上课之前,先到隔壁班看了一眼中意的女老师有没有来,上完课之后又去吃了自己最爱吃的螺蛳粉~看到这儿有没有感觉到跟一个东西很像,所以SpringAOP面向切面变成的原理就是这样,当然实际实现方面会更加复杂。

代理分为三个角色

  1. 接口
  2. 委托类
  3. 代理类

静态代理

我们先说一下静态代理,就用我们前面举的例子,直接上代码。

接口:

package com.staticproxy;

//我和代理老师都是老师,共同实现了老师接口
public interface Teacher {
   void teach();
}

委托类:

package com.staticproxy;
//这个就是生病的老师
public class MathTeacher implements Teacher {
   @Override
   public void teach() {
       System.out.println("传道受业解惑40分钟");
   }
}

代理类:

package com.staticproxy;
//这个是代理老师
public class ProxyTeacher implements Teacher {
   //通过构造器注入被代理对象(注入一个生病老师的对象)
   private Teacher targetTeacher;
   public ProxyTeacher(Teacher teacher){
       this.targetTeacher=teacher;
   }

   //代理老师实现了接口也有teach方法
   @Override
   public void teach() {
       System.out.println("上课之前先去隔壁班看美女老师");
       //调用生病老师的teach方法
       targetTeacher.teach();
       System.out.println("上完课了,去吃个螺蛳粉压压惊!");
   }
}

Client的main方法:

package com.staticproxy;

public class Client {
   public static void main(String[] args) {
       Teacher teacher=new MathTeacher();
       Teacher proxyteacher=new ProxyTeacher(teacher);
       proxyteacher.teach();
   }
}

结果:
JAVA关于静态代理和JDK动态代理_第1张图片
静态代理跟着走一遍应该很快就能理清,非常简单。
下面我们继续动态代理,动态代理需要用到反射机制。

JDK动态代理

接口:

package com.jdkproxy;

public interface Teacher {
   void teach();
}

没什么好说的跟前面一样的接口

委托类:

package com.jdkproxy;

public class MathTeacher implements Teacher {
   @Override
   public void teach() {
       System.out.println("传道受业解惑40分钟");
   }
}

重点来了

package com.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* 注意动态代理这里不需要再实现教师接口了
* 这样才能体现动态的概念,往往在实际应用之中
* 我们是不会提前知道我们需要代理什么对象的
*/
public class ProxyTeacher {

   private Object targetteacher;
   public ProxyTeacher(Teacher teacher){
       this.targetteacher=teacher;
   }

/**
* 这里调用了Proxy的newProxyInstance方法获得代理对象
* 参数1表示被代理对象的类加载器
* 参数2是被代理对象实现的接口,可以是数组(表示实现多个接口)
* 参数3是用匿名内部类实例化一个实现了InvocationHandler接口的对象
*/
   public Object getProxyInstance(){
       return Proxy.newProxyInstance(targetteacher.getClass().getClassLoader(), targetteacher.getClass().getInterfaces(),
               new InvocationHandler() {
                   /**
                   * @param proxy 调用这个方法的代理实例
    			   * @param method 要调用的方法
    			   * @param args 方法调用时所需要的参数
    			   * @return 方法调用的结果
   				   */
   				   @Override
                   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                       System.out.println("上课之前先去隔壁班看美女老师");
                       method.invoke(targetteacher,args);
                       System.out.println("上完课了,去吃个螺蛳粉压压惊");
                       return null;
                   }
               });
   }
}

Client:

package com.jdkproxy;

public class Client {
   public static void main(String[] args) {
       Teacher teacher=new MathTeacher();
       Teacher proxyTeacher=(Teacher)new ProxyTeacher(teacher).getProxyInstance();
       proxyTeacher.teach();
   }
}

结果:
JAVA关于静态代理和JDK动态代理_第2张图片
总结:
当然SpringAop用的动态代理更为复杂,还有cglib动态代理等其他技术这里不做延伸,我们只需要知道,动态代理可以在完成原来对象实现的功能的基础之上,继续延伸和拓展,这也是SpringAop面向切面编程的一个重要思想,广泛应用在比如日志,异常处理,监控,事务管理等功能上。这就是面向切面的大致原理,可以这么想,上课本来就是老师必做的流程,在该流程上横向切入了看美女和吃东西两个功能,而丝毫不影响功能的实现。

你可能感兴趣的:(java,aop,proxy,反射,jdk)