17学Java之AOP以及装饰器模式 (3)

170 阅读2分钟

前置简介

上一节:juejin.cn/post/686591…

上一节说了JDK动态代理和基于CGLIB的动态代理,下面说一下动态代理在Spring中的使用,

我们将在下面的demo里使用 spring boot + aop + 注解 实现一个具备缓存功能的接口。

首先在项目中引用spring-boot-starter-aop

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>2.0.0.RELEASE</version>
</dependency>

创建一个Biz

@Service
public class DataBiz {
    public List<String> getList() {
        return Arrays.asList("1","2","3");
    }
}

创建一个Controller

@RestController
public class DataController {
    @Autowired
    private DataBiz dataBiz;

    @GetMapping("/hello")
    public List<String> getList() {
        return dataBiz.getList();
    }
}

首先我们根据上面的两个类可以看到,我们通过访问一个http://ip:端口/hello的地址,

获取一个list返回结果,

下面我们有一个需求,就是只有第一次访问这个接口的时候,真正调用了biz的方法获取返回值,

其余的时候,都是通过缓存中拿,

这个需求我们用spring aop来实现以下,看下面创建的类。

创建Cache注解

@Retention(RetentionPolicy.RUNTIME)
public @interface Cache {
    
}

这个类用于配合切面使用,告诉切面需要拦截哪些方法,就是一个标记。

创建切面类

// 标记这是一个切面类
@Aspect
// 告诉Spring这个类需要进行bean管理
@Configuration
public class CacheAspect {

    Map<String,Object> cache = new HashMap<>();

	// 环绕通知,并且拦截带有Cache的方法,在方法的前后进行切面处理
    @Around("@annotation(Cache)")
    public Object cache(ProceedingJoinPoint point) throws Throwable {
    	// 获取方法信息
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 获取方法名称
        String methodName = signature.getName();
        // 从缓存中获取方法的返回值
        Object cacheValue = cache.get(methodName);
        // 如果缓存中有 就返回缓存值
        if(cacheValue != null) {
            System.out.println("从缓存中返回");
            return cacheValue;
        } else {
        	// 否则调用真实的方法,获取返回值缓存,并返回
            System.out.println("从方法中返回");
            cacheValue = point.proceed();
            cache.put(methodName,cacheValue);
            return cacheValue;
        }
    }
}

最后,在biz类的方法里加上我们定义的Cache注解。

@Service
public class DataBiz {
    @Cache
    public List<String> getList() {
        return Arrays.asList("1","2","3");
    }
}

完成上面的步骤我们基于一个Spring Aop实现的缓存功能就实现了,看下面效果。

上面我们用到的AOP切面是 @Around 环绕通知,

还有 @After (方法执行后) @Before (方法执行前) 等使用方式,

可以查看Spring Aop官方文档,做更多的了解docs.spring.io/spring/docs…

最后要注意的是,Spring的Aop默认是基于JDK的动态代理的,但是Spring Boot 引入Aop的时候,

自动将配置改成了基于Cglib的代理,这个请多注意。

本篇代码示例:github.com/qiaomengnan…