动态代理原理

导读:本篇文章讲解 动态代理原理,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

动态代理 (原理)

1.动态代理原理及代码实现

  • 动态代理非常的灵活,可以为任意的接口实现类对象做代理。
  • 动态代理可以为被代理对象的所有接口的所有方法做代理,动态代理可以在不改变方法源码的情况下,实现对方法功能的增强,
  • 动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。
  • 动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。
  • 动态代理同时也提高了开发效率。
  • 缺点:只能针对接口的实现类做代理对象,普通类是不能做代理对象的。

java.lang.reflect.InvocationHandler接口 是代理实例的调用处理程序 实现的接口。用来生产代理人对象的动态代理接口。

可以把被代理对象传递到InvocationHandlerImpl类中,让InvocationHandlerImpl生产被代理对象的代理人对象。

InvocationHandler接口中的方法:

// 在代理实例上处理方法调用并返回结果。
// 作用:使用invoke方法对被代理人的方法进行拦截,让部分方法可以运行,部分方法不能运行
Object invoke(Object proxy, Method method, Object[] args) 

参数:
Object proxy	// 内部产生的代理人对象,不用管
Method method	// invoke方法对传递被代理对象的方法进行拦截,方法内部使用反射技术获取到拦截到的方法
Object[] args	// 拦截到方法的参数

返回值:
Object		// 就是拦截到的方法的返回值

想要实现动态代理:使用Proxy类(java.lang.reflect.Proxy)生成代理人对象

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

Proxy类中的静态方法:

// 返回一个指定接口的代理类对象实例,该接口可以将方法调用指派到指定的调用处理程序。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
                
参数:
    ClassLoader loader		// 传递类加载器
    Class<?>[] interfaces	// 传递被代理对象实现的所有接口
    InvocationHandler h		// 生成代理人的接口,传递InvocationHandler接口的实现类对象
返回值:
    Object		// 返回的就是创建好的代理人对象

InvocationHandler接口的实现类:

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

public class InvocationHandlerImpl implements InvocationHandler{
    //在实现类中定义一个Star类型的变量,用于接收被代理人的对象
    private Star star;

    //使用构造方法,把明星传递到类中,给Star变量赋值
    public InvocationHandlerImpl(Star star) {
        this.star = star;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //获取到方法的名称
        String methodName = method.getName();
        //对方法的名称进行判断
        if("chifan".equals(methodName)){
            throw new RuntimeException("不和你吃饭!");
        }
        if("wanyouxi".equals(methodName)){
            throw new RuntimeException("不和你玩游戏!");
        }
        //其他的方法,使用Method对象调用invoke方法运行方法
        Object v = method.invoke(star, args);
        return v;
    }
}

测试类:

import java.lang.reflect.Proxy;

/*
    动态代理:
        创建代理人对象,对明星进行代理,对明星的方法进行拦截
        调用明星的changge,tiaowu,yandianying方法放行==>可以运行
        调用明星的chifan,wanyouxi方法拦截==>不让方法运行
 */
public class Demo01Proxy {
    public static void main(String[] args) {
        
        CaiXuKun cxk = new CaiXuKun();

        //使用Proxy类中的静态方法newProxyInstance获取代理人对象
        Star cxkProxy = (Star)Proxy.newProxyInstance(CaiXuKun.class.getClassLoader(),
                CaiXuKun.class.getInterfaces(), new InvocationHandlerImpl(cxk));
        cxkProxy.changge();
        cxkProxy.tiaowu();
        cxkProxy.chifan();	//RuntimeException: 不和你吃饭!
        String s = cxkProxy.yandianying(100);
        System.out.println(s);
    }
}

2.动态代理综合案例

代码实现:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/*
    需求:
	使用动态代理模拟unmodifiableList方法,对List接口进行代理
		调用List接口的方法会被拦截
		如果使用的size,get方法,没有对集合进行修改,则允许执行
		如果使用的add,remove,set方法,对集合进行了修改,则抛出运行时异常

    分析:
        1.定义一个代理方法proxyList
            参数:传递List集合
            返回值:被代理之后的List集合
        2.方法内部可以使用Proxy类中的方法实现动态代理
 */
@SuppressWarnings("all")	//注解的作用是抑制警告,不让警告出现
public class Demo02Proxy {
    public static void main(String[] args) {
        //创建List集合对象
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        List<String> proxyList = proxyList(list);
        System.out.println(proxyList.size());//3
        System.out.println(proxyList.get(2));//c
        proxyList.add("d");//UnsupportedOperationException: add no run!
        proxyList.remove(1);//UnsupportedOperationException: remove no run!
        proxyList.set(1,"www");//UnsupportedOperationException: set no run!
    }

    //1.定义一个代理方法proxyList 参数:传递List集合 返回值:被代理之后的List集合
    public static List<String> proxyList(List<String> list){
        //2.方法内部可以使用Proxy类中的方法实现动态代理
        List<String> listProxy = (List<String>)Proxy.newProxyInstance(
            	list.getClass().getClassLoader(), list.getClass().getInterfaces(),
                new InvocationHandler() {
                    //invoke方法对List集合的方法进行拦截,让部分方法可以运行,让部分方法不能运行,抛出异常
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //获取拦截到的方法的名称
                        String methodName = method.getName();
                        //如果使用的add,remove,set方法,对集合进行了修改,则抛出运行时异常
                        if("add".equals(methodName)){
                            throw new UnsupportedOperationException("add no run!");
                        }
                        if("remove".equals(methodName)){
                            throw new UnsupportedOperationException("remove no run!");
                        }
                        if("set".equals(methodName)){
                            throw new UnsupportedOperationException("set no run!");
                        }
                        //如果使用的size,get方法,没有对集合进行修改,则允许执行
                        Object v = method.invoke(list, args);
                        return v;
                    }
                });
        return listProxy;
    }
}

在这里插入图片描述

动态代理案例流程图

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/112026.html

(0)
Java光头强的头像Java光头强

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!