1. 动态代理讲解

第一讲

动态代理讲解

  • 动态代理是框架的基础(默认反射机制都清楚啦~),

因为框架是为了应用于不同情境下的,所以不同模块之间的代码需要进行解耦,(低耦合,高内聚,可扩展)。动态代理的出现就是为了解决耦合的问题。

举列:

Spring框架,Mybatis框架都是基于动态代理实现的,这是一个重要思想,后续讲解中会陆续讲解,这些框架的实现原理。

1. Proxy介绍

  • 翻译
    proxy n.代理人,代表,代理权,代表权(bingDic翻译)
    这就是接下来讲解的核心类!!!

  • JAVA中API介绍
    -在这里插入图片描述
    重点是了解

  1. 构造方法
  2. getProxyClass
  3. newProxyInstance

1.1getProxyClass的讲解

getProxyClass(ClassLoader,Interface)
顾名思义,getProxyClass的目的是为了获取代理类
要对代理对象进行操作,那么肯定就需要获得该类是字节码文件。
1、所以在此基础就自然的需要类加载器(ClassLoader)
2、并且为了指定要代理类的类型,那么就需要一个接口(interface),接口的作用,指定了代理对象的方法规则。

//实例用Collection演示
Class clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class)

了解:显然在此基础上,就会有疑问是否可以对一个类进行代理,不通过接口。答案是可以的,但是java本身不提供,需要第三方提供方法【CGLib】,通过子类实现代理。

在jvm知道了加载该类的加载器,以及字节码中方法加载规则,那么就可以生成一个新的字节码文件,就是动态生成的代理类。

1.2 生成代理对象

在上述操作,已经获取到代理对象的字节码文件【方法区】,但是还未创建出实例【堆】。

  • 那么生成了字节码文件,自然就需要生成实例对象使用,自然就想到利用反射中的newInstance()生成实例对象。
  • 但是如果直接newInstance()是不行的。根据上面贴图中可见,构造方法只有一种有参构造Proxy(InvocationHandler h)
  • 所以需要在newInstance中传入 InvocationHandler的实例参数
//创建InvocationHandler的实例对象
class MyInvocation implements InvocationHandler{
 			@Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
}
//获得字节码文件
Class clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class)
Constructor construtor = clazz.getConstuctor((InvocationHandler.class)
//通过构造器生成实例
Collction collection =  (Collection)construtor .newInstance(new MyInvocation());

在Proxy中的部分源码

 protected InvocationHandler h;
 protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

在API中有这样的描述:
在这里插入图片描述

1.3简化书写

上述书写是可以成功创建代理类的,但是比较麻烦,java提供了应该更简单的方法

newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

Colleciton collection = (Collection)Proxy.newProxyInstance(
								Collection.class.getClassLoader(),
								Collection.class,
								// lambda表达式,更为优雅
								(proxy,method,args)->{
								//暂时不写,下面讲解。
									return null;
								}					
);
//此时已经生成了collection实例类,操作和原来一样

在这里插入图片描述

1.4 InvocationHandler的讲解

  • 所有源码
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

修改上面的代码

 Collection coll= (Collection) Proxy.newProxyInstance(
 				Collection.class.getClassLoader(),
                Collection.class,
                //匿名实现类
                new InvocationHandler() {
                ArrayList target = new ArrayList();
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Long beginTime = System.currentTimeMillis();
                        //method.invoke(对象,参数)--> 执行调用的方法
                        Object retVal = method.invoke(target, args);
                        Long endTime = System.currentTimeMillis();
                        System.out.println(method.getName() + " running time of" + (endTime - beginTime));
                        return retVal;
                    }

                }
        );

        coll.add("jack");
        coll.add("rose");
        coll.add("tom");

此时proxy调用add方法,实际就是将(proxy,add,“jack”)传入了InvocationHandler中的invoke方法。
再通过invoke实现对对象方法的操作,因为现在要通过代理对象进行处理,中间多了一个桥梁(原来是直接调用),这样就可以在中间做其他操作【例如:修改参数等,添加额外“代码”】,改变原本操作。

AOP面向切面编程的核心思想,就是以上的这几句话。

那么下一小结就讲,aop的思想及编程。

版权所有【weixin_41263632 , Limm_666】,禁止转载

猜你喜欢

转载自blog.csdn.net/weixin_41263632/article/details/82908117
1.