1、什么叫做面向切面编程(aop)及其应用场景
对比面向对象编程(oop),oop中模块化的核心单位是类,而aop的核心单位是切面。切面使事务管理等关注点的模块化得到实现。比如跨多个类型和对象的事务管理。登录token校验、方法执行的权限校验(访问控制)、性能检测、事务管理、日志记录等
2、切面编程的名词
切面(Aspetct):切点和通知的关系称为切面
连接点(Join Point):类中所有的方法都是连接点
切点(Point Cut):缺少共性功能代码的方法 (切入点一定是连接点,连接点不一定是切入点)
通知(Advice)(有的人叫增强):定义切面要干的事,被抽取的共性代码逻辑。(通知有位置区分)
前置通知(before)
后置通知(after)
返回通知(after-returning)
异常通知(after-throwing)
环绕通知(around)
引入(Introduction):通知只能抽取共性逻辑代码,变量是抽取不出来的,需要把变量引入到切点方法中,就要用引入。引入机制可以成为类添加额外的成员变量或者成员方法。引入机制是在编译器或者类加载期完成的。(了解)
目标对象(Target Object):缺少了共性代码的对象 ,即被抽离共性的代码的对象(目标对象是不完整的)
代理对象(AOP Proxy):代理目标对象。
织入(weaving):在切入点地方,代理对象把通知织入到目标对象中,是一个动作(springAop在运行时织入 )
3、切面编程的相关注解和配置
@Aspect 定义切面
@Pointcut定义命名的切点
切入点表达式:execution(* cn.tedu.store.service.impl.*.*(..))&& args(*)
第一个*:返回任意类型
第二个*:类
第三个*:类中的方法
第四个(..):方法中接收任意类型的参数
第五个*:指定参数
execution([方法的访问控制修饰符] 方法的返回值 包名.类名/接口名.方法名(参数))
注意:方法的访问控制修饰符可以省略,写方法名的时候要把包名和类名全部带上。
@Before定义方法执行前通知 (应用场景:校验)
@After定义方法执行后通知 (应用场景:清理现场,释放资源)
@AfterReturning定义方法执行结果返回后通知 (应用场景:常规数据处理)
@AfterThrowing定义方法执行中抛出异常后通知 (应用场景:异常处理)
@Around 可以在目标方法的前后执行 通知 (应用场景:十分强大,可以做任何事情)
4、案例
4.1、切面获取目标方法参数的方式:
第一种:通过JoinPoint的JoinPoint.getArgs()方法进行获取,它是ProceedingJoinPoint的父类。
第二种:通过切入点表达式加上&& args(*)(耦合度太高,不推荐用)
4.2、获取目标方法的参数进行修改后传给目标方法,只能用ProceedingJoinPoint,也就只能用around通知方式
4.3、切面获取返回值的方式:
第一种: @AfterReturning(value = "pointCut()", returning = "res") (returning 可以自定义,但是要与注解的方法参数名一致,即为Object res)
第二种:使用around通知,ProceedingJoinPoint.proceed()方法的返回值就是目标方法的返回值(注意:ProceedingJoinPoint返回目标对象的返回值的时候,返回方法类型要与目标方法返回类型一致)
5、aop代理
aop代理分为静态代理和动态代理,静态代理的代表是AspectJ,动态代理的代表是springAop。
所谓动态代理就是说aop框架不会去修改字节码,而是在内存中存在临时为方法生成一个Aop对象(我们可以把它称为“代理对象”),这个Aop对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
5.2、CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,即在编译后,通过修改字节码,生成新的代理对象proxyObj。注意,CGLIB是通过继承的方式做的动态代理。因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
举例:
JDK动态代理:
目标类(实现类)可以认作为厨师张三,张三能够具体实现接口的所有功能,比如老板可以让张三做饭,当aop代理的时候,会根据张三所实现的接口,再创造一个张三A(代理对象)作为张三的分身,这时候张三和张三A具有相同的接口(动态的体现),两者长得一模一样,这时候张三A就可以在张三做饭之前把菜洗干净了,然后张三本人来做饭。但是在老板(调用者)看来,自始至终都是张三(目标类)一个人在洗菜做饭。但是张三(目标类)知道,在他动手做饭之前他的代理对象帮他做了一些事情,同理代理对象也可以在他本人做晚饭以后帮他洗碗。
所以,目标类要是没有实现接口,程序就不能根据接口在实现出来一个代理对象,也就不能代替目标类(实现类)去做一些事情。这种代理方式只有在通过接口调用方法的时候才有效。
基于注解开发AOP:
不同注解之间的执行顺序是固定的:
around before
before
around after
after
afterReturning
相同注解之间的执行顺序是不固定的,受方法名和位置的影响,所以如果程序和执行顺序有关还是建议使用xml配置
类似继承
CGLIB动态代理:全称(Code Generation Library),是一个代码生成的类库,可以动态生成字节码对象
CGLIB实现动态代理步骤:
1、凭空生成一个字节码对象(空的)
2、设置字节码对象的父类是目标对象
3、通过生成的字节码对象进行回调方法,在回调的过程中进行目标方法的增强(方法功能的增强)
4、创建代理对象(完成动态代理)
调用代理对象的方法,方法功能就增强了
CGLIB是第三方的,但是已经整合到spring的核心jar包中了。
idea查看一个接口的子接口或者实现类的快捷键:
先选中类或者接口,再按从Ctrl + h



版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/18368.html