我们在处理日志、安全、事务这些系统服务时,会把这些有着通用代码的服务称为 交叉业务,这些交叉业务有着两个主要问题
第一: 交叉业务代码在多个业务流程中反复出现,显然这个交叉业务代码没有得到复用。并且修改这些交叉业务代码的话,需要修改多处。
第二:程序员无法专注核心业务代码的编写,在编写核心业务代码的同时还需要处理这些交叉业务。
我们需要一种编程思想解决这个问题。AOP可以帮助我们很好的解决这类问题,保证程序不违反OCP开闭原则
AOP:第一:代码复用性增强
第二:代码易维护
第三:使开发者更关注业务逻辑
AOP七大术语
连接点Joinpoint
在程序的整个执行流程中,可以织入切面的位置。方法的执行前后,异常抛出之后等位置.
切点 Pointcut
在程序执行流程中,真正织入切面的方法。(一个切点对应多个连接点)
通知 Advice
通知又叫增强,就是具体你要织入的代码
通知包括:
前置通知
后置通知
环绕通知
异常通知
最终通知
切面Aspect
切点 + 通知就是切面。
织入 Weaving
把通知应用到目标对象上的过程。
代理对象 Proxy
一个目标对象被织入通知后产生的新对象。
目标对象 Target
被织入通知的对象
切点表达式
切点表达式用来定义通知(Advice往哪些方法上切入
execution([访问控制权限修饰符] 返回值类型 [全限定类名]方法名(形式参数列表) [异常])
使用Spring的AOP
Spring对AOP的实现包括以下3种方式
第一种方式:Spring框架结合AspectJ框架实现的AOP,基于注解方式第二种方式:Spring框架结合AspectJ框架实现的AOP,基于XML方式第三种方式: Spring框架自己实现的AOP,基于XML配置方式。
准备工作
<!--spring context依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.0-M2</version>
</dependency>
<!--spring aop依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>6.0.0-M2</version>
</dependency>
<!--spring aspects依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.0.0-M2</version>
</dependency>
<?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">
</beans>
目标类
// 目标类
@Component
public class OrderService {
// 目标方法
public void generate(){
System.out.println("订单已生成!");
}
}
切面类
import org.aspectj.lang.annotation.Aspect;
// 切面类
@Aspect
@Component
public class MyAspect {
}
spring.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.powernode.spring6.service"/>
</beans>
在切面类中添加通知和切点表达式
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;
// 切面类
@Aspect
@Component
public class MyAspect {
// 切点表达式
@Before("execution(* com.powernode.spring6.service.OrderService.*(..))")
// 这就是需要增强的代码(通知)
public void advice(){
System.out.println("我是一个通知");
}
}
在spring配置文件中启用自动代理
<?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.powernode.spring6.service"/>
<!--开启自动代理-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>