spring aop应用 简单的一个例子

1 篇文章 0 订阅
1 篇文章 0 订阅

最近在做接口,需要将接口调用做个记录,记录接口调用的入参、出参、执行之间等详细信息,因此就想到了切面,自定义一个注解,将含有欧该注解的方法的调用都记录下来。(最一开始想用的是webservice的拦截器,但是webservice拦截器不能将入参和出参报文对应上,因此只能用spring aop,用拦截器来做。)

具体使用方法:

1.依赖jar包导入:项目用的spring版本比较低2.5.6,所以jar包版本也比较低

aspectjweaver.jar和aspectjrt.jar可以通过这个链接下载:http://www.eclipse.org/aspectj/

下载步骤:

2.配置拦截器代理扫描:

<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

3.自定义注解:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CalledRecord {
    public String desc() default "";
}

4.定义拦截器:

package com.dcits.base.aspect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.dcits.base.bean.CalledRecordBean;
import com.dcits.base.ws.CalledRecordAspectWS;
import com.webservices.org.annotation.CalledRecord;

/**
 * 记录带有CalledRecord注解的接口调用信息
 * @Description
 */
@Aspect
@Component
public class CalledRecordAspect {
    private static final Logger logger = Logger.getLogger(CalledRecordAspect.class);
    
    @Autowired
    private CalledRecordAspectWS CalledRecordAspectWSImpl;
    
    /**
     * 拦截含有CalledRecord注解的方法,并记录相关信息
     */
    @Pointcut("@annotation(com.webservices.org.annotation.CalledRecord)")
    public void calledRecord() {
    }

    @Around("calledRecord()")
    public Object handle(ProceedingJoinPoint joinPoint) throws Throwable {
        logger.info("进入了CalledRecordAspect.handle方法");
        CalledRecordBean crd;
        Object retVal = null;;
        try {
            crd = preHandle(joinPoint);
            long startTime = System.currentTimeMillis();
            retVal = joinPoint.proceed();
            long endTime = System.currentTimeMillis();
            crd.setStartTime(formatTime(startTime));
            crd.setEndTime(formatTime(endTime));
            crd.setDuration("" + (endTime - startTime));
            String respParam = postHandle(retVal);
            crd.setOutArgs(respParam);
            int num = CalledRecordAspectWSImpl.saveCalledRecord(crd);
            logger.info("保存了"+num+"条数据");
        }catch(Exception e) {
            logger.info("保存接口调用详情异常");
            e.printStackTrace();
        }
        return retVal;
    }

    /**
     * 格式化时间格式 long-->yyyy-MM-dd HH:mm:ss
     */
    public String formatTime(long time) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(time);
        return sdf.format(date);
    }

    /**
     * 处理入参
     */
    private CalledRecordBean preHandle(ProceedingJoinPoint joinPoint) throws SecurityException, NoSuchFieldException {
        CalledRecordBean crd = new CalledRecordBean();
        StringBuffer inArgs = new StringBuffer();
        Object[] args1 = joinPoint.getArgs();
        for (Object arg : args1) {
            inArgs.append(arg.toString());
        }
        crd.setInArgs(inArgs.toString());
        Signature signature = joinPoint.getSignature();
        String methodName = signature.getName();
        crd.setMethodName(methodName);
        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod();
        Annotation[] annotations = targetMethod.getAnnotations();
        for (int i = 0; i < annotations.length; i++) {
            if (annotations[i].annotationType().equals(CalledRecord.class)) {
                CalledRecord call = (CalledRecord) annotations[i];
                crd.setMethodDesc(call.desc());
                break;
            }
        }
        return crd;
    }

    /**
     * 处理出参
     */
    private String postHandle(Object retVal) {
        return retVal.toString();
    }

}
spring aop分两层,外层是spring框架层面的,内层就是开发人员自定义的了,我们写的就是内层的拦截器。

按照上面的步骤就能定义一个简单的拦截器了。

遇到的问题:

1.漏掉@Component注解,导致拦截器一直未被调用   **********

2.handle方法未写返回值,导致方法被调用后调用者接收到的返回值为null  *************。

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring AOP(面向切面编程)是Spring框架中的一个关键特性,它允许开发者在不修改原始代码的情况下,通过切入点和通知来实现横切关注点的功能。 下面我给出一个简单Spring AOP例子来解释其工作原理。 假设我们有一个Spring应用程序,其中包含一个名为UserService的服务类,负责处理用户相关的业务逻辑,比如验证用户、保存用户等操作。 首先,我们需要定义一个切入点(Join point),用来确定在UserService的哪些方法上我们需要应用AOP。例如,我们可以将切入点定义为所有保存用户的方法。 其次,我们需要定义通知(Advice),它是在切入点之前或之后执行的代码逻辑。例如,我们可以定义一个前置通知(Before advice)来在保存用户之前验证用户的信息。 接下来,我们需要将切入点和通知组合起来,创建一个切面(Aspect)。切面是一个类,它包含了切入点和通知,并指定了在切入点上何时应用通知。在我们的例子中,切面可以是一个名为ValidationAspect的类,其中定义了一个前置通知方法。 最后,我们需要将切面配置为Spring容器的一部分。我们可以通过在Spring的配置文件中声明一个<aop:aspectj-autoproxy>元素来完成这一配置。这样,当应用程序启动时,Spring容器会自动为我们创建切面。 当我们调用UserService的保存用户方法时,Spring AOP就会根据切面配置来决定是否将前置通知应用于该方法。如果切入点的条件匹配,前置通知会提前执行验证用户的逻辑。 通过这个例子,我们可以看到,Spring AOP提供了一种非侵入式的方式来增强代码的功能,使得我们可以在不修改原始代码的情况下,通过切入点和通知来实现横切关注点的功能。这样可以提高代码的模块化和可重用性,降低代码的复杂性。 ### 回答2: Spring AOP(面向切面编程)是Spring框架中的一个重要特性,用于在不改变原有代码的情况下增加功能和耦合性。它通过将主要的业务逻辑(核心业务)与横切关注点(如日志记录、事务管理等)分离来实现。 下面是一个可以帮助理解Spring AOP例子:假设我们有一个简单应用程序,其中包含一个Service层的类来处理用户的注册请求。在用户注册成功后,我们希望自动生成一个欢迎邮件,同时在控制台中记录下来。这里就可以使用Spring AOP来实现。 首先,我们需要定义一个切面类来处理横切关注点,例如记录日志和发送欢迎邮件。切面类应该实现通知(Advice)。在这个例子中,我们可以使用@Before通知来在目标方法执行之前发送欢迎邮件,并使用@After通知在目标方法执行之后记录日志。 接下来,在Spring配置文件中进行配置。我们需要定义一个切点(Pointcut),以告诉Spring在哪些方法上应用切面。在这个例子中,我们可以使用execution()表达式定义一个切点,以匹配Service层中的所有方法。 最后,在Service层的类中,我们需要使用一个@Autowired注解将切面类注入到目标类中。这样,当Service层中的方法被调用时,切面类就会自动执行。 通过这个例子,我们可以清楚地看到Spring AOP如何帮助我们将横切关注点与核心业务分离,并在不改变原有代码的情况下实现功能的增强。这样,我们可以更容易地维护、扩展和重用代码,提高系统的可维护性和灵活性。 ### 回答3: Spring AOPSpring框架中的一个关键特性,它提供了一种方法来通过动态代理技术在应用程序的不同层之间添加横切关注点。 举一个简单例子来说明Spring AOP的用法。假设我们有一个电商网站,我们想要在用户购买商品之前验证用户的身份。我们可以通过使用Spring AOP来实现这个功能。 首先,我们需要定义一个切面(Aspect),用于对购买商品的方法进行拦截和处理。我们可以创建一个类,并在其中定义一个方法,使用@Before注解来标记它。在这个方法中,我们可以编写代码来验证用户的身份,例如检查用户是否已登录。 然后,我们需要配置Spring AOP,告诉它在哪些类和方法上应用这个切面。我们可以在Spring配置文件中使用<aop:aspectj-autoproxy>元素来启用自动代理,然后在<aop:config>元素中定义切面的位置和应用规则。 接下来,我们需要在我们的购买商品方法上添加一个标记(Annotation),以告诉Spring AOP对该方法应用切面。我们可以在方法上添加一个自定义的注解,例如@RequiresAuthentication。然后,我们可以在切面的方法中使用@Pointcut注解来指定切入点,即哪些方法应该被拦截。 最后,我们可以测试这个例子。我们可以创建一个控制器(Controller),其中有一个方法用于购买商品。当用户调用该方法时,Spring AOP会自动拦截并执行切面中的逻辑,验证用户的身份是否合法。如果用户未登录或身份验证失败,可以抛出异常或返回错误信息。 综上所述,Spring AOP一个非常强大的功能,可以帮助我们在应用程序中实现横切关注点,提高代码的模块化和可维护性。以上是一个简单例子,展示了如何使用Spring AOP来验证用户身份。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值