调用者 代理对象 目标对象
代理对象除了可以完成核心任务,还可以增强其他任务,无感的增强
代理模式目的:
不改变目标对象的目标方法的前提,去增强目标方法
分为:静态代理,动态代理
静态代理
有对象->前提需要有一个类,那么我们可以事先写好一个类,他是一个代理类
程序员为目标类编写一个代理类(用于增强目标方法),要求目标类和代理类实现同一个接口,让用户感觉代理和目标是一类的东西,无感的
创建一个maven
创包com.fs.staticproxy
创目标类和代理类的统一接口:
创建目标类:
目标方法之前可能需要扩展 日志记录 权限管理等等 这些不是非核心代码、功能,可能就是一些简单的业务,但是又不省略,但是他又不是固定的,时可变的,而卸载目标类就是硬代码
创建代理类:代理代理 -> 我中有你 有一个目标对象
出现问题:重复
解决办法:我(代理类)中有(目标类)你
给属性复赋值:构造方法 set方法 实现了代理类增强方法
测试类(调用者):
需要改变时,目标对象、目标类不需要改变,核心代码不用改变,,只需要改代理对象
缺点:多个接口要实现相同的方法,增强相同的方法,那么需要创建很多个代理类,这是不对的,
核心接口加方法,代理类也要加方法实现对应的方法,目标对象和代理类都需要维护
导致静态代理的缺点问题根源->代理类的存在
动态代理
这个静态代理类不要你写,通过code动态生成
存的是BussinessInterface接口 -> 使得这个代理类代理的范围更加多一点,不再只有Buiness这一个实现类的代理类,他可以实现只要你的目标类实现BussinessInterface这一类 统一接口下面所有的不同类型的这个目标类都可以被我的代理类所代理
站在使用者这边,我们在乎的是代理类对象,而不是代理类,基于这个,
jdk可以自动生成生成这个代理类对象,确实可以实现,我要代哪一个接口,接口告诉我,然后jdk有一个api方法,经过这个api方法的时候,他就可以得到一个api代理对象,此时我就不需要代理类了,我直接用这个代理对象就行了
通过接口的class对象,创建一个实现类的Class对象,再通过反射得到实现类的对象(这个实现类是动态的,创建的是不存在的实现类对象)
jdk提供了通过接口的Class对象,创建一个实现类(动态,不存在)的Class对象的API:java.lang.reflect .Proxy类:
Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。以class造class
接口不能创建方法,因为它没有构造方法(用于创建对象),,现在想创建对象,
根据接口的创建对象,没有这个类,没有这个构造方法,也可以通过反射得到对象,通过反射得到Class对象,调用它的构造方法得到对象
我们现在需要一个类 class 由于接口不能创建构造方法,所以我们需要根据接口的class来克隆/生成一个类的class,这个类的classs是构造方法的class根据 根据接口的class对象生成类的class对象,这个类的class对象复制了接口的所有的方法,同时他又有构造方法。
创建对象的核心:前提条件就是要有该类的Class对象,(也可以通过new的方式去拿)拿到之后我么就可以通过反射创建对象,当然底层还是调用构造方法,比如接口类没有构造方法就无法创建对象
动态代理(基于接口)
创一个类:
$ -> 动态类
Class Proxy.getProxyClass(),得到Class对象对应类是Proxy的子类,而且得到Class对应类的模版参考Proxy类
Proxy的构造方法
子类构造方法(由于父类构造方法私有,不能调用父类构造方法)
父类只提供给这个有参构造方法:
$Proxy4:生成一个如下构造方法 虽然是受保护类型,但是
(上面做了,通过接口的class对象构造代理类的实现对象)
代理对象执行目标方法他会在底层调用invoke()方法
只要我在invoke写核心code 那么我就可以重写excute的逻辑code
为什么代理对象执行目标方法,底层还调用lnvocationHandler的invoke()?
为什么还要proxy.excute()和invoke()分开呢?
当我们使用动态代理时,代理对象执行目标方法时底层还调用`InvocationHandler`的`invoke()`方法是因为代理对象并不知道具体要执行的目标方法是什么,以及是否需要添加额外的逻辑。因此,代理对象将目标方法的调用委托给了`InvocationHandler`来处理。
代理对象在执行目标方法时,会将目标方法的信息(包括方法名、参数等)传递给`InvocationHandler`的`invoke()`方法。`InvocationHandler`可以根据这些信息进行额外的操作,比如在方法调用前后进行日志记录、权限验证等。
为什么还要将`proxy.execute()`和`invoke()`分开呢?这是因为动态代理的实现是通过`Proxy`类和`InvocationHandler`接口来配合完成的。`Proxy`类负责生成代理对象,而`InvocationHandler`接口负责处理方法调用。
`Proxy`类生成的代理对象并不直接实现目标接口的方法,而是在代理对象的方法中调用`InvocationHandler`的`invoke()`方法。这样的设计可以将代理对象的方法和`InvocationHandler`的逻辑分离,使得代理对象可以专注于代理的行为,而不需要关心具体的方法实现。
通过将方法调用和逻辑处理分开,我们可以更灵活地控制代理对象的行为。可以在`InvocationHandler`的`invoke()`方法中添加额外的逻辑,也可以根据需要选择不同的`InvocationHandler`实现,实现动态切换和扩展代理对象的功能。
总结来说,代理对象执行目标方法时底层还调用`InvocationHandler`的`invoke()`方法是为了将方法调用和逻辑处理分离,以实现更灵活的代理行为。这样的设计使得代理对象可以专注于代理行为,而不需要关心具体的方法实现。同时,通过分离方法调用和逻辑处理,我们可以实现更高级的代理功能,如动态切换代理行为或添加额外的逻辑。
proxy.excute();//但是没看到它重写的代码
匿名类部类
lamba表达式(jdk8)
动态代理: getMappper使用的动态代理
传接口的class对象,得到的是接口的实现类对象,再得到构造方法,再new instance得到实例对象
得到实现类的构造方法
得到接口的实现类对象之后,再实现代理
替换之前写的
Proxy类得到接口的代理类对象,并且还需要对接口的抽象方法进行重写,写在invotionHandler接口对象的invoke()当中
问题: Proxy类得到接口的代理类对象,并且还需要对接口的抽象方法进行重写,重写方法的逻辑代码,在lnvocationHandler接口对象的invoke0中
Proxy:创建代理对象
lnvocationHandler接口对象的invoke()对方法重写的为了创建代理对象与编写方法逻辑代码方法体分离,解耦
我们在创建代理对象的时候,可以不实现方法体,在后期根据你实际需求,传递方法体
开始代理
此时只能指定代理指定的代理类对象
现在改一改
对任何接口的目标类进行增强
所有:
对他增强
proxy.fun();
实现增强
配置文件优化,把增强代码出来,分离,形成一个增强类,
jdk实现的动态代理要求目标类一定要实现接口,所以这也是一个其动态代理的一个缺点所在
第二种方式:
使用第三方的CGLIB,它生成的代理类,这个类会继承目标类,所以他不会管这个目标类有没有实现接口,但是它要i求不能实现fina关键字(继承不能)
jdk自带的动态管理,要求目标类一定要实现接口,没有实现接口那么就是用CGLIB,记得不要使用final关键字就行了
动态代理的优点
优点:
1.没有代理类,解决静态代理的代理类暴增的问题
2.解决了静态代理的重复代码问题
3.创建代理对象与重写方法逻辑代码解耦
缺点:
增强代码与目标方法是通过硬编码的方式组织在一起,如果需要动态生成增强代码,需要修改代码
SpringAop
AOP:面向切面编程,对OOP的补充。不改变目标方法代码前提,增强目标方法
横切面:切面 目标方法/目标类->独立 增强类/增强方法->独立 两者独立,目标类前后都有
增强类/增强方法 但是在运行的时候,通过AOP或者其他技术,感觉这三个玩意是一起的,面向横切面
OOP:面向对象编程
userSer。。。 只要写目标类的核心代码 配置/注解的时候
AOP使用场景:
- 事务控制 下单流程(生成订单insert 支付状态update 商品库存数量update)
- 日志记录 (log4j) (开发中的日志表,记录用户行为信息)
- 权限控制
- 性能分析
- 缓存操作 (实际缓存是基于Redis的技术)
Spring两大核心
- IOC/DI:依赖对象之间的解耦
- AOP:目标类与增强类的解耦 关注的是横切面的一个解耦
AOP采取横向抽取机制((动态代理),取代了传统纵向继承机制的重复性代码,其应用主要体现在事务处理、日志管理、权限控制、异常处理等方面。
主要作用是分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点或者横切逻辑,减少对业务代码的侵入,增强代码的可读性和可维护性。
简单的说,AOP的作用就是保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能
SpringAOP开始使用
基于AspectJ这个AOP实现的
2.编写目标类目标方法
3.编写增强类(通知类)中增强方法
基于AspectJ方式,对增强类没有任何要求,就是一个普通类
增强:
前置增强
后置增强
最终增强
日志增强
......
4.织入,把目标方法与增强方法编织在一起,Spring提供AOP提供相关配置和注解
通过配置之后,这个before方法先于目标方法执行
delete没有实现增强代码功能
对这个包及子包