代理是一个设计模式,提供了对目标对象另外的访问方式;即通过代理访问目标对象。
好处:可以在目标对象实现的基础上,增强额外的功能操作。
Cglib 代理,也叫作 子类代理。
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB 实现。
CGLIB 是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java 接口。它广泛的被许多AOP的框架使用,例如 SpringAOP 和dynaop,为他们提供方法的 interception (拦截)
CGLIB 包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。
cglib 子类代理
1) 需要引入 cglib.jar 文件,不过spring 的核心包中已经包含了cglib 功能,只需要引入 spring-core*
2)引入功能包后,就可以在内存中动态构建子类
3) 代理的类不能是 final,否则报错
4) 目标对象的方法如果为 final/static ,那么就不会被拦截,即不会执行目标对象额外的业务方法
在Spring的AOP 编程中
如果加入容器的目标对象有实现接口,用JDK 代理
如果目标对象没有实现接口,用CGLIB 代理
AOP 面向切面的编程
AOP 可以实现“业务代码” 与 “关注点代码” 分离
//保存一个用户 public void add(User user) { Session session = null; Transaction trans = null; try { session = HibernateSessionFactoryUtils.getSession(); //【关注点代码】 trans = session.beginTranstaion(); //【关注点代码】 session.save(user);//【核心业务代码】 trans.commit();//【关注点代码】 }catch(Exception e) { e.printStackTrace(); if(trans != null) { trans.rollback();//【关注点代码】 } }finally { HibernateSessionFactoryUtils.closeSession(session);//【关注点代码】 } }
分析总结:
关注点代码,就是指重复执行的代码
业务代码与关注点代码分离的好处
关注点代码写一次即可
可发者只需要关注核心业务
运行期间,执行核心业务代码时候动态植入关注点代码【代理】
如何分离?
过程式/对象式/代理模式分离
AOP 概念
AOP aspect object programming 面向切面编程
功能:让关注点和业务代码分离
关注点: 重复代码就叫作关注点
切面:关注点形成的类,就叫作切面
面向切面编程,就是指 对很多功能都有重复的代码抽取,再在运行的时候 往 业务方法上动态植入“切面类代码”
切入点: 执行目标对象方法,动态植入切面代码
可以通过切入点表达式,指定拦截哪些类的哪些方法,给指定的类在运行的时候植入切面类代码
方面(Aspect) 一个关注点的模块化,这个关注点实现可能另外横切多个对象。方面用spring的Advisor 或 拦截器实现
连接点(Joinpoint) :程序执行过程中明确的点,如方法的调用或特定的异常被抛出
通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”,“before”,“throws”通知。以拦截器做通知模型,维护一个“围绕”连接点的拦截器链
切入点(Pointcut):指定一个通知将引发一系列连接点的集合。AOP框架必须允许开发者指定切入点(例如使用正则表达式)
引入(Introduction): 添加方法或字段到被通知的类。Spring 允许引入新的接口道任何被通知的对象。
目标对象(Target Object):包含连接点的对象,也被称作被通知或被代理对象
AOP代理(AOP Proxy):AOP 框架创建的对象,包含通知。在Spring中,AOP代理可以是Java代理 和 CGLIB 代理
编织(Weaving) : 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
注解方式实现AOP编程
步骤:
1)先引入aop 相关jar 文件
spring-aop-*.jar aopalliance.jar aspectjweaver.jar aspectjrt.jar
2) bean.xml 引入aop 名称空间
3) 开启aop 注解
4) 使用注解
@Aspect 指定一个类为切面类
@Pointcut("execution(* com.panie.example.*.*(..))") 指定切入点表达式
@Before("pointcut()") 前置通知:目标方法之前执行
@After("pointcut()") 后置通知:目标方法之后执行
@AfterReturining("pointcut()") 返回后通知:执行方法结束前执行(异常不执行)
@AfterThrowing("pointcut()") 异常通知:出现异常时候执行
@Around("pointcut()") 环绕通知:环绕目标方法执行