用户工具


aop面向切面编程,拦截指定函数,在调用前,后作一些其他操作

spring中有2种方式实现AOP

  1. 通过注解方式(建议使用,简单)
  2. 通过xml配置文件方式

mvn 依赖

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.1.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.1.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.11</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.11</version>
        </dependency>

方式1(注解)

要拦截的函数

package aop.annotation;


public class HelloWorld {
    public void sayHello() {
        System.out.println("hello world");
    }
}

拦截后要执行的操作

package aop.annotation;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class Annotation {

    // 定义拦截函数,aspect函数的作用域相当于一个id
    @Pointcut("execution(* aop.annotation.HelloWorld.sayHello(..))")
    public void aspectBefore(){	}

    @Pointcut("execution(* aop.annotation.HelloWorld.sayHello(..))")
    public void aspectAfter(){	}

    /**
     * aspectBefore函数对应的函数被拦截前执行,doBefore函数
     */
    @Before("aspectBefore()")
    private void doBefore(JoinPoint joinPoint) {
        System.out.println("-----doBefore().invoke-----");
    }

    /**
     * aspectAfter函数对应的函数被拦截前执行,doBefore函数
     */
    @After("aspectAfter()")
    private void doAfter(JoinPoint joinPoint) {
        System.out.println("-----doAfter().invoke-----");
    }
}

main函数

    public static void main(String[] args) {
        BeanFactory factory = new ClassPathXmlApplicationContext("spring_aop_annotation.xml");
        HelloWorld userManager = (HelloWorld)factory.getBean("helloWorld");
        userManager.sayHello();
    }

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/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <!-- 激活组件扫描功能,在包cn.ysh.studio.spring.aop及其子包下面自动扫描通过注解配置的组件 -->
    <context:component-scan base-package="aop.annotation"/>
    <!-- 激活自动代理功能 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

    <bean id="helloWorld" class="aop.annotation.HelloWorld"/>
</beans>

方式2(xml配置)

要拦截的函数

package aop.xml;

public class UserManagerImpl {

    public String findUserById(int userId) {
        System.out.println("---------HelloWorld.sayHello()--------");
        if (userId <= 0) {
            throw new IllegalArgumentException("该用户不存在!");
        }
        return "张三";
    }
}

拦截后要执行的操作

package aop.xml;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Advice通知类
 * 测试after,before,around,throwing,returning Advice.
 * @author Admin
 *
 */
public class XMLAdvice {

    /**
     * 在核心业务执行前执行,不能阻止核心业务的调用。
     * @param joinPoint
     */
    private void doBefore(JoinPoint joinPoint) {
        System.out.println("-----doBefore().invoke-----");
        System.out.println(" 此处意在执行核心业务逻辑前,做一些安全性的判断等等");
        System.out.println(" 可通过joinPoint来获取所需要的内容");
        System.out.println("-----End of doBefore()------");
    }

    /**
     * 手动控制调用核心业务逻辑,以及调用前和调用后的处理,
     *
     * 注意:当核心业务抛异常后,立即退出,转向After Advice
     * 执行完毕After Advice,再转到Throwing Advice
     * @param pjp
     * @return
     * @throws Throwable
     */
    private Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("-----doAround().invoke-----");
        System.out.println(" 此处可以做类似于Before Advice的事情");

        //调用核心逻辑
        Object retVal = pjp.proceed();

        System.out.println(" 此处可以做类似于After Advice的事情");
        System.out.println("-----End of doAround()------");
        return retVal;
    }

    /**
     * 核心业务逻辑退出后(包括正常执行结束和异常退出),执行此Advice
     * @param joinPoint
     */
    private void doAfter(JoinPoint joinPoint) {
        System.out.println("-----doAfter().invoke-----");
        System.out.println(" 此处意在执行核心业务逻辑之后,做一些日志记录操作等等");
        System.out.println(" 可通过joinPoint来获取所需要的内容");
        System.out.println("-----End of doAfter()------");
    }

    /**
     * 核心业务逻辑调用正常退出后,不管是否有返回值,正常退出后,均执行此Advice
     * @param joinPoint
     */
    private void doReturn(JoinPoint joinPoint) {
        System.out.println("-----doReturn().invoke-----");
        System.out.println(" 此处可以对返回值做进一步处理");
        System.out.println(" 可通过joinPoint来获取所需要的内容");
        System.out.println("-----End of doReturn()------");
    }

    /**
     * 核心业务逻辑调用异常退出后,执行此Advice,处理错误信息
     * @param joinPoint
     * @param ex
     */
    private void doThrowing(JoinPoint joinPoint,Throwable ex) {
        System.out.println("-----doThrowing().invoke-----");
        System.out.println(" 错误信息:"+ex.getMessage());
        System.out.println(" 此处意在执行核心业务逻辑出错时,捕获异常,并可做一些日志记录操作等等");
        System.out.println(" 可通过joinPoint来获取所需要的内容");
        System.out.println("-----End of doThrowing()------");
    }
}

main函数

public static void main(String[] args) {
        BeanFactory factory = new ClassPathXmlApplicationContext("spring_aop_xml.xml");
        UserManagerImpl userManager = (UserManagerImpl)factory.getBean("userManager");

        //可以查找张三
        userManager.findUserById(1);

        System.out.println("=====我==是==分==割==线=====");

        try {
            // 查不到数据,会抛异常,异常会被AfterThrowingAdvice捕获
            userManager.findUserById(0);
        } catch (IllegalArgumentException e) {
        }
    }

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-3.0.xsd">-->

<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-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

    <bean id="userManager" class="aop.xml.UserManagerImpl"/>
    <bean id="xmlHandler" class="aop.xml.XMLAdvice" />
    <aop:config>
        <!-- 切面: 拦截某个pointcut后要执行的函数 -->
        <aop:aspect id="aspect" ref="xmlHandler">
            <!-- 切入点: 拦截某个函数 -->
            <aop:pointcut id="pointUserMgr" expression="execution(* aop.xml.UserManagerImpl.findUserById(..))"/>
            <!-- 拦截某个函数后(执行函数之前):执行切面(aspect)中的doBefore函数-->
            <!--<aop:before method="doBefore"  pointcut-ref="pointUserMgr"/>-->
            <!-- 拦截某个函数后(执行函数之后):执行切面(aspect)中的doAfter函数-->
            <aop:after method="doAfter"  pointcut-ref="pointUserMgr"/>
            <aop:around method="doAround"  pointcut-ref="pointUserMgr"/>
            <aop:after-returning method="doReturn"  pointcut-ref="pointUserMgr"/>
            <aop:after-throwing method="doThrowing" throwing="ex" pointcut-ref="pointUserMgr"/>

        </aop:aspect>
    </aop:config>
</beans>