面向切面编程可以实现在不修改原来代码的情况下,增加我们所需的业务处理逻辑,比如:添加日志。本文AOP实例是基于Aspect Around注解实现的,我们需要在调用API函数的时候,统计函数调用的具体信息,包括:函数签名,传入参数,函数处理时间,异常信息拦截等, @Around是可以同时在所拦截方法的前后执行一段逻辑,可以满足我们的需求。

目标对象

目标对象是一个客户管理服务,下面分别是其服务接口定义和具体业务逻辑实现。

API

public interface CustomerManagerService {
void addCustomer(String customer) throws CustomeExistException;
}

Implementation

public class customerManager implements CustomerManagerService {

    private List<String> list = Lists.newArrayList();

    public void addCustomer(String customer) throws CustomeExistException {
if (list.contains(customer)) {
throw new CustomeExistException("Customer exists, repeat operation");
}
list.add(customer);
}
@Override
public String toString() {
return "customerManager{" +
"list=" + list +
'}';
}
}

切面类代理

切面代理可以实现对客户管理服务的控制,在切面类中定义Advice函数,设定切面要增加的业务逻辑。APIProxy定义了一个简单的切面类around advice,作用范围为com.mj.spring.aop.api包下面所有的函数, 当作用域内的函数被调用时会执行aroundAdvice中的业务逻辑。

@Aspect
public class APIProxy { private final static Log LOGGER = LogFactory.getLog(APIProxy.class); //切面应用范围是在com.mj.spring.aop.api下面所有的接口函数
@Around("execution(* com.mj.spring.aop.api..*.*(..))")
public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { Signature signature = proceedingJoinPoint.getSignature();
String args = Arrays.toString(proceedingJoinPoint.getArgs()); long start = System.currentTimeMillis();
try {
proceedingJoinPoint.proceed();
} catch (Exception e) {
if (e instanceof CustomeExistException) {
LOGGER.warn(e.getMessage());
}
LOGGER.error(String.format("Method:%s call failed parameter input:%s",
signature,
args), e);
} finally {
LOGGER.info(String.format("method:%s parameter input:%s carry_out_time:%s ms",
signature, args, System.currentTimeMillis() - start));
}
}
}

ProceedingJoinPoint接口

ProceedingJoinPoint接口提供了很多实用的函数,便于用户获取应用切面点函数具体的信息。下面四个接口是我们用的比较多的:

  1. Object proceed() throws Throwable; 调用要拦截的方法
  2. Object proceed(Object[] var1) throws Throwable;调用要拦截的方法,可以自定义传入参数
  3. Object[] getArgs();获取拦截方法的传入参数
  4. Signature getSignature();获取拦截方法的方法签名

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.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<!-- 使能AOP-->
<aop:aspectj-autoproxy/> <!--声明切面类 -->
<bean id="apiProxy" class="com.mj.spring.aop.aspect.APIProxy"></bean>
<!-- 声明customerManager bean-->
<bean id="customerManagerService" class="com.mj.spring.aop.impl.customerManager"></bean> </beans>

测试类

public class customerManagerTest {
private ApplicationContext applicationContext = null; @Before
public void setUp() throws Exception {
applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
} @Test
public void should_print_normal_log_info_when_add_a_customer() throws Exception {
CustomerManagerService customerManagerService = (CustomerManagerService) applicationContext.getBean("customerManagerService");
customerManagerService.addCustomer("Mengya");
} @Test
public void should_print_warn_log_info_when_add_a_same_customer_twice() throws Exception {
CustomerManagerService customerManagerService = (CustomerManagerService) applicationContext.getBean("customerManagerService");
customerManagerService.addCustomer("Mengya");
customerManagerService.addCustomer("Mengya");
}
}

运行第一个Test,接口调用信息:

2015-09-24 18:25:42,000 INFO [com.mj.spring.aop.aspect.APIProxy] - method:void com.mj.spring.aop.api.CustomerManagerService.addCustomer(String)  parameter input:[Mengya] carry_out_time:0 ms

运行第二个Test,异常报错信息会被拦截下来:

2015-09-24 18:26:58,885 INFO [com.mj.spring.aop.aspect.APIProxy] - method:void com.mj.spring.aop.api.CustomerManagerService.addCustomer(String)  parameter input:[Mengya] carry_out_time:0 ms
2015-09-24 18:26:58,886 WARN [com.mj.spring.aop.aspect.APIProxy] - Customer exists, repeat operation
2015-09-24 18:26:58,888 ERROR [com.mj.spring.aop.aspect.APIProxy] - Method:void com.mj.spring.aop.api.CustomerManagerService.addCustomer(String) call failed parameter input:[Mengya]
com.mj.spring.aop.impl.CustomeExistException: Customer exists, repeat operation
at com.mj.spring.aop.impl.customerManager.addCustomer(customerManager.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
at com.mj.spring.aop.aspect.APIProxy.aroundAdvice(APIProxy.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy12.addCustomer(Unknown Source)
at com.mj.spring.aop.impl.customerManagerTest.should_print_normal_log_info_when_add_a_same_customer_twice(customerManagerTest.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
2015-09-24 18:26:58,905 INFO [com.mj.spring.aop.aspect.APIProxy] - method:void com.mj.spring.aop.api.CustomerManagerService.addCustomer(String) parameter input:[Mengya] carry_out_time:20 ms

Console窗口日志无法打印问题

使用log4j有时候我们会遇到日志无法在concole窗口打印的问题,console窗口提示日志配置异常。

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

解决这个问题很简单,和src平级目录创建log4j.properties文件,输入下面内容,就可以解决这个问题了

log4j.rootLogger=INFO,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

Conslusion

本文讲解了Spring AOP在函数接口调用性能分析及其日志处理方面的应用,希望能够给大家带来一些帮助和启发。

Spring AOP在函数接口调用性能分析及其日志处理方面的应用的更多相关文章

  1. 基于Spring AOP实现对外接口的耗时监控

    AOP是Spring的核心,Spring不但自身对多种框架的集成是基于AOP,并且以非常方便的形式暴露给普通使用者.以前用AOP不多,主要是因为它以横截面的方式插入到主流程中,担心导致主流程代码不够清 ...

  2. Spring框架下的 “接口调用、MVC请求” 调用参数、返回值、耗时信息输出

    主要拦截前端或后天的请求,打印请求方法参数.返回值.耗时.异常的日志.方便开发调试,能很快定位到问题出现在哪个方法中. 前端请求拦截,mvc的拦截器 import java.util.Date; im ...

  3. spring aop 动态代理批量调用方法实例

    今天项目经理发下任务,需要测试 20 个接口,看看推送和接收数据是否正常.因为对接传输的数据是 xml 格式的字符串,所以我拿现成的数据,先生成推送过去的数据并存储到文本,以便验证数据是否正确,这时候 ...

  4. spring aop实现拦截接口请求打印日志

    在spring配置 1编写自己的注解类 2.编写注解解析类 3.配置spring aop代理 (下面我使用注解 如使用配置 配置切点即可,有两种代理默认jdk代理 设置true 为cglib代理) / ...

  5. Spring AOP中使用@Aspect注解 面向切面实现日志横切功能详解

    引言: AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一 ...

  6. PHP性能分析 - ngnx日志分析

    最终结果展示图: 图解:响应时间在40ms以内的请求数占请求总量的7%,40到80ms的的请求数占32.9%,依次类推... 性能问题有很多种可能,普通的情况通过xhprof可查得主要的性能损耗.但有 ...

  7. Spring AOP实现声明式事务代码分析

    众所周知,Spring的声明式事务是利用AOP手段实现的,所谓"深入一点,你会更快乐",本文试图给出相关代码分析. AOP联盟为增强定义了org.aopalliance.aop.A ...

  8. Mysql聚合函数count(*) 的性能分析

    你首先要明确的是,在不同的 MySQL 引擎中,count(*) 有不同的实现方式. MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,效率很高: 而 ...

  9. platform_device和platform_driver的注册过程,及probe函数何时调用的分析 ⭐⭐⭐

    add  platform_device之后,需要注意的一个地方是这里,add是通过系统初始化里边调用platform_add_devices把所有放置在板级platform_device数组中的所有 ...

随机推荐

  1. ShellExecuteA

    //第三个参数是指令,可以是一个可执行程序(后面不能加参数).有默认打开方式的文件.路径.网址.各种协议地址如迅雷ftp邮箱ed2k等 MessageBoxA

  2. Paxos算法分析

    作者:吴香伟 发表于 2014/09/30 版权声明:可以任意转载,转载时务必以超链接形式标明文章原始出处和作者信息以及版权声明 一致性问题 如上图所示,服务器Ai(i=1,2,..5)组成存储集群, ...

  3. 搭建selenium自动化环境步骤

    1.下载pythonhttps://www.python.org/downloads/2.安装2.X或者3.X3.添加环境变量python和pip(与python一起安装)4.下载setuptools ...

  4. win10 virtualbox5, ubuntu16.04 xshell5配合使用

    这个搭配很好用,各软件的安装很容易,ubuntu安装进virtualbox后安装增强功能,然后将网络连接方式改为桥接,直接改为桥接就可以了,其他的不用变,这个比以前的版本好用多了.这个桥接解决了宿主机 ...

  5. android nio

    Android开发进阶之NIO非阻塞包(二) 有关Android NIO我们主要分为三大类,ByteBuffer.FileChannel和SocketChannel.由于篇幅原因今天Android12 ...

  6. javascript typeof

    https://zhidao.baidu.com/question/79159257.html typeof 运算符返回一个用来表示表达式的数据类型的字符串. 可能的字符串有:"number ...

  7. 【线段树】bzoj3995 [SDOI2015]道路修建

    线段树每个结点维护5个域: 整个区间的MST. 将两个左端点连通,两个右端点不连通,整个区间内选择2*(r-l+1)-2条边的最小生成森林,有两个连通块. 将两个右端点连通,两个左端点不连通,整个区间 ...

  8. zabbix中文乱码解决方法

    将windows下的字体文件Fonts\simkai.ttf上传到zabbix的WEB目录下的fonts目录下 修改zabbix的PHP配置 将原来的DejaVuSans更改成simkai vim / ...

  9. SQL Server 全文索引创建

    在安装数据库管理系统SQL Server 后,默认情况下全文索引的服务是没有开启的 ,所以首先需要先开启服务,在sql server配置管理器中 (sql server configuration M ...

  10. 黑马程序员-c语言-类型强制转换

    强制转换的条件: 1.当所声明的类型不能满足所符值的变量时,需要转换声明的类型,以便能够存储变量. 例如:short存储的最大值为32767,但是所要符值大于32767时,short类型不符合,需要转 ...