参考博客: www.jianshu.com/p/994027425… ,个人感觉比spring实战里面要讲的好(例子举得更真实),可以看了这个再结合spring实战的AOP看。
1.什么是AOP?
面向切面编程(Aspect Oriented Programming),个人裂解面向切面编程和IOC都是一种思想。如博客链接所述,AOP的思想是将业务的核心功能和周边功能分开。 核心功能:对数据库的增删改查都属于核心功能 周边功能:性能统计、日志、事务管理 在AOP的思想中,周边功能即切面。切面和核心功能分开开发,定义为“编织”(Weaving)
2.AOP的目的
封装与业务无关,但是为业务模块所公共调用的的模块(事务处理、日志等)。减少代码量,降低耦合度,提高可维护性和可拓展性。 AOP中的概念: 1)切入点(Pointcut) Where:在什么地方做 2)通知(Advice) When+What:在什么时机做什么 3)切面(Aspect) 切入点+通知:什么时机在什么地方做什么 4)织入(Weaving) 把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)
3.实战AOP demo:
以博客上的租房案例为准,这里再整理一下。 加入包租婆(landlord)想要通过中介把自己的房子租出去,当别人需要租这间房的时候,整体的happy path业务流程如下:
1)找到中介->2)中介带领看房->3)中介谈价格->4)包租婆来签合同->5)包租婆收房租->6)中介交钥匙
很明显,对于包租婆来说,只有4)和5)需要她参与,站在她的角度,这两个环节才是核心业务,而和中介相关的2)->3)->6)都属于政哥happy path的周边业务。这个业务理理清楚之后,开始demo。
3.1首先引包:
implementation 'org.springframework:spring-aspects:5.3.13'
复制代码
3.2创建package pojo->创建Landlord类
@Component
public class Landlord {
public void service() {
//包租婆:只有核心代码
System.out.println("签合同");
System.out.println("收房租");
}
}
复制代码
创建中介类package aspect->Broker
@Aspect
@Component
public class Broker {
//这个broker就是一个通知advice,专注于非核心业务代码
//为避免每一个方法上面写全路径名,专门定义一个方法来放切入点(pointcut)
@Pointcut("execution(* com.springaopdemo.pojo.Landlord.service())")
public void brokerService() {
}
@Before("brokerService()")
public void before() {
//非核心功能-业务之前
System.out.println("看租客房子");
System.out.println("谈价格");
}
@After("brokerService()")
public void after() {
//非核心功能-业务之后
System.out.println("交钥匙");
}
}
复制代码
可以看出切点的编写规则: execution (* 路径.执行方法名)
*excution定义在方法名上,方法执行时触发;代表返回任意类;后面跟方法所属类的路径.方法名(参数)
在启动类上开启扫描
@SpringBootApplication
@ComponentScan({"com.springaopdemo.aspect","com.springaopdemo.pojo"})
public class SpringAoPdemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringAoPdemoApplication.class, args);
}
}
复制代码
通过xml文件对bean进行装配,创建如下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:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.springaopdemo.aspect" />
<context:component-scan base-package="com.springaopdemo.pojo" />
<aop:aspectj-autoproxy/>
</beans>
复制代码
测试:
@SpringBootTest
public class LandlordTest {
@Test
public void should_get_information_from_test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Landlord landlord = context.getBean(Landlord.class);
landlord.service();
}
}
复制代码
运行,输出结果如下:
看租客房子
谈价格
签合同
收房租
交钥匙
复制代码
4.编写规则
除了上面使用的Before,After之外,还有3种:
AspectJ注解声明通知方法 | |
---|---|
@After | 在目标方法放回or抛出异常后调用 |
@Before | 在目标方法调用之前执行 |
@Around | 通知方法会把目标方法封装起来,达到@After和@Before结合的效果 |
@AfterReturning | 方法会在目标方法返回后调用 |
@AfterThrowing | 方法会在目标方法抛出异常后调用 |
5.实战AOP demo_2:
demo2使用@Around注解通过环绕方法来进行通知设计
@Around("brokerService()")
public void around(ProceedingJoinPoint joinPoint) {
System.out.println("租客看房子");
System.out.println("谈价格");
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("交钥匙");
}
复制代码
输出结果:
租客看房子
谈价格
签合同
收房租
交钥匙
复制代码
最后总结一下,在这个demo中,谁是通知advice?谁是切点joinpiont? 通知就是broker的每个方法,切点就是路径对应的方法,二者加起来就是一个切面。 这里是一个简单的AOP的deom,现实的项目中我们可能用的比较多的就是用来打日志。