Spring-AOP例子
第一部分是前期准备,第二部分是基于注解的方式配置事务,第三部分基于
.xml
配置文件配置事务
一、准备
使用加减乘除方法测试,测试AOP
1.1 概览
1.2 jar
包介绍 (lib
)
junit
测试
①junit-4.12.jar
②hamcrest-core-1.3.jar
Spring
核心容器(4个:Beans,Core,Context,expression)
①spring-beans-5.3.1.jar
②spring-context-5.3.1.jar
③spring-core-5.3.1.jar
----->依赖于jar包spring-jcl-5.3.1.jar
④spring-expression-5.3.1.jar
Spring aop
①spring-aop-5.3.1.jar
②spring-aspect-5.3.1.jar
③com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
JdbcTemplate
①spring-jdbc-5.3.1.jar
②spring-orm-5.3.1.jar
③spring-tx-5.3.1.jar
连接数据库的驱动jar包和数据源
①mysql-connector-java-5.1.37-bin.jar
②druid-1.1.9.jar
1.3 方法(Calculator
)
public interface Calculator {
int add(int a,int b);
int sub(int a,int b);
int mul(int a,int b);
int div(int a,int b);
}
1.4 实现类(CalculatorImpl
)
public class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public int sub(int a, int b) {
return a - b;
}
@Override
public int mul(int a, int b) {
return a * b;
}
@Override
public int div(int a, int b) {
return a / b;
}
}
二、基于注解的方式配置事务
2.1 在实现类中添加@Controller注解 (CalculatorImpl
)
@Controller("coc")
public class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public int sub(int a, int b) {
return a - b;
}
@Override
public int mul(int a, int b) {
return a * b;
}
@Override
public int div(int a, int b) {
return a / b;
}
}
2.2 通知事务 (LoggingAspect
)
@Controller//交给Spring的IOC容器管理
@Aspect//声明该类是一个切面
public class LoggingAspect {
//声明切入点表达式,在使用的地方通过方法名引用即可
@Pointcut(value = "execution(* com.spring.aop.aspect.Calculator.*(..))")
public void pointCut() {
}
//前置通知,在方法执行之前执行
@Before(value = "pointCut()")
public void beforeAdvice(JoinPoint joinPoint){
//获取方法名
String methodName = joinPoint.getSignature().getName();
//获取参数
Object[] args = joinPoint.getArgs();
System.out.println("前置通知: "+methodName+" 方法,参数: "+ Arrays.toString(args));
}
//后置通知,在方法执行之后执行,不管是否发生异常
@After("pointCut()")
public void afterAdvice(JoinPoint joinPoint){
//获取方法名
String methodName = joinPoint.getSignature().getName();
System.out.println("后置通知: "+methodName+" 方法");
}
//返回通知,在方法返回结果之后执行
//pointcut属性:指定切入点表达式,跟value属性功能一样;returning属性:获取方法的返回值,并指定通知方法中入参的形参名
@AfterReturning(pointcut = "pointCut()",returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result){
//获取方法名
String methodName = joinPoint.getSignature().getName();
System.out.println("返回通知: "+methodName+" 方法,返回: "+result);
}
//异常通知,在方法执行抛出异常时执行
//pointcut属性:指定切入点表达式,跟value属性功能一样;throwing属性:获取异常信息,并指定通知方法中入参的形参名
@AfterThrowing(value = "execution(* Calculator.*(..))",throwing = "e")
public void afterThrowing(JoinPoint joinPoint,Throwable e){
//获取方法名
String methodName = joinPoint.getSignature().getName();
System.out.println("异常通知: "+methodName+" 方法,异常: "+e);
}
}
2.3 .xml配置 (calculator.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.spring.aop.aspect"/>
<!--开启通知-->
<aop:aspectj-autoproxy/>
</beans>
2.4 测试类 (testCalculator
)
public class testCalculator {
ApplicationContext ioc = new ClassPathXmlApplicationContext("calculator.xml");
@Test
public void test01() {
Calculator calculator = (Calculator) ioc.getBean("coc");
calculator.add(10, 2);//加
calculator.sub(10, 2);//减
calculator.mul(10, 2);//乘
calculator.div(10, 0);//除:测试异常通知
}
}
2.5 输出
改进为环绕通知
2.6 改进通知事务 (LoggingAspect
)为环绕通知
@Controller
@Aspect
public class LoggingAspect {
@Pointcut(value = "execution(* com.spring.aop.aspect.Calculator.*(..))")
public void pointCut() {
}
//环绕通知,相当于动态代理的全过程
@Around(value = "pointCut()")
public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
//获取方法名
String methodName = proceedingJoinPoint.getSignature().getName();
//获取参数
Object[] args = proceedingJoinPoint.getArgs();
Object result = null;
try {
//前置通知
System.out.println("前置通知: "+methodName+" 方法,参数: "+ Arrays.toString(args));
//执行被代理对象的方法
result = proceedingJoinPoint.proceed();
//返回通知
System.out.println("返回通知: "+methodName+" 方法,返回: "+result);
} catch (Throwable e) {
//异常通知
System.out.println("异常通知: "+methodName+" 方法,异常: "+e);
e.printStackTrace();
} finally {
//后置通知
System.out.println("后置通知: "+methodName+" 方法");
}
return result;
}
}
2.7 切面执行顺序
如果有两个事务通知,要规定其先后顺序就可以使用
@Order()
注解,设置value参数,越小执行越靠前,默认值为2147483647。
在切面类中直接注解
三、基于.xml
配置文件配置事务
3.1 还原实现类(CalculatorImpl
)
public class CalculatorImpl implements Calculator{
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public int sub(int a, int b) {
return a - b;
}
@Override
public int mul(int a, int b) {
return a * b;
}
@Override
public int div(int a, int b) {
return a / b;
}
}
3.2 事务通知(LoggingAspect
)
public class LoggingAspect {
//前置通知
public void beforeAdvice(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("前置通知:" + methodName + "方法,参数为:" + Arrays.toString(args));
}
//后置通知
public void afterAdvice(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("后置通知:" + methodName + "方法。");
}
//异常通知
public void afterThrowing(JoinPoint joinPoint, Throwable e) {
String methodName = joinPoint.getSignature().getName();
System.out.println("异常通知:" + methodName + "方法,异常:" + e);
}
//返回通知
public void afterReturning(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("返回通知:" + methodName+"方法,结果为:" + result);
}
}
3.3 .xml配置 (calculator-xml.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="calculator" class="com.spring.aop.aspect.aop.CalculatorImpl"/>
<bean id="loggingAspect2" class="com.spring.aop.aspect.aop.LoggingAspect"/>
<aop:config>
<aop:pointcut id="pointCut" expression="execution(* com.spring.aop.aspect.xml.CalculatorImpl.*(..))"/>
<aop:aspect ref="loggingAspect2">
<!--前置通知-->
<aop:before method="beforeAdvice" pointcut-ref="pointCut"/>
<!--后置通知-->
<aop:after method="afterAdvice" pointcut-ref="pointCut"/>
<!--返回通知-->
<aop:after-returning method="afterReturning" pointcut-ref="pointCut" returning="result"/>
<!--异常通知-->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointCut" throwing="e"/>
</aop:aspect>
</aop:config>
</beans>
3.4 测试类 (testCalculator-xml
)
public class TestCalculator {
ApplicationContext ioc = new ClassPathXmlApplicationContext("calculator-xml.xml");
@Test
public void test01(){
Calculator calculator = (Calculator) ioc.getBean("calculator");
calculator.add(10, 2);
calculator.sub(10, 2);
calculator.mul(10, 2);
calculator.div(10, 0);
}
}
3.5 改进通知事务 (LoggingAspect
)为环绕通知
public class LoggingAspect {
//环绕通知,相当于动态代理的全过程
public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
//获取方法名
String methodName = proceedingJoinPoint.getSignature().getName();
//获取参数
Object[] args = proceedingJoinPoint.getArgs();
Object result=null;
try {
//前置通知
System.out.println("前置通知:" + methodName + "方法,参数为:" + Arrays.toString(args));
//执行被代理对象的方法
result = proceedingJoinPoint.proceed();
//返回通知
System.out.println("返回通知:" + methodName+"方法,结果为:" + result);
} catch (Throwable e) {
//异常通知e
System.out.println("异常通知:" + methodName + "方法,异常:" + e);
e.printStackTrace();
} finally {
//后置通知
System.out.println("后置通知:" + methodName + "方法。");
}
return result;
}
}
3.6 修改配置文件 (calculator-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="calculator" class="com.spring.aop.aspect.xml.CalculatorImpl"/>
<bean id="loggingAspect" class="com.spring.aop.aspect.xml.LoggingAspect"/>
<aop:config>
<aop:pointcut id="pointCut" expression="execution(* com.spring.aop.aspect.xml.CalculatorImpl.*(..))"/>
<aop:aspect ref="loggingAspect">
<!--<!--前置通知-->
<aop:before method="beforeAdvice" pointcut-ref="pointCut"/>
<!--后置通知-->
<aop:after method="afterAdvice" pointcut-ref="pointCut"/>
<!--返回通知-->
<aop:after-returning method="afterReturning" pointcut-ref="pointCut" returning="result"/>
<!--异常通知-->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointCut" throwing="e"/>-->
<!--环绕通知-->
<aop:around method="aroundAdvice" pointcut-ref="pointCut"/>
</aop:config>
</beans>