Spring AOP 面向切面编程
一、概述
1、简介
AOP是一个面向切面编程的思想,它补充了面向对象的不足 简化代码把方法中非核心功能且重复的代码抽取 出来 增强代码把特定的功能封装到切面类中,哪里需要就往上套,被套用 的方法被切面增强了 对方法的增强,本质上就是在执行方法的前后添加功能 把一些与业务逻辑层无关的代码分离出来
2、核心概念
切面:类是对物体特征的抽象,切面就是对横切关注点的抽象 通知:指拦截到连接点之后要执行的代码,分为前置、后置、异常、返回后、环绕通知五类 横切关注点:对哪些方法进行拦截,拦截后怎么处理,为横切关注点 连接点:被拦截到的点,被抽取的方法 目标:被代理的目标对象 代理:向目标对象应用通知之后创建的代理对象 切入点:对连接点进行拦截的定义
3、应用场景
二、AOP注解
@Aspect:切面类 @PointCut:切点 @Before:前置通知 @After:后置通知 @AfterReturning:返回后通知 @AfterThrowing:异常通知 @Around:环绕通知 @Order:优先级,value指越小优先级越高
三、基于XML的AOP
1、导入jar包pom.xml
< dependencies>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-context</ artifactId>
< version> 5.3.21</ version>
</ dependency>
< dependency>
< groupId> junit</ groupId>
< artifactId> junit</ artifactId>
< version> 4.13.2</ version>
</ dependency>
< dependency>
< groupId> org.springframework.boot</ groupId>
< artifactId> spring-boot-starter-aop</ artifactId>
< version> 2.7.0</ version>
</ dependency>
</ dependencies>
2、创建Calculator接口
package com. sgz. aop ;
public interface Calculator {
int add ( int i, int j) ;
int sub ( int i, int j) ;
int mul ( int i, int j) ;
int div ( int i, int j) ;
}
3、创建CalculatorImpl实现类
package com. sgz. aop ;
public class CalculatorImpl implements Calculator {
@Override
public int add ( int i, int j) {
int result = i + j;
System . out. println ( "方法内部,result:" + result) ;
return result;
}
@Override
public int sub ( int i, int j) {
int result = i - j;
System . out. println ( "方法内部,result:" + result) ;
return result;
}
@Override
public int mul ( int i, int j) {
int result = i * j;
System . out. println ( "方法内部,result:" + result) ;
return result;
}
@Override
public int div ( int i, int j) {
int result = i / j;
System . out. println ( "方法内部,result:" + result) ;
return result;
}
}
4、创建LoggerAspect类
package com. sgz. aop ;
import org. aspectj. lang. JoinPoint ;
import org. aspectj. lang. ProceedingJoinPoint ;
import org. aspectj. lang. Signature ;
import org. springframework. stereotype. Component ;
@Component
public class LoggerAspect {
public void beforeAdviceMethod ( JoinPoint joinPoint) {
Signature signature = joinPoint. getSignature ( ) ;
System . out. println ( "LoggerAspect-->前置通知" + signature. getName ( ) ) ;
}
public void afterAdviceMethod ( JoinPoint joinPoint) {
Signature signature = joinPoint. getSignature ( ) ;
System . out. println ( "LoggerAspect-->后置通知" + signature. getName ( ) ) ;
}
public void afterReturningAdviceMethod ( JoinPoint joinPoint, Object result) {
Signature signature = joinPoint. getSignature ( ) ;
System . out. println ( "LoggerAspect-->返回通知" + signature. getName ( ) + ",结果:" + result) ;
}
public void afterThrowingAdviceMethod ( JoinPoint joinPoint, Throwable ex) {
Signature signature = joinPoint. getSignature ( ) ;
System . out. println ( "LoggerAspect-->异常通知" + signature. getName ( ) + ",异常通知" + ex) ;
}
public Object aroundAdviceMethod ( ProceedingJoinPoint joinPoint) {
Object result = null ;
try {
System . out. println ( "环绕通知-->前置通知" ) ;
result = joinPoint. proceed ( ) ;
System . out. println ( "环绕通知-->返回通知" ) ;
} catch ( Throwable e) {
e. printStackTrace ( ) ;
System . out. println ( "环绕通知-->异常通知" ) ;
} finally {
System . out. println ( "环绕通知-->后置通知" ) ;
}
return result;
}
}
5、创建ValidateAspect类
package com. sgz. aop ;
import org. springframework. stereotype. Component ;
@Component
public class ValidateAspect {
private void beforeMethod ( ) {
System . out. println ( "ValidateAspect-->前置通知" ) ;
}
}
6、配置applicationContext.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
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd" >
< context: component-scan base-package = " com.sgz.aop" > </ context: component-scan>
< aop: config>
< aop: pointcut id = " pointCut" expression = " execution(* com.sgz.aop.CalculatorImpl.*(..))" />
< aop: aspect ref = " loggerAspect" >
< aop: before method = " beforeAdviceMethod" pointcut-ref = " pointCut" > </ aop: before>
< aop: after method = " afterAdviceMethod" pointcut-ref = " pointCut" > </ aop: after>
< aop: after-returning method = " afterReturningAdviceMethod" returning = " result" pointcut-ref = " pointCut" > </ aop: after-returning>
< aop: after-throwing method = " afterThrowingAdviceMethod" throwing = " ex" pointcut-ref = " pointCut" > </ aop: after-throwing>
< aop: around method = " aroundAdviceMethod" pointcut-ref = " pointCut" > </ aop: around>
</ aop: aspect>
< aop: aspect ref = " validateAspect" order = " 1" >
< aop: before method = " beforeMethod" pointcut-ref = " pointCut" > </ aop: before>
</ aop: aspect>
</ aop: config>
</ beans>
7、创建TestAopXML测试类
package com. sgz. aop. test ;
import com. sgz. aop. Calculator ;
import org. junit. Test ;
import org. springframework. context. support. ClassPathXmlApplicationContext ;
public class TestAopXML {
@Test
public void test ( ) {
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
Calculator calculator = ioc. getBean ( Calculator . class ) ;
calculator. add ( 1 , 1 ) ;
}
}
四、基于注解的AOP
1、导入jar包pom.xml
< dependencies>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-context</ artifactId>
< version> 5.3.21</ version>
</ dependency>
< dependency>
< groupId> junit</ groupId>
< artifactId> junit</ artifactId>
< version> 4.13.2</ version>
</ dependency>
< dependency>
< groupId> org.springframework.boot</ groupId>
< artifactId> spring-boot-starter-aop</ artifactId>
< version> 2.7.0</ version>
</ dependency>
</ dependencies>
2、创建Calculator接口
package com. sgz. aop ;
public interface Calculator {
int add ( int i, int j) ;
int sub ( int i, int j) ;
int mul ( int i, int j) ;
int div ( int i, int j) ;
}
3、创建CalculatorImpl实现类
package com. sgz. aop ;
import org. springframework. stereotype. Component ;
@Component
public class CalculatorImpl implements Calculator {
@Override
public int add ( int i, int j) {
int result = i + j;
System . out. println ( "方法内部,result:" + result) ;
return result;
}
@Override
public int sub ( int i, int j) {
int result = i - j;
System . out. println ( "方法内部,result:" + result) ;
return result;
}
@Override
public int mul ( int i, int j) {
int result = i * j;
System . out. println ( "方法内部,result:" + result) ;
return result;
}
@Override
public int div ( int i, int j) {
int result = i / j;
System . out. println ( "方法内部,result:" + result) ;
return result;
}
}
4、创建LoggerAspect类
package com. sgz. aop ;
import org. aspectj. lang. JoinPoint ;
import org. aspectj. lang. ProceedingJoinPoint ;
import org. aspectj. lang. Signature ;
import org. aspectj. lang. annotation. * ;
import org. springframework. stereotype. Component ;
@Component
@Aspect
public class LoggerAspect {
@Pointcut ( "execution(* com.sgz.aop.CalculatorImpl.*(..))" )
public void pointCut ( ) {
}
@Before ( "pointCut()" )
public void beforeAdviceMethod ( JoinPoint joinPoint) {
Signature signature = joinPoint. getSignature ( ) ;
System . out. println ( "LoggerAspect-->前置通知" + signature. getName ( ) ) ;
}
@After ( "pointCut()" )
public void afterAdviceMethod ( JoinPoint joinPoint) {
Signature signature = joinPoint. getSignature ( ) ;
System . out. println ( "LoggerAspect-->后置通知" + signature. getName ( ) ) ;
}
@AfterReturning ( value = "pointCut()" , returning = "result" )
public void afterReturningAdviceMethod ( JoinPoint joinPoint, Object result) {
Signature signature = joinPoint. getSignature ( ) ;
System . out. println ( "LoggerAspect-->返回通知" + signature. getName ( ) + ",结果:" + result) ;
}
@AfterThrowing ( value = "pointCut()" , throwing = "ex" )
public void afterThrowingAdviceMethod ( JoinPoint joinPoint, Throwable ex) {
Signature signature = joinPoint. getSignature ( ) ;
System . out. println ( "LoggerAspect-->异常通知" + signature. getName ( ) + ",异常通知" + ex) ;
}
@Around ( "pointCut()" )
public Object aroundAdviceMethod ( ProceedingJoinPoint joinPoint) {
Object result = null ;
try {
System . out. println ( "环绕通知-->前置通知" ) ;
result = joinPoint. proceed ( ) ;
System . out. println ( "环绕通知-->返回通知" ) ;
} catch ( Throwable e) {
e. printStackTrace ( ) ;
System . out. println ( "环绕通知-->异常通知" ) ;
} finally {
System . out. println ( "环绕通知-->后置通知" ) ;
}
return result;
}
}
5、创建ValidateAspect类
package com. sgz. aop ;
import org. aspectj. lang. annotation. Aspect ;
import org. aspectj. lang. annotation. Before ;
import org. springframework. core. annotation. Order ;
import org. springframework. stereotype. Component ;
@Component
@Aspect
@Order ( 1 )
public class ValidateAspect {
@Before ( "com.sgz.aop.LoggerAspect.pointCut()" )
private void beforeMethod ( ) {
System . out. println ( "ValidateAspect-->前置通知" ) ;
}
}
6、配置applicationContext.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
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd" >
< context: component-scan base-package = " com.sgz.aop" > </ context: component-scan>
< aop: aspectj-autoproxy/>
</ beans>
7、创建TestAop测试类
package com. sgz. aop. test ;
import com. sgz. aop. Calculator ;
import org. junit. Test ;
import org. springframework. context. support. ClassPathXmlApplicationContext ;
public class TestAop {
@Test
public void test ( ) {
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
Calculator calculator = ioc. getBean ( Calculator . class ) ;
calculator. add ( 1 , 1 ) ;
}
}