您的位置:首页 > 编程语言 > Java开发

Spring 核心技术 AOP 实例

antoniopeng 2021-01-13 22:35 10 查看 https://www.cnblogs.com/antoni

AOP 简介

Aop(Aspect Oriented Programming),面向切面编程,这是对面向对象思想的一种补充。

面向切面编程,就是在程序运行时,不改变程序源码的情况下,动态的增强方法的功能,常见的使用场景非常多:

  1. 日志
  2. 事务
  3. 数据库操作
  4. ....

这些操作中,无一例外,都有很多模板化的代码,而解决模板化代码,消除臃肿就是 Aop 的强项。在 Aop 中,有几个常见的概念:

概念 说明
切点 要添加代码的地方,称作切点
通知(增强) 通知就是向切点动态添加的代码
切面 切点 + 通知
连接点 切点的定义

AOP 的实现

在 Aop 实际上集基于 Java 动态代理来实现的。Java 中的动态代理有两种实现方式:

  • cglib
  • jdk

动态代理

基于 JDK 的动态代理实例。

1. 定义一个计算器接口

public interface MyCalculator {

int add(int a, int b);
}

2. 定义计算机接口的实现

public class MyCalculatorImpl implements MyCalculator {

public int add(int a, int b) {
return a + b;
}
}

3. 定义代理类

public class CalculatorProxy {

public static Object getInstance(final MyCalculatorImpl myCalculator) {
return Proxy.newProxyInstance(CalculatorProxy.class.getClassLoader(), myCalculator.getClass().getInterfaces(), new InvocationHandler() {

/**
* @param proxy 代理对象
* @param method 代理的方法
* @param args 方法的参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName()+"方法开始执行啦...");
Object invoke = method.invoke(myCalculator, args);
System.out.println(method.getName()+"方法执行结束啦...");
return invoke;
}
});
}
}

Proxy.newProxyInstance 方法接收三个参数,第一个是一个 classloader,第二个是代理多项实现的接口,第三个是代理对象方法的处理器,所有要额外添加的行为都在 invoke 方法中实现。

XML 配置 AOP

1. 在 pom.xml 中引入 Spring 和 AOP 相关依赖

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>

<!-- AOP Begin -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.5</version>
</dependency>
<!-- AOP Over -->

2. 接下来,定义通知/增强,但是单纯定义自己的行为即可,不再需要注解

public class LogAspect {

public void before(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println(name + "方法开始执行了...");
}

public void after(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println(name + "方法执行结束了...");
}

public void returing(JoinPoint joinPoint,Integer r) {
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println(name + "方法返回:"+r);
}

public void afterThrowing(JoinPoint joinPoint,Exception e) {
Signature signature = joinPoint.getSignature();
String name = signature.getName();
System.out.println(name + "方法抛异常了:"+e.getMessage());
}

public Object around(ProceedingJoinPoint pjp) {
Object proceed = null;
try {
//这个相当于 method.invoke 方法,我们可以在这个方法的前后分别添加日志,就相当于是前置/后置通知
proceed = pjp.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return proceed;
}
}

3. 接下来在 Spring 中配置 AOP

<bean class="com.antoniopeng.hello.spring.aop.LogAspect" id="logAspect"/>
<aop:config>
<aop:pointcut id="pc1" expression="execution(* com.antoniopeng.hello.spring.aop.commons.*.*(..))"/>

<aop:aspect ref="logAspect">
<aop:before method="before" pointcut-ref="pc1"/>
<aop:after method="after" pointcut-ref="pc1"/>
<aop:after-returning method="returing" pointcut-ref="pc1" returning="r"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pc1" throwing="e"/>
<aop:around method="around" pointcut-ref="pc1"/>
</aop:aspect>
</aop:config>

4. 最后,在 Main 方法中加载配置文件

public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
MyCalculatorImpl myCalculator = ctx.getBean(MyCalculatorImpl.class);
myCalculator.add(3, 4);
myCalculator.min(5, 6);
}
}

本文发于:https://antoniopeng.com

标签: