一、AOP ( Aspect Oriented Programming ) 面向切面编程
常用概念
原有功能: 切点, pointcut
前置通知: 在切点之前执行的功能(在目标方法之前执行). before advice
后置通知: 在切点之后执行的功能(在目标方法之后执行),after advice
如果切点执行过程中出现异常,会触发异常通知.throws advice
所有功能总称叫做切面.
织入: 把切面嵌入到原有功能的过程叫做织入
AOP技术利用一种称为“横切”的技术,剖解开封装的对象内部,将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度(参考:https://blog.csdn.net/yuexianchang/article/details/77018603)。举个栗子,在银行的取钱存钱的过程分别为:取钱:开始取钱-->登录验证-->...-->完成取钱 ; 存钱: 开始存钱-->登录验证-->...-->完成存钱。这两个步骤里有一个共同的行为,就是要进行用户登录校验。那我们可以把这个功能单独封装为一个验证模块,之后在设计银行系统的时候便不需要考虑这个方面,直接略过,后面哪一个步骤需要校验了,就调用这个模块,调用完之后再回到原来的流程中继续进行。
如下图,在程序原有纵向执行流程中,针对某一个或某一些方法添加通知(类似拦截器的作用一样),形成横切面过程就叫做面向切面编程。
二、AOP 实现方式
- Schema-based
每个通知都需要实现接口或类
配置 spring 配置文件时在<aop:config>配置
- AspectJ
每个通知不需要实现接口或类
配置 spring 配置文件是在<aop:config>的子标签<aop:aspect>中配置
三、Schema-based实现
1、jar包
2、新建通知类:前置通知类和后置通知类
package com.wzg.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class MyBeforeAdvice implements MethodBeforeAdvice{
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("前置通知信息:");
System.out.println("切点方法对象"+arg0+",方法名"+arg0.getName());
if(arg1!=null&&arg1.length>0) {
System.out.println("切点方法参数"+arg1);
}else {
System.out.println("切点方法没有参数");
}
System.out.println("对象"+arg2);
}
}
package com.wzg.advice;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class MyAfterAdvice implements AfterReturningAdvice{
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
System.out.println("后置通知信息");
System.out.println("切点方法返回值:"+arg0);
System.out.println("切点方法对象"+arg1+",方法名"+arg1.getName());
if(arg1!=null&&arg2.length>0) {
System.out.println("切点方法参数"+arg2);
}else {
System.out.println("切点方法没有参数");
}
System.out.println("对象"+arg3);
}
}
3. 配置 spring 配置文件
首先要引入aop的命名空间,这里可以理解为模块,需要spring的那部分功能,就调用相关的模块,引入相应的文件。之后配置通知类的<bean>并配置切面。
<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="demo" class="com.wzg.test.Demo"></bean>
<!-- 配置通知类的<bean> -->
<bean id="mybefore" class="com.wzg.advice.MyBeforeAdvice"></bean>
<bean id="myafter" class="com.wzg.advice.MyAfterAdvice"></bean>
<aop:config>
<!-- * 通配符,匹配任意方法名,任意类名,任意一级包名.如果希望匹配任意方法参数 (..) -->
<aop:pointcut expression="execution(* com.wzg.test.Demo.*(..))" id="mypoint"/>
<aop:advisor advice-ref="mybefore" pointcut-ref="mypoint"/>
<aop:advisor advice-ref="myafter" pointcut-ref="mypoint"/>
</aop:config>
</beans>
4.测试类
package com.wzg.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo = ac.getBean("demo", Demo.class);
demo.demo1();
}
}
四、环绕通知(Schema-based实现)
环绕通知类
package com.wzg.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* 环绕通知
* @author wang
*
*/
public class MyArround implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
System.out.println("环绕--前置");
Object result = arg0.proceed();//放行,调用切点方式
System.out.println("环绕--后置");
return result;
}
}
spring配置文件
<bean id="mythrow" class="com.wzg.advice.MyArround"></bean>
<aop:config>
<aop:pointcut expression="execution(* com.wzg.test.Demo.demo1())" id="mypoint"/>
<aop:advisor advice-ref="mythrow" pointcut-ref="mypoint"/>
</aop:config>
五、异常通知(Schema-based实现)
新建一个类实现 throwsAdvice 接口,必须自己写方法,且必须叫 afterThrowing。
有两种参数方式,必须是 1 个或 4 个,异常类型要与切点报的异常类型一致。
public class MyThrow implements ThrowsAdvice{
// public void afterThrowing(Method m, Object[] args,Object target, Exception ex) {
// System.out.println("执行异常通知");
// }
public void afterThrowing(Exception ex) throws Throwable {
System.out.println("执行异常通过-schema-based 方式");
}
}
spring配置文件
<bean id="mythrow" class="com.wzg.advice.MyThrow"></bean>
<aop:config>
<aop:pointcut expression="execution(* com.wzg.test.Demo.demo1())" id="mypoint"/>
<aop:advisor advice-ref="mythrow" pointcut-ref="mypoint"/>
</aop:config>