Spring_IOC_AOP_动态代理

IOC是什么:

是一种控制反转,依赖注入的思想:

控制:
有Spring容器控制生成对象,如果你A类依赖于B类的对象,不用你在A类的代码里硬编码的方式将new B() 对象A类的代码里。

反转:
不是A类生成对象,A类只需要在类里留一个B类的接口,并写上注释,告诉容器我这里需要一个B类对象,容器生成这个对象后,再注入到B类的接口。

在这里插入图片描述
https://zhuanlan.zhihu.com/p/65731623

Spring如何设计容器的?

设计了两个接口用以表示容器。

BeanFactory 低级容器,可以理解为一个HashMap,key是BeanName. value是Bean实例,负责加载bean,获取bean。
ApplicationContext 高级容器 获取资源,refresh刷新,重新加载,刷新所有的bean。

Spring IoC 的初始化过程

1.用户构造ClassPathXmlApplicationContext(CPAC)
2.CPAC访问抽象高级容器的refresh方法,方法里回调低级容器的refreshBeanFactory 方法,低级容积加载所有beanDefinition和Properties到容器中。
3.低级容积加载成功后,高级容器实例化单例等功能。

Bean 工厂和 Application contexts 有什么区别?

Bean 工厂:低级容器,只负责从xml中加载bean的定义和属性到容器中,如果bean有依赖关系,使用占位符。
Application contexts:高级容器,负责实例化单例,进行真正的注入,碰到占位符,再从容器中获取这个bean,然后注入到事例中。

什么是BeanDefion

bean定义的一个顶级接口
Class只是有这个类的所有信息,但程序需要这个对象的形式,比如单例,是否需要延迟加载,需要BeanDefinition去再次加工
在这里插入图片描述
https://zhuanlan.zhihu.com/p/65731623

AOP

把一些交叉植入的功能分离成一个个模块,如事务,日志等,然后核心业务值专注于核心业务功能,需要其他功能,只需要将这些切入到需要的地方。

底层是依赖动态代理实现的,代理 = 增强对象 + 增强。 代理 = 核心业务 + 其他功能。

在这里插入图片描述
https://zhuanlan.zhihu.com/p/65731623

https://www.zhihu.com/question/20794107/answer/658139129


https://www.zhihu.com/question/20794107/answer/658139129

静态代理

一个代理类只能代理一个目标类。在代码运行前,为每个目标类,写好对应代理类,在运行时,加载代理类的class文件和被代理类的class文件,然后生成代理类对象和目标类对象,调用代理类对象方法的里面会调用目标类对象的方法。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
缺点:不够灵活,当要增强的目标对象很多时,要编写大量的代理类。

动态代理

假设现在有100个不同的类,每个类负责的业务不同,但都实现了Calculator接口,是处理add()业务的不同子类。
现在需求:要在这100个不同类的add()方法前面和后面增加打印日志的功能。

既然不能事先编写代理类,又要在代码运行时生成拥有add()方法的代理类对象,接口Calculator的class对象来反射的生成对象,Calculator接口的class对象包含接口的所有信息,有add()方法,那靠类对象生成的对象肯定也有add()方法了,但因为是接口,接口的class对象没有构造方法,不能生成对象。

Proxy类有个静态方法,getProxyClass(ClassLoader, interfaces),传入一个类加载器对象和一组接口,就可以返回
一个class对象,并且class对象含有构造函数。

利用方法可以将Calculator接口类对象的所有信息拷贝一份,并添加上构造方法。
这样我就可以靠Calculator接口的类对象反射生成拥有add()方法的对象了。

在这里插入图片描述

在这里插入图片描述
Proxy.getProxyClass()本质:以Class造Class

有了Class对象就可以生成对象,执行对象的方法,为对象设置属性等等
在这里插入图片描述
比较难理解的
根据代理Class的构造器创建对象时,需要传入InvocationHandler,每次调用代理对象的方法,最终都会调用InvocationHandler的invoke()方法。
在这里插入图片描述

用Class的构造器创建对象时,传入了一个InvocationHandler对象,通过构造器传入一个引用,那么必然有一个成员变量去接收。是的,代理对象的内部确实有一个成员变量InvocationHandler,而且代理对象的每个方法内部都会调用handler.invoke(),InvocationHandler对象成了代理对象和目标对象的桥梁,不像静态方法那么直接。

InvocationHandler是代理对象和目标对象的桥梁在这里插入图片描述
仔细看动态代码,发现invoke()方法中没有写入目标对象。现在写入目标对象。

因为用Proxy帮我们生成的接口类对象中的构造函数会传一个InvocationHandler对象,代理对象在调用代理方法时,内部会调用InvocationHandler对象的invoke()方法,

所以我们相当于在invoke方法里,既要原来对象调用它原本的方法,又要在invoke()方法中写上增强逻辑

它是代理类和增强类的一个中间桥梁。

在这里插入图片描述
在这里插入图片描述
但这种方式是硬编码不行,我们将要代理的对象传过来就可以了。
在这里插入图片描述
在这里插入图片描述
现在无论你有多少类,只需要把实例传进来,Proxy类都会给你返回对应的代理对象。

实际编程中,会用Proxy.newInstance(),直接返回代理实例对象,自己就先生成构造器,再生成对象给你,你只用传一个你想让invoke()方法执行什么逻辑的InvocationHandler对象就好了。生成的对象,执行的是invoke()方法。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

精简动态代理

现在需求:要在这100个不同类的add()和substract()方法前面和后面增加打印日志的功能。这100个类有一个共同的Caculator接口,100个类中的add()和substract()就是覆写的这个接口的add()和substract()方法。

需要两个类,

一个是Proxy类负责生成代理类的对象,

Proxy通过newProxyInstance(ClassLoader, interfaces, InvocatinHandler)方法,复制这个接口的class类对象,并为接口的类对象添加一个构造函数,这样有了类对象,构造函数,就可以实例对象了,而且这个实例对象因为是用100个不同类的共同接口生成的,所以这个对象可以调用add()和substract()方法。

另一个是InvocationHandler,它是负责代理类和增强对象的类。生成的动态代理类对象调用add()方法时,其实是调用InvocationHandler对象的invoke()方法,invoke()方法会根据方法名add或substract生成出方法对象,然后反射执行这个方法, Object res = method.invoke(target,args); 哪个target,对象执行,你传入就好了。

        Calculator target = new CalculatorImpl();
        // 通过Proxy类帮忙生成的Calculator接口代理对象
        Calculator calculatorProxy = (Calculator) getProxy(target);
        // 代理对象调用接口中定义的方法
        // 代理对象调用方法时,实际内部调用的是invoke()方法,invoke()通过反射
        // 得到执行方法的名字再去生成对应的method对象,method方法由生成代理对象时传入的target执行
        calculatorProxy.add(1, 2);  
        calculatorProxy.substract(2,1);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值