AOP:面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是 Spring框架中的一个重要内容。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等
下面总结下AOP几种通知(切入方式)。
首先:
建立操作的接口ActionService:
public interface ActionService {
public void addAction(String param);
}
ActionService的实现类:ActionServiceImpl
public class ActionServiceImpl implements ActionService{
@Override
public void addAction(String name) {
System.out.println("执行参数:"+name+"===执行动作进行中......");
}
}
再建立一个切面类:ActionServiceAspect,该类主要是承载各种切入(通知)情况
public class ActionServiceAspect {
.......
通知代码
.......
}
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: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
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="actionServiceAspect" class="com.java.advice.ActionServiceAspect"></bean>
<bean id="actionService" class="com.java.service.impl.ActionServiceImpl"></bean>
<!-- AOP配置 -->
<aop:config>
<!-- 配置一个切面 -->
<aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
<!-- 定义个切点: expression方法表达式-->
<aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
<!-- 以下配置通知 -->
......
......
</aop:aspect>
</aop:config>
</beans>
建测试类Test.java 执行测试结果:
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//这里使用到多态,可以指向具体的实现类
ActionService sService=(ActionService)ac.getBean("actionService");
sService.addAction("ActionParam");
}
1、前置通知
在ActionServiceAspect.java中加入前置的方法
public void doBefore(JoinPoint jp){
System.out.println("前置通知");
System.out.println("操作的类名:"+jp.getTarget().getClass().getName());
System.out.println("操作的方法名:"+jp.getSignature().getName());
System.out.println("执行方法的参数:"+jp.getArgs()[0]);
}
applicationContext.xml在AOP中配置前置通知
<!-- AOP配置 -->
<aop:config>
<!-- 配置一个切面 -->
<aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
<!-- 定义个切点: expression方法表达式-->
<aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
<!-- 前置通知 -->
<aop:before method="doBefore" pointcut-ref="pointCut"/>
</aop:aspect>
</aop:config>
执行Test.java,结果:
(前置通知)
操作的类名:com.java.service.impl.ActionServiceImpl
操作的方法名:addAction
执行方法的参数::ActionParam
执行参数:ActionParam===执行动作进行中......
顾名思义,前置通知,切入方法执行前执行。
2.后置通知
在ActionServiceAspect.java中加入后置通知的方法
public void doBeAfter(JoinPoint jp){
System.out.println("执行动作完成(后置通知)");
}
applicationContext.xml在AOP中配置后置通知
<!-- AOP配置 -->
<aop:config>
<!-- 配置一个切面 -->
<aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
<!-- 定义个切点: expression方法表达式-->
<aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
<!-- 后置通知 -->
<aop:after method="doBeAfter" pointcut-ref="pointCut"/>
</aop:aspect>
</aop:config>
Test.java执行结果(切入操作方法完成后再执行):
执行参数:ActionParam===执行动作进行中......
执行动作完成(后置通知)
3.环绕通知
在ActionServiceAspect.java中加入环绕通知的方法
public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("执行动作前(环绕通知)..........");
//pjp.proceed()相当调用addAction方法,返回值相当于方法的返回值
Object obj=pjp.proceed();
System.out.println("执行动作后(环绕通知)..........");
return obj;
}
applicationContext.xml在AOP中配置环绕通知
<!-- AOP配置 -->
<aop:config>
<!-- 配置一个切面 -->
<aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
<!-- 定义个切点: expression方法表达式-->
<aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
<!-- 配置环绕通知 -->
<aop:around method="doAround" pointcut-ref="pointCut"/>
</aop:aspect>
</aop:config>
执行结果:
执行动作前(环绕通知)..........
执行参数:ActionParam===执行动作进行中......
执行动作后(环绕通知)..........
由此可见,环绕通知囊括前置、后置通知,所以使用环绕通知就不必要使用前后置,当然,视需求而定。
4.返回通知
在ActionServiceAspect.java中加入返回通知的方法
public void doAfterRuturning(JoinPoint jp){
System.out.println("返回通知");
}
applicationContext.xml在AOP中配置返回通知
<!-- AOP配置 -->
<aop:config>
<!-- 配置一个切面 -->
<aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
<!-- 定义个切点: expression方法表达式-->
<aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
<!-- 返回通知 -->
<aop:after-returning method="doAfterRuturning" pointcut-ref="pointCut"/>
</aop:aspect>
</aop:config>
执行结果:
执行参数:ActionParam===执行动作进行中......
返回通知
返回通知类似后置通知,觉得有点怪异。
4.异常通知
在操作类ActionServiceImpl中添加异常的方法:
public void addAction(String name) {
System.out.println("执行参数:"+name+"===执行动作进行中......");
System.out.println((1/0));
}
在ActionServiceAspect.java中加入异常通知的方法
public void doAfterThrowing(JoinPoint pj,Throwable ta){
System.out.println("异常通知");
System.out.println("打印异常:"+ta.getMessage());
}
applicationContext.xml在AOP中配置异常通知
<!-- AOP配置 -->
<aop:config>
<!-- 配置一个切面 -->
<aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
<!-- 定义个切点: expression方法表达式-->
<aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
<!-- 异常通知 -->
<aop:after-throwing method="doAfterThrowing" pointcut-ref="pointCut" throwing="ta"/>
</aop:aspect>
</aop:config>
执行结果:
执行参数:ActionParam===执行动作进行中......
异常通知
打印异常:/ by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.java.service.impl.ActionServiceImpl.addAction(ActionServiceImpl.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
下面我们再试下这几种方式一起执行看看执行的顺序:
完整的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: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
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="actionServiceAspect" class="com.java.advice.ActionServiceAspect"></bean>
<bean id="actionService" class="com.java.service.impl.ActionServiceImpl"></bean>
<!-- AOP配置 -->
<aop:config>
<!-- 配置一个切面 -->
<aop:aspect id="actionServiceAspect" ref="actionServiceAspect">
<!-- 定义个切点: expression方法表达式-->
<aop:pointcut expression="execution( * com.java.service.*.*(..))" id="pointCut"/>
<!-- 前置通知 -->
<aop:before method="doBefore" pointcut-ref="pointCut"/>
<!-- 后置通知 -->
<aop:after method="doBeAfter" pointcut-ref="pointCut"/>
<!-- 配置环绕通知 -->
<aop:around method="doAround" pointcut-ref="pointCut"/>
<!-- 返回通知 -->
<aop:after-returning method="doAfterRuturning" pointcut-ref="pointCut"/>
<!-- 异常通知 -->
<aop:after-throwing method="doAfterThrowing" pointcut-ref="pointCut" throwing="ta"/>
</aop:aspect>
</aop:config>
</beans>
执行结果:
前置通知
操作的类名:com.java.service.impl.ActionServiceImpl
操作的方法名:addAction
执行方法参数:ActionParam
执行动作前(环绕通知)..........
执行参数:ActionParam===执行动作进行中......
打印异常(异常通知):/ by zero
执行动作完成(后置通知)
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.java.service.impl.ActionServiceImpl.addAction(ActionServiceImpl.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)