Java学习笔记整理: 关于设计模式:代理模式 2024/7/10;-动态代理

时间:2024-07-13 10:49:03

自理解:通过JDK/Cglib拦截被代理类对象,并对其进行修改使代理类拥有所有被代理类实现的接口内方法;

JDK原理:被代理类需要接口,使用JDK自带方法Proxy获取代理对象 通过反射获取其方法;

Cglib原理:被代理类无须接口,引入Cglib通过指定方法获取代理对象.

动态代理是在程序运行时通过反射机制动态创建的。

JDK动态代理:

通过JDK自带的方法Proxy获取代理对象

涉及反射

调用Proxy类的静态方法newProxyInstance即可,该方法会返回代理类对象

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h ) 接收的三个参数依次为:

  • ClassLoader loader:指定当前目标对象使用类加载器,写法固定

  • Class<?>[] interfaces:目标对象实现的接口的类型,写法固定

  • InvocationHandler h:提供的执行被代理角色方法的方法。

  • 缺点:
  • 可以看出静态代理和JDK代理有一个共同的缺点,就是目标对象必须实现一个或多个接口,如果没有,则可以使用Cglib代理。

 public interface ISinger {
     void sing();
     void sings();
 }
 
 /**
  *  目标对象实现了某一接口
  */
 public class Singer implements ISinger{
     public void sing(){
         System.out.println("唱一首歌");
     }  
     public void sings(){
         System.out.println("唱二首歌");
     }     
 }
​
public class Test{
     public static void main(String[] args) {
   //new被代理类对象
    Singer target = new Singer();
   //通过lambda创建代理类对象proxy
      ISinger proxy  = (ISinger) Proxy.newProxyInstance( target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {
         @Override
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              System.out.println("向观众问好");
              //执行目标对象方法
              Object returnValue = method.invoke(target, args);
              System.out.println("谢谢大家");
              return returnValue;
              }
        });
   //输出方法,可直接调用被代理类对象中的方法并且经过代理类拦截修改后输出
        proxy.sing();
        proxy.sings();
     }
 }
//若不适应lambda则可以创建代理类--------------------------------------
//代理类
public class Behavior {
    //代理对象接口
    private SellHours sellHours;
    //带参构造器
    Behavior(SellHours sellHours){
        this.sellHours = sellHours;
    }
    //JDK内proxy方法:
    public Object getSellHours(){
        //指定当前目标对象使用类加载器,写法固定
        ClassLoader classLoader = sellHours.getClass().getClassLoader();
        //目标对象实现的接口的类型,写法固定
        Class<?>[] interfaces = sellHours.getClass().getInterfaces();
        //提供的执行被代理角色方法的方法
        InvocationHandler invocationHandler = new InvocationHandler(){
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //调用执行部分:
                System.out.println("进入动态代理:::");
                //通过反射获取对象方法
                Object invoke = method.invoke(sellHours);
                //返回值
                return invoke;
            }
        };
        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    };
}
//测试
public class Test {
    public static void main(String[] args) {
        //创建代理对象并赋值被代理类对象
        Behavior behavior = new Behavior(new Landlord());
        //使用代理对象内方法获取被代理类方法
        SellHours sellHours = (SellHours) behavior.getSellHours();
        //执行
        sellHours.getName();
    }
}

Cglib代理:

前提条件:
  1. 需要引入cglib的jar文件,由于Spring的核心包中已经包括了Cglib功能,所以也可以直接引入spring-core-3.2.5.jar

  2. 目标类不能为final

  3. 目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法

/**
 * 目标对象,没有实现任何接口
 */
public class Singer{
​
    public void sing() {
        System.out.println("唱一首歌");
    }
}
/**
 * Cglib子类代理工厂:这里的代码也非常固定,只有部分是需要自己写出---------
 * 创建代理类并实现Cglib中的MethodInterceptor接口
 */
public class ProxyFactory implements MethodInterceptor{
    // 维护目标对象
    private Object target;
​
    public ProxyFactory(Object target) {
        this.target = target;
    }
​
    // 给目标对象创建一个代理对象
    public Object getProxyInstance(){,
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置被代理对象的父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建代理对象
        return en.create();
    }
    //重写Cglib中的方法
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        //调用执行部分:--------------------
        System.out.println("向观众问好");
        //通过反射执行目标对象的方法
        Object returnValue = method.invoke(target, args);
        System.out.println("谢谢大家");
        //返值
        return returnValue;
    }
}
/**
 * 测试类
 */
public class Test{
    public static void main(String[] args){
        //目标对象
        Singer target = new Singer();
        //代理对象
        Singer proxy = (Singer)new ProxyFactory(target).getProxyInstance();
        //执行代理对象的方法
        proxy.sing();
    }
}