AOP 代理模式(动态代理)

  动态代理

           不需要手动创建动态代理类,而是通过jdk中提供的API然后动态的为某个目标类创建所对应动态代理类。

             jdk提供的API带代码运行的过程中动态的创建每一个目标类所对应的动态代理类。

img

 

 

    JDK本身就支持动态代理,这是反射技术的一部分。

   下面创建一个代理类(生产代理对象的工厂类):

package com.atguigu.spring.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
* 是动态生成目标类所对应的代理类(相当于工具类),所以叫工厂,就是专门生产代理类的
*/

public class ProxyFactory {
   /**
    * 目标对象:因为现在是针对任何的目标类来创建代理类的
    *         所以类型写Object
    */
   private Object target;

   public ProxyFactory(Object target) {
       this.target = target;
  }

    //创建一个方法
   public Object getProxy(){
       /**
        * 使用动态代理的方法:jdk动态代理,使用的API就是Proxy
        * 来创建一个代理实例,通过这个方法创建动态代理类动态代理对象
        * 里面有三个参数:1.类加载器 2.接口 3.对象
        *   1. ClassLoader loader:指定加载动态生成的代理类的类加载器
        *         类想要执行,必须要被加载,类的加载需经过类的加载器加载
        *       类加载器:
        *         ①根类加载器:底层是c来实现的,获取的时候,只要加载一些核心类库
        *         ②扩展类加载器:加载的是扩展类库
        *         ③应用类加载器:自己写的一些类,和引入的第三方jar包里面的类,都是由应用类加载器加载
        *         ④自定义加载器:
        *     2. Class<?>[] interfaces:获取目标对象实现的所有的接口的class对象的数组
        *       都是通过反射获取
        *     3.InvocationHandler h:设置代理类中的抽象方法如何重写
        */

       //1.获取当前这个类的类加载器,this直接表示当前类的对象
       ClassLoader classLoader = this.getClass().getClassLoader();
       
       //2.获取目标对象实现的所有的接口
       //为什么获取实现的接口class对象的数组:因为从静态代理写到动态代理,静态代理说了保证目标对象跟代理对象实现的功能是一致的
       Class<?>[] interfaces = target.getClass().getInterfaces();
       
       /**           3.代理类中的抽象方法如何重写
            *         表示代理类中的方法该如何执行(执行:调用目标对象的实现功能的过程)
            */
       InvocationHandler h=new InvocationHandler() {
           @Override
           /**
              * praxy:表示代理对象,method表示要执行的方法,args:表示要执行的方法到参数列表
              */
           public Object invoke(Object proxy, Method method, Object[] args) {
               Object result = null;
               try {
                    // 功能实现之前          
     System.out.println("日志,方法:"+method.getName()+",参数:"+ Arrays.toString(args));
                   
                 // invoke有两个参数:①当前要使用的对象②参数列表 所以调的是目标对象
                    // 所以这代码表示的就是目标对象实现的功能的过程
                 result = method.invoke(target, args);
                   
                    //功能实现之后
                   System.out.println("日志,方法:"+method.getName()+",结果:"+ result);
                   
              } catch (Exception e) {
                   e.printStackTrace();
 System.out.println("目标对象执行过程出现了异常"+"日志,方法:"+method.getName()+",异常:"+e);
              } finally {
                   System.out.println("方法执行完毕");
              }
               return result;
          }
      };
       return Proxy.newProxyInstance(classLoader,interfaces,h);
  }
   public Object getTarget() { return target;}
   public void setTarget(Object target) {this.target = target;}
}


 /**
    * 动态代理有两种:
    * 1.jdk动态代理,要求必须有接口,最终生成的代理类和目标类实现相同的接口,
    *   在com.sum.proxy包下,类名为$proxy
    * 2.cglib动态代理:最终生成的代理类会继承目标类,并且和目标类在相同的包下
    */

   @Test
   public void testProxy(){
       /**
        * 然后把目标对象传进来,
        * 不知道目标对象怎么来创建所对应动态代理类,所以得在里面new CalculatorImpl
        */
       ProxyFactory proxyFactory=new ProxyFactory(new CalculatorImpl());
       //因为不知道当前动态生成代理类的类型,知道他实现的接口就可以,通过接口获取
       Calculator proxy = (Calculator) proxyFactory.getProxy();
       proxy.add(1,2);
       /**
        * 日志,方法:add,参数:[1, 2]
        * 方法内部,result:3
        * 日志,方法:add,结果:3
        * 方法执行完毕
        */
  }
 
posted @ 2022-11-18 22:33  zjw_rp  阅读(127)  评论(0)    收藏  举报