Java 静态代理和动态代理

Java 静态代理和动态代理

代理模式:A调用B,由于某些原因(解耦合、保护B、扩展B),B不想让A直接调用,创建一个中间代理者C,由A调用C,由C中调用B的功能和C封装的东西。

优点:

  • 将调用者与被调用者分离,保护被调用者,降低耦合度
  • 扩展被调用者功能时比较方便

缺点:

  • 增加较多的代理类,类的设计数量会上升,增加系统复杂度
  • 请求经过代理类,整体的运行响应速度会有影响

静态代理只能指定单一的被代理类,动态代理可以在运行时使用反射机制动态生成代理类

下面举三个例子,分别不使用代理使用静态代理使用动态代理来进行比较。

People接口含有一个方法say(),每个实现此接口的类都要输出自己的姓氏,但是有一天需求扩展,还要在执行 say() 之后输出一句代表新增扩展功能的字符串。

代码举例:

公共接口:People

// 人类接口
public interface People {
    // 说话方法
    public void say();
}

不使用代理

// 不使用代理类,实现人类接口
public class Ling implements People {
    public void say() {
        System.out.println("I am Ling ... ");
    }
}
public class MyTest {

    public static void main(String[] args) {

        // 1、不使用代理
        System.out.println("-- 不使用代理 --");
        // 创建基本类对象
        People ling = new Ling();
        // 新增扩展功能
        System.out.println("扩展功能 ... ");
        // 执行基本类基本方法
        ling.say();
    }
}

不使用代理的时候,就只能指定实现类Ling,且执行 say() 方法,再单独执行代表扩展功能的字符串。如果有很多个地方都要执行 ling.say() ,当扩展功能时,那么每个调用 ling.say() 的地方都要添加扩展功能代码,就会显得十分繁琐。

优点: 简单明了
缺点: 扩展复杂,冗余度高

静态代理:

// 被代理类,实现人类接口
public class Wang implements People {
    public void say() {
        System.out.println("I am Wang ... ");
    }
}
// 静态代理类,封装被代理类
public class WangSayProxy implements People {

	// 内部创建被代理类
    private Wang wang = new Wang();

    public void say() {
    	// 新增扩展功能
        System.out.println("扩展功能 ... ");
        // 执行被代理类基本功能
        wang.say();
    }
}
public class MyTest {

    public static void main(String[] args) {

        // 2、使用静态代理
        System.out.println("-- 使用静态代理 --");
        // 创建静态代理类对象
        People wangSayProxy = new WangSayProxy();
        // 执行静态代理类方法
        wangSayProxy .say();
    }
}

使用静态代理,规定了 WangSayProxy 类为 Wang 类的静态代理类,调用此静态代理类,不仅可以实现调用 wang.say() ,还可以在静态代理类中进行功能增强,最后展示到外层。只要本来调用 wang.say() 的地方,都可以直接调用 wangSayProxy.say() ,如果 wang.say() 有扩展功能,直接在 WangSayProxy 类中就修改即可,减少代码耦合度。

优点: 减耦合,功能扩展方便
缺点: 被代理的对象比较单一,不够灵活

动态代理:

// 被代理类,实现人类接口
public class Zhan implements People {
    public void say() {
        System.out.println("I am Zhan ... ");
    }
}
// 动态代理类,封装被代理类
public class PeopleSayProxyHandler implements InvocationHandler {

	// 内部创建Object对象
    private Object object;

	// 有参构造(指定被代理的动态类型)
    public PeopleSayProxyHandler(Object object) {
        this.object = object;
    }

	// 动态生成被代理类
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    	// 执行扩展功能
        System.out.println("扩展功能 ... ");
        // 执行动态被代理类的方法
        method.invoke(object, args);
        return null;
    }
}
public class MyTest {

    public static void main(String[] args) {

        // 3、使用动态代理
        System.out.println("-- 使用动态代理 --");
        // 创建希望被动态代理的类
        People zhan = new Zhan();
        // 创建动态代理类(此处指定被动态代理对象,此对象为参数,运行时才能确定创建对象)
        InvocationHandler peopleSayProxyHandler = new PeopleSayProxyHandler(zhan);
        // 通过Proxy类的静态方法newProxyInstance返回一个接口的代理实例
        People proxySay = (People) Proxy.newProxyInstance(zhan.getClass().getClassLoader(),
                zhan.getClass().getInterfaces(), peopleSayProxyHandler);
        // 执行动态代理类方法
        proxySay.say();
    }
}

使用静态代理,灵活的将被代理类的功能进行扩展。

可以发现,动态代理的关键点就是使用 Proxy 类的静态方法 newProxyInstance ,因此我们可以查看下源码:

    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
    	// 判断对象为不为空
        Objects.requireNonNull(h);

		// 对象克隆
        final Class<?>[] intfs = interfaces.clone();
        // 创建安全管理器
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
        	// 此方法调用上述安全管理器对象检查是否存在恶意代码
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
         // 生成代理类对象
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

			// 使用指定的调用处理程序获取代理类的构造函数对象
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            // 如果Class作用域为私有,通过 setAccessible 支持访问
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            // 获取ProxyClass构造函数创建Proxy代理实例
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

更详细的源码解读可以参考此文章:动态代理源码解读

你可能感兴趣的:(Java,java,代理模式,开发语言)