AOP——面向切面编程
在软件工程方面有一个重要的概念:
即关注点分离:不同的问题交给不同的部分去解决。
AOP就是一种关注点分离的技术,比如我们在写一个Javaweb,需要写缓存,业务逻辑,日志,出错处理等等东西都要混在一起,于是为了将业务的各个功能分离开,就有了所谓的切面(Aspect)。当业务功能代码和切面代码分开之后,架构就会变得高内聚低耦合。
但是在这个基础上,我们又知道,如果模块化之后,虽然模块本身的成本降低了,但是接口的开发的成本又升高了,我们为了保证业务的完整性,就需要使用切面,将业务去进行合并。
AOP一共有三种置入的方式:
- 编译的时候置入:需要特殊的Java编译器,如AspectJ
- 类加载的时候置入:需要特殊的Java编译器,如AspectJ和AspectWerkz
- 运行的时候置入:Spring常规的时候采用的方式,基于动态代理,实现简单。
比如下面的案例:
- 我们首先用@Aspect创建一个切面,然后用@Component加入进切面
- 分别使用@PointCut,@Before,@AfterReturning定义针对切面要做的事情与配置
接下来再来介绍几个AOP相关的主要名词概念:
- Aspect:通用功能的代码实现
- Target:被织入Aspect的对象
- Join Point:可以作为切入点的机会,所有方法都可以作为切入点
- Pointcut:Aspect实际被应用在的JoinPoint,支持正则
- Asvice:类里的方法以及这个方法如何织入到目标方法的方式
- Weaving:Aop的实现过程
AOP的实现:JdkProxy与Cglib
具体使用哪种方式去实现,由AopProxyFactory根据AdvisedSupport对象的配置去决定,
默认的策略是如果目标类是接口,就使用JDKProxy来实现,否则用后者。
JDKProxy底层是使用的JDK的反射也就是利用了InvocationHandler接口和Proxy类来实现的。
如果不是接口,就默认使用Cglib,底层原理是ASM字节码框架,用继承的方式动态生成目标类的代理。
从性能角度来说,ASM在生成类之后的执行过程中比较高效,而反射机制在生成了类过程中比较高效。
在Spring中,真实实现类的逻辑都包含在了getBean里,而getBean方法返回的实际上就是Proxy的实例,而Proxy的实例是Spring采用JDK Proxy或者Cglib动态生成的。