03.Spring_AOP
1.需要导入的jar包
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
commons-logging-1.1.3.jar
spring-aop-4.0.0.RELEASE.jar
//以下是AOP需要额外导入的jar包
spring-aspects-4.0.0.RELEASE.jar
2.AOP中的注解
- @Aspect
- 声明某一个类是一个切面类
- 声明为切面类的同时还需要交给IOC容器管理
@Aspect
// 声明当前类是一个切面类
@Component
// 将当前类交给IOC容器管理
public
class
LoggingAspect {
- @Pointcut
- 声明切入点表达式
//声明切入点表达式
@Pointcut("execution(*
com.atguigu.spring.aop.ArithmeticCalculator.*(..))")
public
void
pointCut(){};
- @Before
- 声明前置通知
- 前置通知在方法执行之前调用
// 前置通知,在目标方法调用之前执行
@Before(value
=
"pointCut()")
public
void
beforeAdvice(JoinPoint
jp) {
// 获取方法名
String
name
=
jp.getSignature().getName();
// 获取参数
Object[]
args
=
jp.getArgs();
System.out.println("[★★★Logging]The
method "
+
name
+
" begins with "
+ Arrays.asList(args));
}
- @After
- 声明后置通知
- 后置通知在方法执行完成后调用(不管是否发生异常)
// 后置通知,在目标方法执行完成之后执行(不管是否发生异常)
@After("pointCut()")
public
void
afterAdvice(JoinPoint
jp) {
// 获取方法名
String
name
=
jp.getSignature().getName();
System.out.println("[★★★Logging]The
method "
+
name
+
" ends");
}
- @AfterReturning
- 声明返回通知
- 返回通知在方法执行完之后调用
//返回通知,在目标方法执行后执行
@AfterReturning(pointcut
=
"execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))",returning="result")
public
void
returnAdvice(JoinPoint
jp
, Object
result) {
// 获取方法名
String
name
=
jp.getSignature().getName();
System.out.println("[★★★Logging]The
method "
+
name
+
" returns "+result);
}
- @AfterThrowing
- 声明异常通知
- 异常通知在方法执行出现异常时调用
//异常通知,在目标方法执行出现异常时执行
@AfterThrowing(pointcut
=
"execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))",throwing="e")
public
void
returnAdvice(JoinPoint
jp
, Exception
e) {
// 获取方法名
String
name
=
jp.getSignature().getName();
System.out.println("[★★★Logging]The
method "
+
name
+
" occours "+e);
}
- @Around(使用环绕通知必须将前面的前后等方法注掉)
- 声明环绕通知
- 环绕通知相当于动态代理的全过程
//环绕通知,相当于动态代理的全过程
@Around("pointCut()")
public
Object roundAdvice(ProceedingJoinPoint
pjp) {
//获取方法名
String
name
=
pjp.getSignature().getName();
//获取参数
Object[]
args
=
pjp.getArgs();
Object
result
=
null;
try
{
//前置通知
System.out.println("[★★★★★Logging]The
method "
+
name
+
" begins with "
+ Arrays.asList(args));
//执行目标方法
result
=
pjp.proceed();
//返回通知
System.out.println("[★★★★★Logging]The
method "
+
name
+
" returns "+result);
}
catch
(Throwable
e) {
//异常通知
System.out.println("[★★★★★Logging]The
method "
+
name
+
" occours "+e);
// e.printStackTrace();
}
finally{
//后置通知
System.out.println("[★★★★★Logging]The
method "
+
name
+
" ends");
}
return
result;
}
- @Order
- 声明切面的优先级
- 通过该注解中的value属性值来设置切面的优先级,里面传入一个int类型的值,值越小优先级越高,默认值是Integer的最大值
@Order(10)
//可以通过@Order注解中的value属性设置切面的优先级,value属性值越小优先级越高,默认值是Integer的最大值
@Aspect
// 声明当前类是一个切面类
@Component
// 将当前类交给IOC容器管理
public
class
ValidateAspect {
- Spring的配置文件中的配置
<?xml
version="1.0"
encoding="UTF-8"?>
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsd";>
<!-- 设置自动扫描的包 -->
<context:component-scan
base-package="com.atguigu.spring.aop"></context:component-scan>
<!-- 启用 AspectJ
注解支持:Spring会自动创建代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
package com.atguigu.spring.aop;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect // 声明当前类是一个切面类
@Component // 将当前类交给IOC容器管理
public class LoggingAspect {
//声明切入点表达式
@Pointcut("execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))")
public void pointCut(){};
/**
* 切入点表达式的表示方式: ①execution(public int
* com.atguigu.spring.aop.ArithmeticCalculator.add(int, int))
* execution(public int ArithmeticCalculator.add(int, int))
* -只有调用ArithmeticCalculator接口中的add()方法时才会执行对应的通知 -如果切面类与接口和实现类在同一个包下,包名可以省略
* ②execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int,
* int)) --只有调用ArithmeticCalculator接口中的所有的方法时都会会执行对应的通知 ③execution(*
* com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))
* --调用ArithmeticCalculator接口中的所有的方法时都会会执行对应的通知,而且不考虑权限修饰符和返回值类型
* ④execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))
* --调用ArithmeticCalculator接口中的所有的方法时都会会执行对应的通知,而且不考虑权限修饰符和返回值类型以及参数的类型和个数
* ⑤execution(* *.*(..)) --调用所有接口的方法时都会会执行对应的通知,而且不考虑权限修饰符和返回值类型以及参数的类型和个数
*
*/
// 前置通知,在目标方法调用之前执行
@Before(value = "pointCut()")
public void beforeAdvice(JoinPoint jp) {
// 获取方法名
String name = jp.getSignature().getName();
// 获取参数
Object[] args = jp.getArgs();
System.out.println("[★★★Logging]The method " + name + " begins with " + Arrays.asList(args));
}
// 后置通知,在目标方法执行完成之后执行(不管是否发生异常)
@After("pointCut()")
public void afterAdvice(JoinPoint jp) {
// 获取方法名
String name = jp.getSignature().getName();
System.out.println("[★★★Logging]The method " + name + " ends");
}
//返回通知,在目标方法执行后执行
@AfterReturning(pointcut = "execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))",returning="result")
public void returnAdvice(JoinPoint jp , Object result) {
// 获取方法名
String name = jp.getSignature().getName();
System.out.println("[★★★Logging]The method " + name + " returns "+result);
}
//异常通知,在目标方法执行出现异常时执行
@AfterThrowing(pointcut = "execution(* com.atguigu.spring.aop.ArithmeticCalculator.*(..))",throwing="e")
public void returnAdvice(JoinPoint jp , Exception e) {
// 获取方法名
String name = jp.getSignature().getName();
System.out.println("[★★★Logging]The method " + name + " occours "+e);
}
//环绕通知,相当于动态代理的全过程
@Around("pointCut()")
public Object roundAdvice(ProceedingJoinPoint pjp) {
//获取方法名
String name = pjp.getSignature().getName();
//获取参数
Object[] args = pjp.getArgs();
Object result = null;
try {
//前置通知
System.out.println("[★★★★★Logging]The method " + name + " begins with " + Arrays.asList(args));
//执行目标方法
result = pjp.proceed();
//返回通知
System.out.println("[★★★★★Logging]The method " + name + " returns "+result);
} catch (Throwable e) {
//异常通知
System.out.println("[★★★★★Logging]The method " + name + " occours "+e);
// e.printStackTrace();
} finally{
//后置通知
System.out.println("[★★★★★Logging]The method " + name + " ends");
}
return result;
}
}
test
package com.atguigu.spring.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.atguigu.spring.aop.ArithmeticCalculator;
public class AopTest {
// 创建IOC容器
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans-aop.xml");
@Test
public void testAOP() {
ArithmeticCalculator atc = (ArithmeticCalculator) ioc.getBean("arithmeticCalculator");
// 进行加、减、乘、除的运算
int add = atc.add(10, 2);
System.out.println(add);
int sub = atc.sub(10, 2);
System.out.println(sub);
int mul = atc.mul(10, 2);
System.out.println(mul);
int div = atc.div(10, 0);
System.out.println(div);
}
}
3.基于XML的形式配置AOP
<?xml
version="1.0"
encoding="UTF-8"?>
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsd";>
<!-- 配置数学计算器的实现类bean -->
<bean
id="arithmeticCalculator"
class="com.atguigu.spring.xml.ArithmeticCalculatorImpl"></bean>
<!-- 配置切面类bean -->
<bean
id="loggingAspect"
class="com.atguigu.spring.xml.LoggingAspect"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切入点表达式 -->
<aop:pointcut
expression="execution(* com.atguigu.spring.xml.ArithmeticCalculator.*(..))"
id="pointCut"/>
<!-- 配置切面 -->
<aop:aspect
ref="loggingAspect">
<!-- 前置通知 -->
<aop:before
method="beforeAdvice"
pointcut-ref="pointCut"/>
<!-- 后置通知 -->
<aop:after
method="afterAdvice"
pointcut-ref="pointCut"/>
<!-- 返回通知 -->
<aop:after-returning
method="returnAdvice"
pointcut-ref="pointCut"
returning="result"/>
<!-- 异常通知 -->
<aop:after-throwing
method="exceptionAdvice"
pointcut-ref="pointCut"
throwing="e"/>
<!-- 环绕通知 -->
<aop:around
method="roundAdvice"
pointcut-ref="pointCut"/>
</aop:aspect>
</aop:config>
</beans>
package com.atguigu.spring.xml;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
public class LoggingAspect {
// 前置通知,在目标方法调用之前执行
public void beforeAdvice(JoinPoint jp) {
// 获取方法名
String name = jp.getSignature().getName();
// 获取参数
Object[] args = jp.getArgs();
System.out.println("[▲Logging]The method " + name + " begins with " + Arrays.asList(args));
}
// 后置通知,在目标方法执行完成之后执行(不管是否发生异常)
public void afterAdvice(JoinPoint jp) {
// 获取方法名
String name = jp.getSignature().getName();
System.out.println("[▲Logging]The method " + name + " ends");
}
//返回通知,在目标方法执行后执行
public void returnAdvice(JoinPoint jp , Object result) {
// 获取方法名
String name = jp.getSignature().getName();
System.out.println("[▲Logging]The method " + name + " returns "+result);
}
//异常通知,在目标方法执行出现异常时执行
public void exceptionAdvice(JoinPoint jp , Exception e) {
// 获取方法名
String name = jp.getSignature().getName();
System.out.println("[▲Logging]The method " + name + " occours "+e);
}
//环绕通知,相当于动态代理的全过程
public Object roundAdvice(ProceedingJoinPoint pjp) {
//获取方法名
String name = pjp.getSignature().getName();
//获取参数
Object[] args = pjp.getArgs();
Object result = null;
try {
//前置通知
System.out.println("[▲▲Logging]The method " + name + " begins with " + Arrays.asList(args));
//执行目标方法
result = pjp.proceed();
//返回通知
System.out.println("[▲▲Logging]The method " + name + " returns "+result);
} catch (Throwable e) {
//异常通知
System.out.println("[▲▲Logging]The method " + name + " occours "+e);
// e.printStackTrace();
} finally{
//后置通知
System.out.println("[▲▲Logging]The method " + name + " ends");
}
return result;
}
}
test
package com.atguigu.spring.test;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.atguigu.spring.xml.ArithmeticCalculator;
public class Aop_xmlTest {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans-xml.xml");
@Test
public void testAOP_xml() {
ArithmeticCalculator atc = (ArithmeticCalculator) ioc.getBean("arithmeticCalculator");
// 进行加、减、乘、除的运算
int add = atc.add(10, 2);
System.out.println(add);
int sub = atc.sub(10, 2);
System.out.println(sub);
int mul = atc.mul(10, 2);
System.out.println(mul);
int div = atc.div(10, 2);
System.out.println(div);
}
}