Spring AOP的使用实例

Spring AOP可以实现对指定的类的公共方法进行拦截,添加前置和后置处理,甚至对方法调用进行mock替换。内部实现原理是使用的JAVA的动态代理(针对具有接口的类)或者CGLIB(针对没有接口的类)。

下面以一个具体的代码例子来演示Spring AOP的使用。

1. 新建一个idea的maven工程

pom.xml添加AOP需要的依赖包:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.1</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

2.Spring AOP的配置

在resources目录下新增applicationContext.xml文件,进行Spring AOP的配置。

<?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-4.3.xsd">

    <bean id="userService" class="io.spring2go.corespring.command.aop.UserServiceImpl"></bean>
    <bean id="logAdvisor" class="io.spring2go.corespring.command.aop.LogAdvisor"></bean>

    <aop:config>
        <aop:aspect ref="logAdvisor">
            <aop:pointcut expression="execution(* io.spring2go.corespring.command.aop.*.*(..))" id="pointUserService"/>
            <aop:before method="doBefore" pointcut-ref="pointUserService"/>
            <aop:after method="doAfter" pointcut-ref="pointUserService"/>
            <aop:around method="doAround" pointcut-ref="pointUserService"/>
            <aop:after-returning method="doReturn" pointcut-ref="pointUserService"/>
            <aop:after-throwing method="doThrowing" throwing="ex"  pointcut-ref="pointUserService"/>
        </aop:aspect>
    </aop:config>
</beans>

3.进行AOP处理的接口和实现类

接口:

package io.spring2go.corespring.command.aop;

public interface UserService {
    public String fsindUserById(int id);
}

实现类:

package io.spring2go.corespring.command.aop;

public class UserServiceImpl implements UserService{

    @Override
    public String fsindUserById(int id) {
        System.out.println("find user by id["+id+"]....");
        if(id <= 0){
            throw new IllegalArgumentException("user is not exist!");
        }
        return "tom";
    }
}

4.AOP代理类

package io.spring2go.corespring.command.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class LogAdvisor {

    /**
     * 在核心业务执行前执行,不能阻止核心业务的调用。
     * @param joinPoint
     */
    public 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
     */
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("-----doAround().invoke-----");
        System.out.println(" 此处可以做类似于Before Advice的事情");

        String targetName = pjp.getTarget().getClass().getName();
        String methodName = pjp.getSignature().getName();
        Object[] arguments = pjp.getArgs();

        Class targetClass = Class.forName(targetName);
        Method[] method = targetClass.getMethods();
        Map<String,Object> map = new HashMap<>();
        for (Method m : method) {
            if (m.getName().equals(methodName)) {
                Class[] tmpCs = m.getParameterTypes();
            }
        }
        //调用核心逻辑
        Object retVal = pjp.proceed();

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

    /**
     * 核心业务逻辑退出后(包括正常执行结束和异常退出),执行此Advice
     * @param joinPoint
     */
    public 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
     */
    public 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
     */
    public 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()------");
    }
}

5. 客户端运行

package io.spring2go.corespring.command.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestMain {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) ac.getBean("userService");
        userService.fsindUserById(1);
        System.out.println("=============");

        try {
            userService.fsindUserById(0);
        } catch (Exception e) {
            System.out.println("异常捕获");
        }
    }
}

 

posted @ 2020-07-08 20:21  windpoplar  阅读(622)  评论(0编辑  收藏  举报