1.jdk和cglib两种代理方式的选择
- ava动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
(1)如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
(2)如果目标对象实现了接口,可以强制使用CGLIB实现AOP
(3)如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
2.Spring的AOP理解
OOP 面向对象,允许开发者定义纵向的关系,但并适用于定义横向的关系,导 致了大量代码的重复,而不利于各个模块的重用。
AOP 面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了 模块间的耦合度,同时提高了系统的可维护性。可用于权限认证.日志.事务处 理。
AOP 实现的关键在于 代理模式,AOP 代理主要分为静态代理和动态代理。 静态代理的代表为 AspectJ;动态代理则以 Spring AOP 为代表。
(1) AspectJ 是静态代理的增强,所谓静态代理,就是 AOP 框架会在编 译阶段生成AOP 代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切 面)织入到 Java 字节码中,运行的时候就是增强之后的 AOP 对象。
(2) Spring AOP 使用的动态代理,所谓的动态代理就是说 AOP 框架不会 去修改字节码,而是每次运行时在内存中临时为方法生成一个 AOP 对象,这个 AOP 对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回 调原对象的方法。Spring AOP 中的动态代理主要有两种方式,JDK 动态代理和 CGLIB 动态 代理:
(1) JDK 动态代理只提供接口的代理,不支持类的代理。核心 InvocationHandler 接口和 Proxy 类,InvocationHandler 通过invoke()方法 反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy 利用 InvocationHandler 动态创建一个符合某一接口的的实例, 生成目标类的 代理对象。
(2) 如果代理类没有实现 InvocationHandler 接口,那么 Spring AOP 会 选择使用 CGLIB 来动态代理目标类。CGLIB(Code Generation Library),是 一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖 其中特定方法并添加增强代码,从而实现 AOP。CGLIB 是通过继承的方式做的 动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代 理的。
(3) 静态代理与动态代理区别在于生成 AOP 代理对象的时机不同,相对 来说 AspectJ 的静态代理方式具有更好的性能,但是 AspectJ 需要特定的编译 器进行处理,而 Spring AOP 则无需特定的编译器处理。 InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy 是最终生成的 代理实例; method 是被代理目标实例的某个具体方法;args 是被代理目标实例 某个方法的具体入参, 在方法反射调用时使用。
3.术语
- 目标对象(Target Object): 被一个或者多个切面(aspect)所通 知(advise)的对象。也有人把它叫做 被通知(adviced) 对象。 既然 Spring AOP 是通过运行时代理实现的,这个对象永远是一个 被代理(proxied)对象。
连接点(Join point):指方法,在 Spring AOP 中,一个连接点 总 是 代表一个方法的执行。其实就是被代理的对象中的所有方法
切入点(Pointcut):切入点是指 我们要对哪些 Join point 进行拦 截的定义。通过切入点表达式,指定拦截的方法,比如指定拦截add* 等。// 目标对象中的一部分方法(要进行功能增强的部分)
增强(通知)(Advice):在切面的某个特定的连接点(Join point)上执行 的动作。通知有各种类型,其中包括“around”.“before”和“after”等通知。 许多 AOP 框架,包括 Spring,都是以拦截器做通知模型, 并维护一个以连接 点为中心的拦截器链。// 一个具体的功能(打日志 开启事务 提交事务 增强类 增强方法)
织入(Weaving):指把增强应用到目标对象来创建新的代理对象的 过程。Spring 是在运行时完成织入。// 将切入点代码和增强方法合在一起的动作
代理对象:经过织入之后产生对象
切面(Aspect):被抽取的公共模块,可能会横切多个对象。在 Spring AOP 中,切面可以使用通用类(基于模式的风格) 或者在普通类中 以 @AspectJ 注解来实现。
//切面
切点 + 增强
切面是一种描述, 描述了这样一件事: 一个 [什么样的增强功能] 添加在了 [哪些切点的] [什么位置]上
切面就是描述的切点方法和增强方法的执行顺序
4.SpringAOP配置详解
4.1切点表达式
切点表达式的作用: 定义一组规则, 用于在连接点中挑选切点
4.2Springd的通知
(1) 前置通知(Before advice):在某连接点(join point)之前执行的通知,但这 个通知不能阻止连接点前的执行(除非它抛出一个异常)。
(2) 后置通知(After-returning advice):在某连接点(join point)正常完成后 执行的通知:例如,一个方法没有抛出任何异常,正常返回。
(3) 抛出异常后通知(After-throwing advice):在方法抛出异常退出时执行的通知。
(4) 最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是 正常返回还是异常退出)。
- 当四大通知同时出现的时候, 它的执行顺序会受到配置顺序的影响
(5) 环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法 调用。这是最强大的一种通知类型。他允许你以编码的形式实现四大通知。 环绕通知可以在方法调用前后完成自定义的行为。它 也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。 环绕 通知是最常用的一种通知类型。大部分基于拦截的 AOP 框架,例如 Nanning 和 JBoss4, 都只提供环绕通知。
5.AOP工作原理
开发阶段(开发者完成)
开发共性功能,制作成增强
开发非共性功能,制作成切点
在配置文件中,声明切点与增强间的关系,即切面容器启动阶段(AOP完成)
Spring读取配置文件中的切面信息,根据切面中的描述, 将[增强功能]增加在[目标对象的切点方法]上,动态创建代理对象, 最后将代理对象放入容器中
正向 : 1) 日志处理 2) 事务 3) 性能统计
反向:新员工代码性能测试
6.JdbcTemplate介绍
JdbcTemplate是Spring提供的持久层技术,用于操作数据库,它底层封装了JDBC技术。
核心类:
- JdbcTemplate 用于执行增删改查的SQL语句 (QueryRunner)
- RowMapper 这是一个接口,主要作用是将数据库返回的记录封装进实体对象(ResultHandler)
核心方法:
- update() 用来执行增、删、改语句
- query() 用来执行查询语句
7.Spring中事务管理
7.1 事务管理方式
Spring支持两种事务管理方式:编程式事务和声明式事务
- 编程式事务就是将业务代码和事务代码放在一起书写,它的耦合性太高,开发中不使用
- 声明式事务其实就是将事务代码和业务代码隔离开发,然后通过一段配置让他们组装运行,最后达到事务控制的目的
声明式事务就是通过AOP原理实现的
7.2 Spring事务管理相关的API
7.2.1 PlatformTransactionManager
PlatformTransactionManager这是Spring进行事务管理的一个根接口,我们要使用它的实现类做事务管理
我们需要知道的是:mybatis和jdbcTemplate都可以使用它的一个子类(DataSourceTransactionManager)做事务管理
7.2.2 TransactionDefinition
TransactionDefinition这个API是用来做事务定义的
7.2.2.1 隔离级别
7.2.2.2 传播行为
事务传播行为指的就是当一个业务方法【被】另一个业务方法调用时,应该如何进行事务控制
- a(){
b();// b必须有事务才可以运行
}
b(){}
7.2.2.3 只读性
只读事务(增 删 改不能使用,只能查询使用)
换句话说,只读事务只能用于查询方法
7.2.2.4 超时时长
事务超时时间, 此属性需要底层数据库的支持
它的默认值是-1, 代表不限制
7.2.3 TransactionStatus
TransactionStatus代表的是事务的当前状态
- 三个API之间的关系
PlatformTransactionManager通过读取TransactionDefinition中定义事务信息参数,来管理事务,管理之后会产生一些列的TransactionStatus
8.注解
@Aspect//这个注解表明这是一个切面
@Pointcut("execution(* com.itheima.service.impl..(..))") //定义切点表达式
@Before("pt()")//代表的是当前的增强方法在pt()挑选出来的切点前面执行
@Around("execution(* com.itheima.service.impl..(..))")
aop:aspectj-autoproxy (xml)//激活切面自动代理
tx:annotation-driven (xml)//开启注解驱动
@Transactional //次注解可以表示在类上,也可以表示在方法上,表示当前类中的方法具有事务管理功能
//并且这个注解标在方法上的优先级会高于标在类上@EnableTransactionManagement (xml)//相当于 开启注解驱动 : tx:annotation-driven