手把手教你学会用Spring AOP

        用了Spring很长时间了,一直想写些AOP的东西,但一直没有空闲,直到如今项目稍微进入正轨了,才赶忙写写。废话很少说,先从AOP入门开始,后面再介绍AOP的原理(JDK动态代码和CGLIB动态代码的知识)。注:该部分适合于未接触过Spring AOP的童鞋,若是是AOP老手,请直接绕过,不用打招呼^^php

       请尊重做者劳动成果,转载请标明原文连接:html

       http://www.javashuo.com/article/p-qwsupnnn-ez.htmljava

1、环境准备web

       1.在Spring官网(地址见本文最后)下载springframework相关jar包,下载完后的jar包里面会包含aop/aspects/context/beans/core等相关的jar。spring

       2.在AspectJ官网(AOP依赖包,地址见本文最后)下载AspectJ.jar,目前最新稳定版是1.9.1。express

       3.在Eclipse中,新建java project,而后在根目录下新建lib目录,并将第1步中下载的jar包所有copy到lib目录下。app

       4.将第2步下载的AspectJ.jar解压,并将解压后的aspectjrt.jar、aspectjweaver.jar两个jar包copy到lib目录下。eclipse

       5.项目右键-build path-libraries-add jars,而后选择lib中的所有jar包,点击肯定。webapp

       6.在项目根目录下新建配置文件applicationContext.xml,文件内容暂时为空,到此环境准备完毕。ide

2、代码示例

       了解AOP的童鞋都知道,使用AOP的方式有多少,这里建议使用配置文件的方式,可以减小对代码的注入,比较简洁。

       1.新建切面类

package test; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; public class AspectAdvice { /** * 前置通知 * * @param jp */
    public void doBefore(JoinPoint jp) { System.out.println("===========进入before advice============ \n"); System.out.print("准备在" + jp.getTarget().getClass() + "对象上用"); System.out.print(jp.getSignature().getName() + "方法进行对 '"); System.out.print(jp.getArgs()[0] + "'进行删除!\n\n"); System.out.println("要进入切入点方法了 \n"); } /** * 后置通知 * * @param jp * 链接点 * @param result * 返回值 */
    public void doAfter(JoinPoint jp, String result) { System.out.println("==========进入after advice=========== \n"); System.out.println("切入点方法执行完了 \n"); System.out.print(jp.getArgs()[0] + "在"); System.out.print(jp.getTarget().getClass() + "对象上被"); System.out.print(jp.getSignature().getName() + "方法删除了"); System.out.print("只留下:" + result + "\n\n"); } /** * 环绕通知 * * @param pjp * 链接点 */
    public void doAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("===========进入around环绕方法!=========== \n"); // 调用目标方法以前执行的动做
        System.out.println("调用方法以前: 执行!\n"); // 调用方法的参数
        Object[] args = pjp.getArgs(); // 调用的方法名
        String method = pjp.getSignature().getName(); // 获取目标对象
        Object target = pjp.getTarget(); // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
        Object result = pjp.proceed(); System.out.println("输出:" + args[0] + ";" + method + ";" + target + ";" + result + "\n"); System.out.println("调用方法结束:以后执行!\n"); } /** * 异常通知 * * @param jp * @param e */
    public void doThrow(JoinPoint jp, Throwable e) { System.out.println("删除出错啦"); } }
View Code

       2.新建业务类

package test; public class AspectBusiness { public String delete(String obj) { System.out.println("==========调用切入点:" + obj + "说:你敢删除我!===========\n"); return obj + ":瞄~"; } public String add(String obj) { System.out.println("================这个方法不能被切。。。============== \n"); return obj + ":瞄~ 嘿嘿!"; } public String modify(String obj) { System.out.println("=================这个也设置加入切吧====================\n"); return obj + ":瞄改瞄啊!"; } }
View Code

       3.在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 definitions here -->



    <!-- 声明一个业务类 -->
    <bean id="aspectBusiness" class="test.AspectBusiness" />

    <!-- 声明通知类 -->
    <bean id="aspectAdvice" class="test.AspectAdvice" />

    <aop:config>
        <aop:aspect id="businessAspect" ref="aspectAdvice">
            <!-- 配置指定切入的对象 -->
            <aop:pointcut id="point_cut" expression="execution(* test.*.*(..))" />
            <!-- 只匹配add方法做为切入点 <aop:pointcut id="except_add" expression="execution(* test.*.add(..))" />
             -->

            <!-- 前置通知 -->
            <aop:before method="doBefore" pointcut-ref="point_cut" />
            <!-- 后置通知 returning指定返回参数 -->
            <aop:after-returning method="doAfter" pointcut-ref="point_cut" returning="result" />
            <aop:around method="doAround" pointcut-ref="point_cut"/>
            <aop:after-throwing method="doThrow" pointcut-ref="point_cut" throwing="e"/>
        </aop:aspect>
    </aop:config>
</beans>
View Code

       4.新建测试类

package test; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class StringTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); AspectBusiness business = (AspectBusiness) context.getBean("aspectBusiness"); business.delete("猫"); } }
View Code

3、运行结果

       运行结果以下所示:

===========进入before advice============ 准备在class test.AspectBusiness对象上用delete方法进行对 '猫'进行删除! 要进入切入点方法了 ===========进入around环绕方法!=========== 调用方法以前: 执行! ==========调用切入点:猫说:你敢删除我!=========== 输出:猫;delete;test.AspectBusiness@3b69e7d1;猫:瞄~ 调用方法结束:以后执行! ==========进入after advice=========== 切入点方法执行完了 猫在class test.AspectBusiness对象上被delete方法删除了只留下:null

       这样AOP的示例就算完成了,本篇先不介绍切面、通知、切入点等的相关概念了,这些概念在百度上可谓信手拈来,若是有不了解,能够自行百度。本篇先写到这里,后续再介绍AOP的相关原理。

 

       参考资料:

       1. Spring官网:https://spring.io/

       2. Spring5.0官网下载地址:https://repo.spring.io/webapp/#/artifacts/browse/tree/General/libs-release-local/org/springframework/spring/5.0.0.RELEASE

       3. AspectJ最新稳定版官网下载地址:http://www.eclipse.org/aspectj/downloads.php#stable_release