Spring AOP概述
AOP的全称是Aspect-Oriented Programming,即
面向切面编程
(也称面向方面编程)。它是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式
诞生的原因
如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中。这样,如果想要关闭某个功能,或者对其进行修改,就必须要修改所有的相关方法。这不但增加了开发人员的工作量,而且提高了代码的出错率
AOP解决
AOP采取
横向抽取机制
,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方
类和却面的关系
AOP术语
术语包括
Aspect
、Joinpoint
、Pointcut
、Advice
、Target Object
、Proxy和Weaving
,
Aspect(切面):在实际应用中,切面通常是指封装的用于横向插入系统功能(如事务、日志等)的类。需要在配置文件中通过元素指定
Joinpoint(连接点):在程序执行过程中的某个阶段点,它实际上是对象的一个操作,例如方法的调用或异常的抛出。在Spring AOP中,连接点就是指方法的调用。
Pointcut(切入点):是指切面与程序流程的交叉点,即那些需要处理的连接点
Advice(通知/增强处理):AOP框架在特定的切入点执行的增强处理,即在定义好的切入点处所要执行的程序代码。可以将其理解为
切面类中的方法
,它是切面的具体实现
Target Object(目标对象):是指所有被通知的对象,也称为被
增强对象
。如果AOP框架采用的是动态的AOP实现,那么该对象就是一个被代理对象
Proxy(代理):将通知应用到目标对象之后,被
动态创建的对象
。
Weaving(织入):将切面代码插入到目标对象上,从而
生成代理对象的过程
。
动态代理
Spring中的AOP代理,可以是JDK动态代理,也可以是CGLIB代理
具体实例和了解可参考
反射 静态代理 动态代理 (JDK代理和CGLib 代理 )
Spring中的AOP代理默认
就是使用JDK动态代理的方式来实现的。在Spring中,使用ProxyFactoryBean
是创建AOP代理的最基本方式
Spring的通知类型
org.aopalliance.intercept.MethodInterceptor(环绕通知)在目标方法执行前后实施增强,可以应用于日志、事务管理等功能
org.springframework.aop.MethodBeforeAdvice(前置通知)在目标方法执行前实施增强,可以应用于权限管理等功能。·
org.springframework.aop.AfterReturningAdvice(后置通知)在目标方法执行后实施增强,可以应用于关闭流、上传文件、删除临时文件等功能。
org.springframework.aop.ThrowsAdvice(异常通知)
·org.springframework.aop.IntroductionInterceptor(引介通知)在目标类中添加一些新的方法和属性,可以应用于修改老版本程序(增强类)。
Spring 实现AOP 实战
基础搭建
导包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
XML实现
public interface UserService {
public void add();
public void delete();
public void search();
}
目标类
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("添加用户方法");
}
public void delete() {
System.out.println("删除用户");
}
public void search() {
System.out.println("搜索用户");
}
}
切面1
public class Log implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println( target.getClass().getName() + "的" + method.getName() + "方法被执行了");
}
}
切面2
public class AfterLog implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" + target.getClass().getName()
+"的"+method.getName()+"方法,"
+"返回值:"+returnValue);
}
}
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: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">
<bean id="log" class="com.Aop.Log"></bean>
<bean id="afterLog" class="com.Aop.AfterLog"></bean>
<bean id="userService" class="com.Aop.UserServiceImpl"></bean>
<!--AOP配置-->
<aop:config expose-proxy="true">
<!--切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.Aop.UserServiceImpl.*(..))"/>
<!--切面,ref引用切面通知类aspectMethod,方便调用其方法-->
<!--通知-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
</beans>
测试类
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
UserService userService = (UserService) context.getBean("userService");
userService.search();
}
@Aspect注解实现
切面
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.Aop.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法执行前---------");
}
@After("execution(* com.Aop.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法执行后---------");
}
@Around("execution(* com.Aop.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
System.out.println("签名:"+jp.getSignature());
//执行目标方法proceed
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
配置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">
<bean id="userService2" class="com.Aop.UserServiceImpl"></bean>
<!--第三种方式:注解实现-->
<bean id="annotationPointcut" class="com.Aop.AnnotationPointcut"/> <aop:aspectj-autoproxy/>
</beans>