AOP介绍
AOP是面向切面编程,是OOP的延续,就是对纵向代码的横向扩展,把每个方法中共同的部分提取出来就叫做切面。
切面:切面就是切点和通知
切点:切面要切入(管理)的地方
通知:切面要执行的操作(前置通知,返回通知,异常通知,后置通知,最终通知,环绕通知)
切点表达式(execution)
execution(修饰符 返回值 包名称.类名称.方法名称(参数列表))
execution(public void com.apesource.service.ServiceImp.findAll())
- 修饰符可以省略代表任意
execution(返回值 包名称.类名称.方法名称(参数列表))
- 返回值可以使用 * 代表任意返回值
execution(* 包名称.类名称.方法名称(参数列表))
- 包名可以使用 * 代表任意包名称
execution(* *.*.*.类名称.方法名称(参数列表))
- 包名可以使用 .. 代表任意层包
execution(* *...类名称.方法名称(参数列表))
- 类名与方法名可以使用 * 代表任意
execution(* *...*.*(参数列表))
- 参数列表可以使用 .. 代表任意个数任意类型
execution(* *...*.*(..))
如果有参数
int======>int
String===>java.lang.String
需求说明
统计学生业务类中每个方法的执行时间并且输出
注:例子只会写出环绕通知!!!
xml方式配置
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注入IOC-->
<bean id="service" class="com.ape.service.StudentServiceImpl"/>
<bean id="advice" class="com.ape.advice.StudentAdvice"/>
<!-- 配置AOP-->
<aop:config>
<!-- 配置切面-->
<aop:aspect id="studentAdvice" ref="advice">
<aop:pointcut id="point" expression="execution(void com.ape.service.*.*(..))"/>
<aop:around method="around" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
<aop:aspectj-autoproxy/>
</beans>
业务接口
package com.ape.service;
public interface StudentService {
/**
* 增删改方法
*/
void insert();
void update();
void delete();
}
接口实现类
package com.ape.service;
import org.springframework.stereotype.Service;
public class StudentServiceImpl implements StudentService {
/**
* 需求:计算每次每个方法的执行时间
* 原始写法在每个方法开始时候获取时间戳,结束后再获取,然后相减
* 缺点:
* 1.冗余代码多,一万个方法就要写一万个获取时间相减操作
* 2.侵入源码
* @return
*/
@Override
public void insert() {
System.out.println("执行insert方法");
// int a = 10/0; //异常开关
}
@Override
public void update() {
System.out.println("执行update方法");
}
@Override
public void delete() {
System.out.println("执行delete方法");
}
}
AOP
package com.ape.advice;
import org.aspectj.lang.ProceedingJoinPoint;
public class StudentAdvice {
public Object around(ProceedingJoinPoint pjp) {
Object res = null;
try {
System.out.println("前置通知");
Object[] args = pjp.getArgs();
res = pjp.proceed(args);
System.out.println("返回通知");
System.out.println("后置通知");
} catch (Throwable e) {
e.printStackTrace();
System.out.println("异常通知");
} finally {
System.out.println("最终通知");
}
return res;
}
}
纯注解实现
配置类
package com.ape.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan(basePackages = "com.ape")
@EnableAspectJAutoProxy // 应用自动切面代理
public class ApplicationContext {
}
业务接口
package com.ape.service;
public interface StudentService {
/**
* 增删改方法
*/
void insert();
void update();
void delete();
}
接口实现类
package com.ape.service;
import org.springframework.stereotype.Service;
@Service(value = "studentServiceImpl")
public class StudentServiceImpl implements StudentService {
/**
* 需求:计算每次每个方法的执行时间
* 原始写法在每个方法开始时候获取时间戳,结束后再获取,然后相减
* 缺点:1.冗余代码多,一万个方法就要写一万个获取时间相减操作
* 2.侵入源码
* @return
*/
@Override
public void insert() {
System.out.println("执行insert方法");
// int a = 10/0; // bug开关
}
@Override
public void update() {
System.out.println("执行update方法");
}
@Override
public void delete() {
System.out.println("执行delete方法");
}
}
AOP
package com.ape.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect // 定义切面 切面=切点(切面切入的地方)+通知(切面要执行的方法)
@Component
public class CurrentTimeAdvice {
// 定义切点
@Pointcut("execution(void com.ape.service.*.*(..))")
public void pointCut() {
}
// 使用环绕通知 (可以代替 前置 返回 异常 后置)
@Around("pointCut()")
public Object aroundMethod(ProceedingJoinPoint pjp) {
long start = 0;
Object obj = null;
try {
// 前置
System.out.println("前置方法");
start = System.currentTimeMillis();
// 如果有参数
Object[] args = pjp.getArgs();
obj = pjp.proceed(args);
// 后置通知
long end = System.currentTimeMillis();
long res = (end - start);
System.out.println(res + "ms");
} catch (Throwable e) {
e.printStackTrace();
// 异常通知
System.out.println("有异常了");
} finally {
System.out.println("最终通知");
}
return obj;
}
}