4.113 Spring的核心-面向切面编程AOP
-
什么是AOP?
-
OOP(Object-Oriented Programming)面向对象编程,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。
-
AOP(Aspect-Oriented Programming),一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。
-
AOP相关术语
-
Aop, aspect object programming 面向切面编程 让关注点代码与业务代码分离
-
关注点,重复代码就叫做关注点;
-
切面,关注点形成的类,就叫切面(类)!
-
面向切面编程,就是指 对很多功能都有的重复的代码抽取,再在运行的时候网业务方法上动态植入“切面类代码”。
-
切入点,执行目标对象方法,动态植入切面代码。可以通过切入点表达式,指定拦截哪些类的哪些方法; 给指定的类在运行的时候植入切面类代码。
-
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
- 代理(Proxy)是一种设计模式, 提供了对目标对象另外的访问方式;即通过代理访问目标对象。 这样好处: 可以在目标对象实现的基础上,增强额外的功能操作。(扩展目标对象的功能)。
-
举例:张学友明星(目标)<---经纪人(代理)<-------电视台
-
代理模式的关键点: 代理对象与目标对象。
-
-
静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
-
静态代理要实现目标对象一样的接口
-
可以做到在不修改目标对象的功能前提下,对目标对象功能扩展
-
缺点:(代理工厂? 可以使用动态代理弥补缺点。)
-
因为代理对象,需要与目标对象实现一样的接口。所以会有很多代理类,类太多
-
一旦接口增加方法,目标对象与代理对象都要维护。
-
JDK动态代理:只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
-
代理对象,不需要实现接口
-
代理对象的生成,是利用JDKAPI, 动态的在内存中构建代理对象(需要我们指定创建 代理对象/目标对象 实现的接口的类型
-
动态代理, JDK代理, 接口代理
-
总结:代理对象不需要实现接口,但是目标对象一定要实现接口;否则不能用动态代理
-
缺点(以子类的方式实现(cglib代理)弥补)
-
有一个目标对象,想要功能扩展,但目标对象没有实现接口,怎样功能扩展?
-
CGLIB来动态代理:如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
-
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。
-
CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
-
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
-
Cglib子类代理实现具体:
-
需要引入cglib – jar文件, 但是spring的核心包中已经包括了cglib功能,所以直接引入spring-core-3.2.5.jar即可。
-
引入功能包后,就可以在内存中动态构建子类
-
代理的类不能为final, 否则报错。
-
目标对象的方法如果为final/static, 那么就不会被拦截,即不会执行目标对象额外的业务方法
-
代理在Spring的AOP编程中
-
如果加入容器的目标对象有实现接口,用JDK代理;
-
如果目标对象没有实现接口,用Cglib代理
-
AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
-
AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
- Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
- 代理(Proxy)是一种设计模式, 提供了对目标对象另外的访问方式;即通过代理访问目标对象。 这样好处: 可以在目标对象实现的基础上,增强额外的功能操作。(扩展目标对象的功能)。
-
实现方式
-
于注解的切面实现:在这种情况下(基于@AspectJ的实现),涉及到的切面声明的风格与带有java5标注的普通java类一致。<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 开启事物注解权限
-
@Aspect 指定一个类为切面类
-
@Pointcut("execution(* com.itmayiedu.service.UserService.add(..))") 指定切入点表达式
-
@Before("pointCut_()") 前置通知: 目标方法之前执行
-
@After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
-
@AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行)
-
@AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行
-
@Around("pointCut_()") 环绕通知: 环绕目标方法执行
-
基于XML Schema方式的切面实现:在这种情况下,切面由常规类以及基于XML的配置实现
-
引入jar文件 【aop 相关jar, 4个】
-
引入aop名称空间
-
aop 配置
-
努力不一定成功,但不努力一定会失败~