1、编程方式
POP 面向过程编程
面向过程编程(Procedure Oriented Programming)是以功能为中心来进行思考和组织的一种编程方法,它强调的是系统的数据被加工和处理的过程,在程序设计中主要以函数或者过程为程序的基本组织方式,系统功能是由一组相关的过程和函数序列构成。
OOP 面向对象编程
面向对象编程(Object Oriented Programming)依然保留着面向过程的特性,面向过程中的功能变成了对象的方法,业务逻辑功能变成了对象的方法,而这部分方法依然需要提供获取操作,同时也对提供写入操作,只是获取与写入也变成了对象。
AOP 面向切面编程
面向切面编程(Aspect Oriented Programming)是对于 OOP 的补充和完善。OOP 引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP 则显得无能为力。也就是说,OOP 允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在 OOP 设计中,它导致了大量代码的重复,而不利于各个模块的重用。
2、代理模式
代理是设计模式的一种,代理类为委托类提供消息预处理,消息转发,事后消息处理等功能。
静态代理
Java 中的静态代理要求代理类和委托类都实现同一个接口。静态代理中代理类在编译期就已
经确定,而动态代理则是 JVM 运行时动态生成,静态代理的效率相对动态代理来说相对高一些,
但是静态代理代码冗余大,一旦需要修改接口,代理类和委托类都需要修改。
动态代理
Java 中的动态代理依靠反射来实现,代理类和委托类不需要实现同一个接口。委托类需要实
现接口,否则无法创建动态代理。代理类在 JVM 运行时动态生成,而不是编译期就能确定。
1、JDK代理
在程序运行的过程中通过java反射机制生成动态代理类,并实现委托类所实现的接口。
2、CGLIB代理
在程序运行的过程中通过ASM字节码修改(类装载机制:class文件不能修改,但cglib可以)
3、代理切换
aop采用动态代理默认值 采用jdk代理
aop设置动态代理为cglib代理 采用cglib代理
aop设置动态代理为jdk代理,但委托未实现接口 自动切换至cglib代理
3、实现方式
在配置之前需要先在pom.xml中引入maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>版本号</version>
</dependency>
1、基于配置
<!-- 配置扫描 -->
<context:compoent-scan base-package="com.zhang.spring"/>
<!-- Aop动态代理 -->
<aop:comfig>
<!--声明aop切面-->
<aop:aspect ref="需要执行的类,首字母小写">
<!--声明切入点匹配类型方法-->
<aop:pointcut id="methodPointcut" expression="execution(返回值类型 项目名+模块名+接口/方法名+参数类型)"/>
<!--例如:execution(* com.zhang.spring.aop.service.AopService.query(String,int))-->
<!--绑定执行方法名称及切入点类型-->
<aop:after method="需要执行的方法" pointcut-ref="methodPointcut"/>
</aop:aspect>
</aop:comfig>
2、基于注解
<!--配置扫描范围,扫描范围内的所有注解(@Controller、@Service、@Repository、@Component)-->
<context:component-scan base-package="com.zhang.spring:/>
<!--启用aop注解支持-->
<aop:aspectj-autoproxy/>
//声明切面
@Aspect
//添加注解,实例化此类
@Component
public void AnnotationText{
//声明切入点,拦截service下所有的所有(任意返回值,任意参数个数及类型,任意名称)方法
@Pointcut("execution(* com.zhang.service.*(..))")
public void methodPointCut(){}
//绑定拦截后方法(可以是其他)
@After("methodPointCut()")
public void method(){
System.out.print("hello word");
}
}
4、通知指示符
1、通知类型
1、before前置通知
在拦截方法之前执行,与程序是否异常无关
2、after-returning成功通知
在拦截方法执行成功后通知
3、after-trhowing异常通知
在拦截方法抛出异常后通知
4、after结束通知
在拦截方法执行结束后通知,无论程序是否执行成功
5、around环绕通知
在拦截方法执行前后均执行。前置工作完成后需要放行,拦截方法返回值需要return
2、通配符
* 匹配任意数量的字符,可以代表任意类型的返回值,模块名、类名、方法名。
<aop:pointcut id="method" expression="execution(* com.zhang.spring.*.service.impl.*.*())"/>
+ 匹配所有目标的子类
<aop:pointcut id="method" expression="within(com.javakc.zhang.aop.service.AopService+)"/>
.. 匹配任意包数量,任意参数类型及数量
execution
用于匹配执行方法的连接点
<aop:pointcut id="method" expression="execution(* com.zhang.spring.*.service.impl.*.*(..))"/>
within
within比较严格,他是严格匹配被代理对象类型的,不会理会继承关系。
<aop:pointcut id="method" expression="within(com.zhang.spring.aop.service.AopService+)"/>
this
匹配当前aop代理对象的执行方法,注意是aop代理对象的类型匹配,这样就可能包括引入接口方法也可以匹配。注意this中使用的表达式必须是类型全限定名,不支持通配符。
<aop:pointcut id="method" expression="this(com.zhang.spring.aop.service.AopService)"/>
target
匹配当前目标对象类型的执行方法,注意是目标对象类型匹配,这样就不包括引入接口也类型匹配。注意target中使用的表达式必须是类型全限定名,不支持通配符。
<aop:pointcut id="method" expression="target(com.zhang.spring.aop.service.AopService)"/>
args
匹配当前执行方法传入的参数类型为指定类型的执行方法,不支持通配符,开销非常大。
<aop:pointcut id="method" expression="args(String, ..)"/>
5、常用注解
@Aspect | 声明切面 |
@Order | 多个切面见排序,数字越小优先级越高 |
@Pointcut | 声明切入点,定义拦截规则,用于获取需要通知实现的方法 |
@Before | 在目标方法执行之前执行执行的通知 |
@After | 在目标方法执行之后执行的通知 |
@AfterThrowing | 在目标方法抛出异常时执行的通知 |
@AfterReturning | 是在目标方法执行之后执行的通知 |
@Around | 在目标方法执行之前和之后都可以执行额外代码的通知 |