第三章 AOP面向切面编程
程序员文章站
2022-06-25 11:20:27
第三章 AOP 面向切面编程3.1 动态代理3.2 AOP 概述3.3 AOP 简介3.4 AOP 编程术语3.1 动态代理可以在程序的执行过程中,创建代理对象。通过代理对象执行方法,给目标类增加额外的功能而不改变原来类中的代码(功能增强)1、JDK 动态代理:要求目标对象必须实现接口,通过 java.lang.reflect 包提供三个类支持代理模式 Proxy、Method 和 InvocationHandler 。实现步骤:1)创建目标类(如果目标类已经存在,此步骤可以省略)2)创...
第三章 AOP 面向切面编程
3.1 动态代理
3.2 AOP 概述
3.3 AOP 编程术语
3.4 AOP 的实现
3.1 动态代理
可以在程序的执行过程中,创建代理对象。通过代理对象执行方法,给目标类增加额外的功能而不改变原来类中的代码(功能增强),在一定程度上减少代码重复。
1、JDK 动态代理:要求目标对象必须实现接口,通过 java.lang.reflect 包提供三个类支持代理模式 Proxy、Method 和 InvocationHandler 。
实现步骤:
1)创建目标类(如果目标类已经存在,此步骤可以省略)
SomeService,SomeServiceImpl(目标类,实现 SomeService 接口)
2)创建 InvocationHandler 接口的实现类,在这个类实现给目标方法增加功能
public class MyInvocationHandler implements InvocationHandler {
// 目标对象
private Object target;
public MyInvocationHandler (Object target) {
this.target = target;
}
// 通过代理对象执行方法时,会调用这个invoke()
// 在这个方法里添加需要增加的功能
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = null;
// 可以在目标方法前添加
// xxxx 要增加的功能
// 执行目标类的方法,通过 Method 类实现
res = method.invoke(target,args);
// 也可以在目标方法后添加
// xxxx 要增加的功能
return res;
}
}
3)使用 jdk 中的类 Proxy 创建代理对象,实现创建对象的能力
// 创建目标对象
SomeService target = new SomeServiceImpl();
// 创建 InvocationHandler 对象
InvocationHandler handler = new MyInvocationHandler(target );
// 使用 Proxy 创建代理
SomeService proxy = (SomeService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);
// 通过代理执行方法,会调用 handler 中的 invoke()
// doSome() 是 SomeService 中的方法,在 SomeServiceImpl 中被实现
proxy.doSome();
2、CGLIB 动态代理:第三方工具库,创建代理对象。原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象,所以要求目标类必须能够被继承,即不能是 final 类。
3.2 AOP 概述
1、Aop是什么?
Aop 是基于动态代理,可以使用 jkd,cglib 两种代理方式。Aop 就是动态代理的规范化,把动态代理的实现步骤、方式都定义好了,让开发人员用一种统一的方式去使用动态代理。
2、怎么理解面向切面编程
AOP(Aspect Orient Programming)
Aspect :切面,给目标类增加的功能就是切面,比如日志、事务、统计信息、参数检查、权限限定都是切面。切面一般都是非业务方法,独立使用。
Orient :面向
Programming:编程
1)在分析项目功能时,需要找出切面
2)合理的安排切面的执行时间(在目标方法前还是目标方法后)
3)合理的安排切面的执行位置(在哪个类,在哪个方法)
3.3 AOP 编程术语
1)Aspect
2)JoinPoint:连接点,程序执行的某一个特定位置,如类初始前后,方法的运行前后,而 Spring 只支持方法的连接点
3)Pointcut:切入点,切点是匹配了一个或多个连接点。定义了切面在何处执行,切点的前提也是一个连接点,它是连接点的一个子集
4)Advice:通知,定义了切面是什么以及何时使用,Spring 中的通知有以下5种:
前置通知(before):在目标方法执行之前执行的通知
后置通知(after):在目标方法执行之后执行的通知,此时不关心方法是否成功执行
返回通知(after-returning):在目标方法成功执行之后执行的通知
异常通知(after-throwing):在目标方法抛出异常之后执行的通知
环绕通知(around):通知包含了目标方法,可以在目标方法执行之前和执行之后执行自定义的行为。
以上五种分别对应 AspectJ 中的通知注解:@Before、@After、@AfterRunning、@AfterThrowing、@Around
5)Target:目标对象,给哪个类的方法增加功能,这个类就是目标对象
3.4 AOP 的实现
spring:spring 在内部实现了 aop 规范,能完成 aop 的工作,主要在事务处理时使用 aop,但我们在项目开发中很少使用 spring 框架中的 aop,因为其比较笨重。
aspectJ:是一个开源专门做 aop 的框架,spring 的框架中集成了 aspectJ 框架,有两种使用方式:
1)xml 配置文件:配置全局事务
2)注解:通常使用此种方式实现
使用 aspectJ 实现 aop 的基本步骤:
1)新建 maven 项目
2)添加 spring 和 aspectJ 依赖
3)创建目标类:接口和它的实现类
4)创建切面类:普通类
在类的上面加入 @Aspect;在类中定义方法,方法就是切面要执行的功能代码;在方法上面加入 AspectJ 中的通知注解;指定切入点表达式 execution()
5)创建 spring 的配置文件:声明对象,把对象交给容器统一管理
a、声明目标类对象
b、声明切面类对象
c、声明 aspect 框架中的自动代理生成器(用来完成代理对象的自动创建功能)标签,以下使用 Proxy 创建代理这步就可省略
6)从 spring 容器中获取目标对象(实际就是代理对象),通过代理执行方法,实现 aop 的功能增强
// spring 依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
// aspectj 依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
/*
* @Aspect :是 Aspectj 框架中的注解
* 作用:表示当前类是切面类
* 切面类:用来给业务方法增加功能的类
* 位置:定义在类的上面
*/
@Aspect
public class MyAspect {
/*
* 定义方法,用来实现切面功能
* 方法的定义要求:
* 1、必须是公共方法(public)
* 2、方法没有返回值(void)
* 3、方法的名称自定义
* 4、方法可以有参数也可以没有参数
*/
/*
* 此处以 @Before 注解为例
* 位置:定义在方法上面
* 特点:
* 1、在目标方法之前执行
* 2、不会改变目标方法的执行结果
* 3、不会影响目标方法的执行
*/
@Before(value="execution(public void 包名.类名.方法名(参数) 异常)")
public void myBefore() {
}
}
// 声明目标对象
<bean id="someService" class="xxx" />
// 声明切面对象
<bean id="myAspect" class="xxx" />
/* 声明自动代理生成器:使用 aspectj 框架内部的功能,创建目标对象的代理对象
* 创建代理对象是在内存中实现的,修改目标对象在内存中的结构,创建为代理对象,
* 所以目标对象就是被修改后的代理对象
*/
// aspectj-autoproxy 会把 spring 容器中的所有目标对象一次性都生成代理对象
<aop:aspectj-autoproxy />
// 以下这步可以省略
// 使用 Proxy 创建代理
SomeService proxy = (SomeService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);
本文地址:https://blog.csdn.net/qq_39171225/article/details/109517124