欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java 静态代理和动态代理

程序员文章站 2022-06-17 19:52:30
...

代理模式

代理模式是一种设计模式,通过代理对象操作访问对象,这样做的好处是:在不修改原目标对象的基础上,提供额外的功能操作,扩展目标对象的目的,换言之就是设置一个中间件来控制员对象。

UML

java 静态代理和动态代理

举个例子:

生活中我们去菜市场购买蔬菜,蔬菜会在原产地拉上大城市,大城市中会有很多批发市场,小区的很多蔬菜商人会在批发市场批发蔬菜,然后在自己的蔬菜超市出售蔬菜,这里的批发市场和蔬菜商店就是代理。

代理分为静态代理和动态代理两种方式,两者的区别为:

  • 静态代理在编译时就已经实现,编译完成后的静态代理实际上就是个class文件
  • 动态代理是在运行期间产生的,即编译后没有实际的class文件,而是在运行时动态生成的类字节码,并加载到JVM中

动态代理:动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理

静态代理缺点:

①冗余:由于代理对象要和目标对象一致的接口,会产生过的类

②不宜维护:一旦接口增加方法,目标对象目标对象和代理对象都要修改

静态代理

原始接口:

package com.demo.dynamicdemo11.poxyUtils;

public interface Subject {

    public void sayGoodBye();
    public void sayHello();

}

真实实现类

package com.demo.dynamicdemo11.poxyUtils;

import android.util.Log;

public class RealSubject implements Subject {

    @Override
    public void sayGoodBye() {
        Log.e("---realSubject-->>", "good_bye");
    }

    @Override
    public void sayHello() {
        Log.e("---realSubject-->>", "good_hello");
    }
}
    

代理实现类:

package com.demo.dynamicdemo11.poxyUtils;

import android.util.Log;

public class PoxySubject implements Subject {

    private Subject subject;

    public PoxySubject(Subject subjects) {
        this.subject = subjects;
    }

    @Override
    public void sayGoodBye() {
        subject.sayGoodBye();
        Log.e("---PoxySubject-->>", "good_bye");
    }

    @Override
    public void sayHello() {
        subject.sayHello();
        Log.e("---PoxySubject-->>", "good_hello");
    }

}

调用出:

 RealSubject realSubject = new RealSubject();
 PoxySubject poxySubject = new PoxySubject(realSubject);
 poxySubject.sayGoodBye();
 poxySubject.sayHello();

打印结果:

02-21 03:06:30.680 1728-1728/? E/---realSubject-->>: good_bye
02-21 03:06:30.680 1728-1728/? E/---PoxySubject-->>: good_bye
02-21 03:06:30.680 1728-1728/? E/---realSubject-->>: good_hello
02-21 03:06:30.680 1728-1728/? E/---PoxySubject-->>: good_hello

代理类中有父类引用,可以把真实的代理放入代理类中进行调用

动态代理

动态搭理利用java api,动态的在内存中构建代理对象,从而实现对目标对象的代理功能,动态代理又被称为jdk代理或接口代理。

动态代理紧密关联的api:

// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器  
static InvocationHandler getInvocationHandler(Object proxy)   
  
// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象  
static Class getProxyClass(ClassLoader loader, Class[] interfaces)   
  
// 方法 3:该方法用于判断指定类对象是否是一个动态代理类  
static boolean isProxyClass(Class cl)   
  
// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例  
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)  

Poxy类的newProxyInstance方法

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
  • load:一个classLoader对象,定义了由哪个classLoader对象来对生成的代理进行加载
  • interface:一个interface数组,表示的是我将要给我需要的代理的对象提供一组接口,如果提供了接口给它,那么这个代理对象就宣布实现了该接口(多态),这样就能调用这组接口中的方法了
  • h:当动态代理对象调用方法的时候,会关联到哪个InvocationHandler上

InvocationHandler

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
  • proxy:指代生成的代理对象
  • method:指我们要调用真实方法的某个method
  • args:调用真实对象某个方法的参数

每一个代理实类例的invocation handler都要实现InvocationHandler这个接口。并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke 方法来进行调用

我们继续用上面静态代理的例子

定义一个接口

package com.demo.dynamicdemo11.poxyUtils;

public interface Subject {

    public void sayGoodBye();
    public void sayHello();

}

定义真实对象(被代理类)

package com.demo.dynamicdemo11.poxyUtils;

import android.util.Log;

public class RealSubject implements Subject {

    @Override
    public void sayGoodBye() {
        Log.e("---realSubject-->>", "good_bye");
    }

    @Override
    public void sayHello() {
        Log.e("---realSubject-->>", "good_hello");
    }
}

定义一个InvocationHandler, 相当于一个代理处理器
SubjectInvocationHandler并不是真正的代理类,而是用于定义代理类需要扩展、增强那些方法功能的类。在invoke函数中,对代理对象的所有方法的调用都被转发至该函数处理。在这里可以灵活的自定义各种你能想到的逻辑。

package com.demo.dynamicdemo11.poxyUtils;

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

public class SubjectInvocationHandler implements InvocationHandler {

    //定义真实的对象
    private Object subject;

    //赋值真实的代理对象
    public SubjectInvocationHandler(Object subjects) {
        this.subject = subjects;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        method.invoke(subject, args);
        return null;
    }
}

调用

//被代理类
        Subject realSubject = new RealSubject();
        //我们要代理哪个类,就把哪个类作为参数传递进去,最后是通过该代理对象来调其他方法的
        SubjectInvocationHandler handler = new SubjectInvocationHandler(realSubject);
        //生成代理对象
        Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),realSubject.getClass().getInterfaces(),    handler);
        subject.sayHello();
        subject.sayGoodBye();

通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象

扩展功能:

@Override
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
    if (method.getName().equals("sayGoodBye")) {//在调用sayGoodBye方法的时候 对返回值进行处理
        int result = (int) method.invoke(subject, args);
        return result + 10;
    } else {//其他方法一律不处理
        return method.invoke(subject, args);
    }
}