一、AOP是什么?
百度百科:在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
简单的说AOP就是在不修改原有程序的情况下,添加一些公共类业务(功能)。如图,通知的功能就是一个切面,他切入到原本的程序执行的流程里,但是不用改变原有程序代码。切面即是图片中的通知,切入的地方为切入点。切入点就是执行之后会触发切面的代码的对象方法。
一般AOP应用在一些公共类业务上面,如:日志,安全,缓存,权限等。AOP本质就是代理。
二、使用AOP的前置准备
除了Spring框架所需的包以外还需要以下jar包
Aopalliance.jar
aspectjweaver.jar
下载链接: https://pan.baidu.com/s/1VxOXzH9VsiNafWfwEHUmDw 提取码: 4625
三、AOP的xml配置
命名空间配置:可以在Spring的帮助文档里面找,也可以自己写,如下将紫色字体复制,在xmlns后加上:aop在把beans(bean)改成aop(红色字体为改好的)
<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"> |
四、实现AOP的3种方式
- 1使用Spring Aop实现
业务类
public interface Service { public void add(); public void update(); public void delete(); } public class ServiceImp implements Service { @Override public void add() { System.out.println("添加数据"); } @Override public void update() { System.out.println("修改数据"); } @Override public void delete() { System.out.println("删除数据"); } } |
切面,log日志类
/*前置通知*/ public class Log implements MethodBeforeAdvice{ /** * @param arg0 method 被调用方法对象 * arg1 被调用方法的参数 * arg2(target)被调用方法的目标对象 * **/ @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println(arg2.getClass().getName()+"的"+arg0.getName()+"方法被执行"); } } |
/*后置通知*/ public class AfterLog implements AfterReturningAdvice { /** * arg0是被执行对象的返回值 * method arg1是被执行的方法对象 * arg2是被执行的方法的参数 * arg3是被执行方法对象的目标对象* **/ @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { System.out.println(arg3.getClass().getName()+"的"+arg1.getName()+"方法被执行后,返回值是"+arg0); } |
XML配置文件
<bean id="service" class="com.service.ServiceImp"></bean> <bean id="log" class="com.log.Log"></bean> <bean id="after" class="com.log.AfterLog"></bean> <aop:config> <!--aop:pointcut为切入点即在哪些方法执行后触发 --> <!-- expression 表达式execution第一个*为所有返回值 后面写具体的包和类的路径 *表示所有 --> <aop:pointcut expression="execution(* com.service.*.*(..))" id="pointcut"/> <!-- aop:advisor将写好的log的bean与切入点关联 --> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="after" pointcut-ref="pointcut"/> </aop:config> |
测试类
public static void main(String[] args) { ApplicationContext ac=new ClassPathXmlApplicationContext("Beans.xml"); Service service=(Service)ac.getBean("service"); service.update(); } |
结果
- 2使用自定义类实现AOP
业务类同上不变。
Log
/*切面*/ public class Log{ public void before() { System.out.println("前置通知"); } public void after() { System.out.println("后置通知"); } } |
Xml配置
<bean id="service" class="com.service.ServiceImp"></bean> <bean id="log" class="com.log.Log"></bean> <aop:config> <!-- aspect关联log切面 --> <aop:aspect ref="log"> <!-- 切入点pointcut --> <aop:pointcut expression="execution(* com.service.*.*(..))" id="pointcut"/> <!-- before--前置通知 method调用的方法名 --> <aop:before method="before" pointcut-ref="pointcut"/> <!-- after--后置通知 method调用的方法名 --> <aop:after method="after" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> |
Test不变
- 3使用注解实现
业务类不变
Log类
//@Aspect 表示这个类是一个切面 @Aspect public class Log{ //@before 前置通知括号表达式声明切入点 @Before("execution(* com.service.*.*(..))") public void before() { System.out.println("----方法执行前----"); } //@after 后置通知括号表达式声明切入点 @After("execution(* com.service.*.*(..))") public void after() { System.out.println("---方法执行后----"); } //@around 环绕通知括号表达式声明切入点 @Around("execution(* com.service.*.*(..))") public void around(ProceedingJoinPoint pdp) throws Throwable { System.out.println("--环绕前--"); //获得将要执行目标对象方法的签名 System.out.println(pdp.getSignature()+"方法将要执行"); //执行目标对象方法 pdp.proceed(); System.out.println("--环绕后--"); } } |
Xml配置
<bean id="service" class="com.service.ServiceImp"></bean> <bean id="log" class="com.log.Log"></bean> <!-- aop:aspectj-autoproxy会自动寻找注解的AOP --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> |
测试类不变