分类
代码

Spring AOP 小例子

AOP 面向切面编程
适用场景:日志记录、执行前后拦截等

步骤
0. 引入相关依赖
1. 编写实际业务方法
2. 编写切面类
2.1 定义连接点
2.2 使用通知
3. 调用业务方法

0. 依赖

 <dependencies>
        <!-- test -->
        <dependency>
            <groupid>junit</groupid>
            <artifactid>junit</artifactid>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupid>org.springframework</groupid>
            <artifactid>spring-test</artifactid>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupid>ch.qos.logback</groupid>
            <artifactid>logback-classic</artifactid>
        </dependency>
        <dependency>
            <groupid>org.slf4j</groupid>
            <artifactid>jcl-over-slf4j</artifactid>
        </dependency>

        <dependency>
            <groupid>org.springframework</groupid>
            <artifactid>spring-core</artifactid>
            <exclusions>
                <exclusion>
                    <groupid>commons-logging</groupid>
                    <artifactid>commons-logging</artifactid>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupid>org.springframework</groupid>
            <artifactid>spring-context</artifactid>
        </dependency>

        <dependency>
            <groupid>org.aspectj</groupid>
            <artifactid>aspectjrt</artifactid>
        </dependency>
        <dependency>
            <groupid>org.aspectj</groupid>
            <artifactid>aspectjweaver</artifactid>
        </dependency>

    </dependencies>

版本自行去找最新版

配置:
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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component -scan base-package="com.youthlin.demo"></context:component>

    <!-- aop -->
    <aop:aspectj -autoproxy></aop:aspectj>

</beans>

Logback:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- https://logback.qos.ch/manual/layouts.html#coloring -->
            <pattern>
                %d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) [%15.15t]%X{sessionId} %cyan(%-40.40logger{39}) : %m%n
            </pattern>
        </encoder>
    </appender>

    <logger name="org" level="warn"></logger>

    <root level="${log.level:-debug}">
        <appender -ref ref="STDOUT"></appender>
    </root>
</configuration>

1. 业务方法

在这个类写实际的业务方法。

package com.youthlin.demo.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * 创建者: youthlin.chen 日期: 17-3-26.
 */
@Service
public class HelloService {
    private static final Logger LOGGER = LoggerFactory.getLogger(HelloService.class);

    @SuppressWarnings("SameParameterValue")
    public String sayHello(String name) {
        LOGGER.debug("in say hello method");
        return "Hello, " + name;
    }

    public void voidFun() {
        LOGGER.debug("void method.");
        throw new RuntimeException("");
    }
}

2. 切面通知

在这个类定义要拦截的方法及拦截的操作。

package com.youthlin.demo.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.util.Arrays;

/**
 * 创建者: youthlin.chen 日期: 17-3-26.
 */
@Aspect//声明切面
@Component//让 Spring 扫描到
public class LogAop {
    private static final Logger LOGGER = LoggerFactory.getLogger(LogAop.class);

    @SuppressWarnings("unused")
    @Pointcut(value = "execution(* com.youthlin.demo.service.*.*(..))")//定义连接点
    private void pointcut() {
    }

    @Around("pointcut()")//环绕通知
    public Object processTx(ProceedingJoinPoint pjp) throws Throwable {
        LOGGER.debug("环绕通知 之前");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Object proceed = pjp.proceed();
        stopWatch.stop();
        LOGGER.debug("环绕通知 之后. {}ms", stopWatch.getTotalTimeMillis());
        return proceed;
    }

    @Before("pointcut()")//前置通知
    public void before(JoinPoint jp) {
        Object[] args = jp.getArgs();
        LOGGER.debug("前置通知 {} args = {}", jp.getSignature(), Arrays.toString(args));
    }

    @AfterReturning(pointcut = "pointcut()", returning = "result")//后置返回通知
    public void afterReturning(Object result) {
        LOGGER.debug("后置返回通知 result = {}", result);
    }

    @AfterThrowing(pointcut = "pointcut()", throwing = "throwable")//后置异常通知
    public void afterThrowing(Throwable throwable) {
        LOGGER.debug("后置异常通知", throwable);
    }

    @After("pointcut()")//后置通知
    public void after() {
        LOGGER.debug("后置通知");
    }
}

3. 测试

package com.youthlin.demo.test;

import com.youthlin.demo.service.HelloService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

/**
 * 创建者: youthlin.chen 日期: 17-3-26.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/app.xml"})
public class AopTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(AopTest.class);
    @Resource
    private HelloService service;

    @Test
    public void logTest() {
        LOGGER.debug("{}", service.sayHello("Lin"));
    }

    @Test(expected = RuntimeException.class)
    public void aVoid() {
        service.voidFun();
    }

}

测试结果:

2017-03-26 20:40:56.063 DEBUG [           main] com.youthlin.demo.aop.LogAop             : 环绕通知 之前
2017-03-26 20:40:56.073 DEBUG [           main] com.youthlin.demo.aop.LogAop             : 前置通知 void com.youthlin.demo.service.HelloService.voidFun() args = []
2017-03-26 20:40:56.134 DEBUG [           main] com.youthlin.demo.service.HelloService   : void method.
2017-03-26 20:40:56.135 DEBUG [           main] com.youthlin.demo.aop.LogAop             : 后置通知
2017-03-26 20:40:56.138 DEBUG [           main] com.youthlin.demo.aop.LogAop             : 后置异常通知
java.lang.RuntimeException: 
	at com.youthlin.demo.service.HelloService.voidFun(HelloService.java:22)
	at com.youthlin.demo.service.HelloService$$FastClassBySpringCGLIB$$8a47ffe4.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
	at com.youthlin.demo.aop.LogAop.processTx(LogAop.java:37)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:47)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:52)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)
	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.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656)
	at com.youthlin.demo.service.HelloService$$EnhancerBySpringCGLIB$$340752f6.voidFun(<generated>)
	at com.youthlin.demo.test.AopTest.aVoid(AopTest.java:30)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
2017-03-26 20:40:56.151 DEBUG [           main] com.youthlin.demo.aop.LogAop             : 环绕通知 之前
2017-03-26 20:40:56.151 DEBUG [           main] com.youthlin.demo.aop.LogAop             : 前置通知 String com.youthlin.demo.service.HelloService.sayHello(String) args = [Lin]
2017-03-26 20:40:56.151 DEBUG [           main] com.youthlin.demo.service.HelloService   : in say hello method
2017-03-26 20:40:56.158 DEBUG [           main] com.youthlin.demo.aop.LogAop             : 环绕通知 之后. 0ms
2017-03-26 20:40:56.158 DEBUG [           main] com.youthlin.demo.aop.LogAop             : 后置通知
2017-03-26 20:40:56.158 DEBUG [           main] com.youthlin.demo.aop.LogAop             : 后置返回通知 result = Hello, Lin
2017-03-26 20:40:56.158 DEBUG [           main] com.youthlin.demo.test.AopTest           : Hello, Lin
输出
输出

完整代码:https://github.com/YouthLin/examples/tree/master/example-aop


发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

[/鼓掌] [/难过] [/调皮] [/白眼] [/疑问] [/流泪] [/流汗] [/撇嘴] [/抠鼻] [/惊讶] [/微笑] [/得意] [/大兵] [/坏笑] [/呲牙] [/吓到] [/可爱] [/发怒] [/发呆] [/偷笑] [/亲亲]