1、动态代理
动态代理是指,程序在整个运行过程中根本不存在目标类的代理类,目标的代理对象只是有代理生成工具(不是真实定义的类)在程序运行时有JVM根据反射等机制动态生成的。代理对象与目标对象的代理关系在程序运行时才确立。
1.1、JDK动态代理
动态代理的实现方式常用的有两种:使用JDK的Proxy,与通过CGLIB生成代理。
jdk的动态要求目标对象必须实现接口,这是java设计上的要求。从jdk1.3以来,java语言通过java.lang.reflect包提供三个类支持代理模式Proxy、Method和InovationHandler。
1.2、CGLIB动态代理
CGLIB(Code Generation Library)是一个开源项目。是一个强大的、高性能、高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。它广泛地被许多AOP的框架使用,例如SpringAOP。
使用JDK的Proxy实现代理,要求目标类与代理类实现相同的接口。若目标类不存在接口,则无法使用该方式实现。但对于无接口的类,要为其创建动态代理,就要使用CGLIB来实现。
CGLIB代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。所以,使用CGLIB生成动态代理,要求目标类必须能够被继承,即不能是final的类。
CGLIB经常应用在框架中,例如Spring、Hibernate等。CGLIB的代理效率高于JDK。项目中直接使用动态代理的地方不多。一般都是用框架提供的功能。
2、AOP(Aspect Orient Programming)
面向切面编程,基于动态代理,可以使用jdk,oglib两种代理方式。
AOP就是动态代理的规范化,把动态代理的实现步骤、方式都定义好了,让开发人员用一种统一的方式,就用动态代理。
Aspect:切面,给你的目标类增加的功能就是切面。切面一般都是非业务方法,是独立使用的。
Orient:面向,对着
Programming:编程
一、怎么理解面向切面编程?
1、需要在分析项目功能时,找出切面
2、合理地安排切面的执行时间(在目标方法钱,还是目标方法后)
3、合理地安排切面执行的位置,在哪个类,哪个方法增加增强功能
二、术语:
1)Aspect:切面,表示增强的功能,就是一堆代码,完成某个功能,非业务功能,常见的切面功能有日志、事务、统计数据、参数检查、权限验证。
2)JoinPoint:连接点,连接业务方法和切面的位置。就某类中的业务方法。
3)Pointcut:切入点,指多个连接点方法的集合,多个方法。
4)目标对象:给哪个类的方法增加功能,这个类就是目标对象。
5)Adivice:通知,通知表示切面功能执行的时间。
三、说一个切面有三个关键的要素:
1)切面的功能代码,切面干什么
2)切面的执行位置,使用Pointcut表示切面执行的位置
3)切面的执行的时间,使用Advice表示时间,在目标代码之前,还是目标代码之后
四、AOP的实现
aop是一个规范,是动态的一个规范化,一个标准。aop的实现框架:
1、spring:spring在内部实现了aop规范,能做aop的工作。但是在spring主要在事务处理时使用aop,我们项目开发中很少使用spring的aop实现。因为aop比较笨重。
2、Aspectj:一个开源的专门做aop的框架。spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能。aspectj框架实现aop有两种方式:
1)使用xml的配置文件,配置全局事务。
2)使用注解,我们在项目中要做aop功能,一般都使用注解,aspectj有五个注解。
五、学习aspectj框架的使用
1、切面的执行时间,这个执行时间在规范中叫做Advice(通知,增强),在aspectj框架中使用注解表示的,也可以使用xml配置文件中的标签。
1)@Before
2)@AfterReturning
3)@Around
4)@AfterThrowing
5)@After
2、表示切面执行的位置,使用的是切入点语法表达式
AspectJ定义了专门的表达式用于指定切入点。表达式的原型是:
execution(modifiers-pattern? ret-type-pattern
declaring-type-pattern? name-pattern(param-pattern)
throws-pattern?)
解释:
- modifiers-pattern 访问权限类型
- ret-type-pattern 返回值类型
- name-pattern(param-pattern) 方法名(参数类型和参数个数)
- throws-pattern 抛出异常类型
- ?表示可选的部分
- 以上表达式供4个部分(访问权限 方法返回值 方法声明(参数) 异常类型)
切入点表达式要匹配的对象就是目标方法的方法名。所以,execution表达式中明显就是方法的签名。注意,表达式中的黑色文字表示可省略部分,各部分间用空格分开。在其中可以使用以下符号
符号 | 意义 |
* | 0至多个任意字符 |
.. |
用在方法参数中,表示多个参数 用在包名后,表示当前包及其子包路径 |
+ |
用在类名后,表示当前类及其子类 用在接口后,表示当前接口及其实现类 |
举例:
1、execution(public * *(..)) 指定切入点:任意公共方法。
2、execution(* set*(..)) 指定切入点:任何一个以“set”开始的方法
3、execution(* com.xyz.service.*.*(...)) 指定切入点:定义在service包里的任意类的任意方法。
4、execution(* com.xyz.service..*.*(..)) 指定所有包下的service子包下所有类(接口)中所有方法为切入点
5、execution(* *.service.*.*(..)) 指定只有一级包下的service子包下所有类(接口)中所有方法为切入点