Loading

Java 代理学习笔记

java代理

特征: 代理类和委托类有同样的接口, 代理类主要为委托类预处理消息, 过滤消息, 吧消息转发给委托类, 以及处理事后消息, 代理类的对象并不真正实现服务, 而是通过调用委托类的相关方法, 来提供特定的服务.

简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性, 因为这种间接性我们可以附加多种用途.

代理模式

  • 代理模式: 为其他对象为提供一种代理以控制对这个对象的访问.
classDiagram class Super{ <<interface>> +operation() } class SubObject{ +operation() } Super <|.. SubObject : 实现 class Proxy{ +operation() } Super <|.. Proxy : 实现 SubObject <-- Proxy : 控制权

Super类定义了SubObject和Proxy的公用接口, 这样在需要使用SubObject的任何地方都可以使用Proxy.

应用场景:

  • 远程代理: 远程对象的本地代表, 本地方法调用这个对象会被转发到远程中.
  • 虚拟代理: 虚拟化开销大的对象
  • 安全代理: 控制访问权限
  • 智能指引: 调用真实的对象时, 处理另外一些事

静态代理

在编译时期就已经将接口, 被代理类等确定下来. 在程序运行之前代理类的.class文件就已经生成.

例子:

classDiagram class Interface{ <<interface>> void doSomthing() void doSomthingElse() } class InterfaceImplFirst{ void doSomthing() void doSomthingElse() } class InterfaceImplTwo{ void doSomthing() void doSomthingElse() } Interface <|.. InterfaceImplFirst : 实现 Interface <|.. InterfaceImplTwo : 实现 InterfaceImplFirst <-- InterfaceImplTwo : 代理

Interface.class

public interface Interface {
    void doSomething();
    void doSomethingElse(String arg);
}

InterfaceImplFirst.class

public class InterfaceImplFirst implements Interface{

    public void doSomething() {
        System.out.println("InterfaceImplFirst: doSomething");
    }

    public void doSomethingElse(String arg) {
        System.out.println("InterfaceImplFirst: doSomethingElse " + arg);
    }
}

InterfaceImplTwo.class

public class InterfaceImplTwo implements Interface {
    private final Interface interfaceImplFirst;

    public InterfaceImplTwo(Interface interfaceImplFirst){
        this.interfaceImplFirst = interfaceImplFirst;
    }

    public void doSomething() {
        interfaceImplFirst.doSomething();
        System.out.println("InterfaceImplTwo: doSomething");
    }

    public void doSomethingElse(String arg) {
        interfaceImplFirst.doSomethingElse(arg);
        System.out.println("doSomethingElse: doSomethingElse " + arg);
    }
}

反射

基本使用:

//获取Class对象的三种方法:
Class<User> clazz = User.class;
Class<User> clazz = user.getClass();
Class<User> clazz = Class.forName(User.class);
//Class获取属性
public Field getField(String name) {...} //获取指定名称字段
public Method getMethod(String name, Class<?>... parameterTypes) {...} //获取指定名称和签名的方法
public Constructor<T> getConstructor(Class<?>... parameterTypes){...} //获取指定参数列表公有构造器
public Constructor<?>[] getConstructors() throws SecurityException {...} //获取所有公有构造器
//记载和类位于同一目录下的资源, 通过类加载器获取
public java.net.URL getResource(String name) {...} //返回URL形式的资源
public InputStream getResourceAsStream(String name) {...} //返回输入流形式的资源
//Constructor构造器的操作
public void setAccessible(boolean flag) {...} //给予私有化构造方法,成员方法,成员变量操作权限
public T newInstance(Object ... initargs) {...} //通过这个构造器声明一个类的新实例
public int getModifiers() {...} //获取构造器的访问修饰符
//Method方法调用
public Object invoke(Object obj, Object... args) {...} //obj为操作对象静态方法为null, args为方法参数

详情可以参考博客

例子:

Class<?> clazz = Class.forName("java.util.Date");
Date instance = (Date)clazz.newInstance();

使用反射复制数组:

使用Object类实现:

public static Object copy(Object array, int newLength){
    Objects.requireNonNull(array);
    Class<?> clazz = array.getClass();
    System.out.println(clazz.getName());
    if (!clazz.isArray()) {
        return null;
    }
    Class<?> componentType = clazz.getComponentType();
    Object newArray = Array.newInstance(componentType, newLength);
    System.arraycopy(array, 0, newArray, 0, newLength);
    return newArray;
}

泛型方式实现:

public static <T> T copy(T array, int newLength){
    Objects.requireNonNull(array);
    Class<?> clazz = array.getClass();
    if (!clazz.isArray()){
        return null;
    }
    Class<?> componentType = clazz.getComponentType();
    Object o = Array.newInstance(componentType, newLength);
    System.arraycopy(array, 0, o, 0, newLength);
    return (T)o;
}

使用泛型和反射实现模型转换:

public class Converter {
    public static <T, S> T convert(S s, Class<T> clazz){
        try {
            T t = clazz.newInstance();
            if (s == null){
                return t;
            }
            BeanUtils.copyProperties(s, t);
            return t;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

动态代理

在程序执行中创建对象, 不需要程序员去创建文件

功能:

  1. 控制访问, 在代理中控制是否可以调用目标的方法
  2. 功能增强, 在完成目标调用时, 附加额外的一些功能, 这些额外的功能叫做功能增强

优点:

  1. 不用创建代理类

  2. 可以给不同的目标随时创建代理

流程:

JDK实现动态代理:

  1. 创建一个处理程序, 经过这个处理程序处理的类的方法执行都会将耗时打印在控制台上
class MyInvokeHandler<T> implements InvocationHandler {
    private T proxied = null;

    public MyInvokeHandler(T proxied){
        this.proxied = proxied;
    }

    /**
     *
     * @param proxy 
     * @param method 代理对象的动作
     * @param args 动作的参数列表
     * @return 返回
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long before = System.currentTimeMillis();
        Object invoke = method.invoke(proxied, args); //使用反射调用类中的方法
        long after = System.currentTimeMillis();
        System.out.println(method.getName() + " used time: " + (after - before));
        return invoke;
    }
}
  1. 下面是被代理对象和其实现接口
interface Super{
    void printHello(String param);
}

class Proxied implements Super{

    public void printHello(String param){
        System.out.println("Hello Proxied: " + param);
    }
}
  1. 实现动态代理
//1. 创建一个被代理类, 就是被处理程序处理的类
Proxied proxied = new Proxied();

//2. 创建程序处理类处理这个被代理类
InvocationHandler handler = new MyInvokeHandler<>(proxied);

//3. 根据程序处理类动态生成代理类
Class<?> proxyClass = Proxy.getProxyClass(Super.class.getClassLoader(), Super.class);

//4. 生成代理类的构造器
Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);

//5. 使用代理类的构造器生成代理对象
Super s = (Super)constructor.newInstance(handler);

//6. 检测代理是否有效
s.printHello("axianibiru");

或者:

//1. 创建被代理类
Proxied proxied = new Proxied();
//2. 生成代理处理程序
InvocationHandler handler = new MyInvokeHandler<Super>(proxied);
//3. 根据代理处理程序动态生成代理类
Super s = (Super)Proxy.newProxyInstance(Super.class.getClassLoader(), new Class<?>[]{Super.class}, handler);
//4. 调用被代理后的方法
s.printHello("axianibiru");
//5. 查看代理类行信息
Class<? extends Super> clazz = s.getClass();
//6. 查看继承和实现关系
Class<?> superclass = clazz.getSuperclass();
System.out.print(clazz.getName() + " extends " + superclass);
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> anInterface : interfaces) {
    System.out.print( " implements " + anInterface.getName() + " ");
}

输出:

Hello Proxied: axianibiru
printHello used time: 0
com.proxyTest.dynamicProxy.thridDemo.$Proxy0 extends class java.lang.reflect.Proxy implements com.proxyTest.dynamicProxy.thridDemo.Super
posted @ 2022-04-19 19:10  AxiaNibiru  阅读(68)  评论(0)    收藏  举报