Spring Aop Demo

来源:互联网 发布:中国gpa算法 编辑:程序博客网 时间:2024/06/06 12:25

    最近做项目时,接入了四个极其重要的外部接口。为了核对接口的准确性,把这四个接口的所有入参和返回值都打了日志。完全是重复性的机械劳动。端午节的时候回想这件事,发现AOP不正是职业解决这种事情的吗!而且用AOP打日志,原有的业务代码省去了日志代码,更加精简。

    先写了个AOP的demo体验下功能。

导入aop相关的依赖

    虽然没有显式引入cglib.jar,但是spring-aop-3.2.jar已经集成了cglib的功能。所以我的服务类没有实现接口,但依然能实现AOP的功能。

<properties>    <v.spring>3.2.0.RELEASE</v.spring>    <v.fastjson>1.1.36</v.fastjson></properties><dependencies>    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-core</artifactId>        <version>${v.spring}</version>    </dependency>    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-beans</artifactId>        <version>${v.spring}</version>    </dependency>    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-test</artifactId>        <version>${v.spring}</version>        <scope>test</scope>    </dependency>    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-context</artifactId>        <version>${v.spring}</version>    </dependency>    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-context-support</artifactId>        <version>${v.spring}</version>    </dependency>    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-aop</artifactId>        <version>${v.spring}</version>    </dependency>    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-aspects</artifactId>        <version>${v.spring}</version>    </dependency>    <dependency>        <groupId>com.alibaba</groupId>        <artifactId>fastjson</artifactId>        <version>${v.fastjson}</version>    </dependency></dependencies>

需要被切入的服务类

package com.jd.ls;import org.springframework.stereotype.Service;/** * Created by Administrator on 2016/6/8. */@Servicepublic class Hello {public String hello(String name) {String s = "hello, " + name;System.out.println(s);return s;}public void throwEx() {throw new NullPointerException();}}

AOP切面类

package com.jd.ls;import com.alibaba.fastjson.JSON;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;/** * Created by Administrator on 2016/6/8. */@Component@Aspectpublic class AopTest {//如果要设置多个切点可以使用 || 拼接@Pointcut("execution(* com.jd.ls.Hello.*(..))")private void anyMethod() {}@Before(value = "anyMethod()")public void doBefore(JoinPoint joinPoint) {System.out.println("前置通知");System.out.println("方法签名:" + joinPoint.getSignature().toLongString());}@AfterReturning(value = "anyMethod()", returning = "result")public void doAfter(JoinPoint jp, String result) {System.out.println("后置通知, result:\t" + result);}@After("anyMethod()")public void after() {System.out.println("最终通知");}@AfterThrowing(value = "anyMethod()", throwing = "e")public void doAfterThrow(JoinPoint joinPoint, Throwable e) {e.printStackTrace();}@Around("anyMethod()")public Object doBasicProfiling(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("进入环绕通知");System.out.println("目标类名称:" + joinPoint.getTarget().getClass().getName());System.out.println("方法签名:" + joinPoint.getSignature().toLongString());System.out.println("方法参数:");for (Object o : joinPoint.getArgs()) {System.out.println(o.getClass().getName() + ":\t" + o.toString());}System.out.println("target" + joinPoint.getTarget());System.out.println("staticPart:" + joinPoint.getStaticPart().toShortString());System.out.println("kind:" + joinPoint.getKind());System.out.println("sourceLocation:" + joinPoint.getSourceLocation());Object object = joinPoint.proceed();// 执行该方法System.out.println("执行结果" + JSON.toJSONString(object));System.out.println("退出方法");System.out.println(joinPoint.toLongString());return object;}}

    @Pointcut的路径参数指定了哪些类的哪些方法会作为切入点进行横向编程。而@Before,@After等注解则指定在什么时机织入代码。

spring配置文件

<?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/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">        <context:component-scan base-package="com.jd.ls"/>    <!-- 打开aop 注解 -->    <aop:aspectj-autoproxy proxy-target-class="true"/></beans>

单元测试

package com.jd.ls;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = {"classpath:spring-config.xml"})public class AppTest {@AutowiredHello hello;@Testpublic void testAop() {System.out.println("====================启动服务");hello.hello("world");System.out.println("====================终止服务");}@Testpublic void testAopEx() {System.out.println("====================启动服务");hello.throwEx();System.out.println("====================终止服务");}}

测试结果

    方法1的运行结果
====================启动服务进入环绕通知目标类名称:com.jd.ls.Hello方法签名:public java.lang.String com.jd.ls.Hello.hello(java.lang.String)方法参数:java.lang.String:worldtargetcom.jd.ls.Hello@4ac216staticPart:execution(Hello.hello(..))kind:method-executionsourceLocation:org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@1777b1前置通知方法签名:public java.lang.String com.jd.ls.Hello.hello(java.lang.String)hello, world执行结果"hello, world"退出方法execution(public java.lang.String com.jd.ls.Hello.hello(java.lang.String))最终通知后置通知, result:hello, world====================终止服务

    方法二的运行结果
====================启动服务进入环绕通知目标类名称:com.jd.ls.Hello方法签名:public void com.jd.ls.Hello.throwEx()方法参数:targetcom.jd.ls.Hello@4ac216staticPart:execution(Hello.throwEx())kind:method-executionsourceLocation:org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@1777b1前置通知方法签名:public void com.jd.ls.Hello.throwEx()最终通知java.lang.NullPointerExceptionat com.jd.ls.Hello.throwEx(Hello.java:18)at com.jd.ls.Hello$$FastClassByCGLIB$$3f78c6d2.invoke(<generated>)at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:50)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)at com.jd.ls.AopTest.doBasicProfiling(AopTest.java:59)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)at java.lang.reflect.Method.invoke(Method.java:597)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:65)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:42)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:50)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:55)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)at com.jd.ls.Hello$$EnhancerByCGLIB$$d4ecbb7c.throwEx(<generated>)at com.jd.ls.AppTest.testAopEx(AppTest.java:27)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)at java.lang.reflect.Method.invoke(Method.java:597)at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)at org.junit.runners.ParentRunner.run(ParentRunner.java:236)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)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:39)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)at java.lang.reflect.Method.invoke(Method.java:597)at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

    方法二抛了异常,异常的堆栈在AOP的切面代码里被输出。
0 0
原创粉丝点击