扩展Spring切面功能
概述
Spring的切面(Spring动态代理)在Spring中应用十分广泛,例如还有事务管理,重试等等。网上介绍SpringAop源码很多,这里假设你对SpringAop有基本的了解。如果你认为Spring代理类会创建多重代理,那说明你真的没了解。
需求背景
假设我现在想提供一个jar包,这个jar包会拦截制定注解方法,并做一些记录。这里要分析一下具体需求
拦截的注解是在方法上
如果注解是放在方法上,那么我们完全可以使用SpringAop的方式,通过自己定义一个注解,并对该注解进行拦截即可。这个不是本篇文章的重点,拦截制定注解的很简单。
拦截的注解是在类上
如果我们需要拦截的注解是类上,这里首先介绍第一个接口
Advisor
public interface Advisor {
Advice getAdvice();
boolean isPerInstance();
}
这个接口简单来说就是持有一个通知(Advice),但是一般不直接使用这个接口,因为这个对通知没有一个有效的过滤(当然如果你想对所有方法都进行拦截),所以一般是使用PointcutAdvisor,
public interface PointcutAdvisor extends Advisor {
Pointcut getPointcut();
}
这个接口就可以通过Pointcut做一些限制。为什么呢? 直接看AopUtils#findAdvisorsThatCanApply方法,这个方法就是从所有Advisor接口实现Bean选择对某个Class有效。
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
//!!!有兴趣的可以重点看一下重点看这里实现,就不大段贴代码了
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
好了,我们知道了,要想让我们的自定义的切面生效,首先,
第一步,创建一个Advisor
public class MyAdvisor implements PointcutAdvisor {
//这个是Spring提供的一个简单的通过注解来获取切点类
AnnotationMatchingPointcut annotationMatchingPointcut = new AnnotationMatchingPointcut(MyAop.class);
//这个是我们自己实现的继承于Advice,
MyAdvice myAdvice =new MyAdvice();
@Override
public Pointcut getPointcut() {
return annotationMatchingPointcut;
}
@Override
public Advice getAdvice() {
return myAdvice;
}
@Override
public boolean isPerInstance() {
return false;
}
//简单起见,就直接使用MethodInterceptor
class MyAdvice implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("haha");
return invocation.proceed();
}
}
第二步,定义一个开关注解,让我们的自定义切面生效
创建一个开关注解,就是一个套路,先创建一个开关注解,@import我们一个Bean注册类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyImporter.class)
public @interface EnableMyAop {
}
在Bean注册类中把我们的MyAdvisor注册进去吧
public class MyImporter implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
register(registry,MyAdvisor.class);
}
private void register(BeanDefinitionRegistry registry, Class<?> aopBeanFactoryPostClass) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(aopBeanFactoryPostClass);
registry.registerBeanDefinition(aopBeanFactoryPostClass.getSimpleName(),rootBeanDefinition);
}
}
至此,只要使用MyAop注解的类,在调用他的任何方法的时候(类内部调用不算),都会进入到我们的切面中。
小结
本篇文章是简单看了一下Spring Aop源码后,尝试自己进行扩展,因此可能不是最优的方法。不过希望能起到抛砖迎玉作用,在其基础上可以做很多有很意思的事情。如果有兴趣可以进一步研究spring自己的Advice,Pointcut的实现类。
扩展Spring切面功能的更多相关文章
- 扩展Spring切面
概述 Spring的切面(Spring动态代理)在Spring中应用十分广泛,例如还有事务管理,重试等等.网上介绍SpringAop源码很多,这里假设你对SpringAop有基本的了解.如果你认为Sp ...
- Spring Boot2.0+中,自定义配置类扩展springMVC的功能
在spring boot1.0+,我们可以使用WebMvcConfigurerAdapter来扩展springMVC的功能,其中自定义的拦截器并不会拦截静态资源(js.css等). @Configur ...
- 实现WebMvcConfigurer接口扩展Spring MVC的功能
前言: 先查看WebMvcConfigurer接口中都定义了哪些内容 public interface WebMvcConfigurer { default void configurePathMat ...
- [02] Spring主要功能模块概述
1.Spring主要功能模块 1.1 Core Container Spring的核心容器模块,其中包括: Beans Core Context SpEL Beans和Core模块,是框架的基础部 ...
- Spring 核心功能演示
Spring 核心功能演示 Spring Framework 简称 Spring,是 Java 开发中最常用的框架,地位仅次于 Java API,就连近几年比较流行的微服务框架 SpringBoot, ...
- Spring切面编程步骤
什么是面向切面编程 面向对象的编程主要注重核心业务,而面向切面编程主要关注一些不是核心的业务,但又是必须的辅助功能,比如一个完整的系统中,记录平时系统运行时抛出的异常,需要我们去记录,以便我们对系统尽 ...
- 第5章 Spring Boot 功能
Spring Boot 功能 本节将会介绍Spring Boot的一些细节. 在这里,您可以了解您将要使用和自定义的主要功能. 如果还没有准备好,您可能需要阅读第二部分“入门指南”和第三部分“使用 S ...
- 使用C++扩展Python的功能 转自:http://blog.csdn.net/magictong/article/details/8897568#comments
使用C++扩展Python的功能 环境 VS2005Python2.5.4 Windows7(32位) 简介 长话短说,这里说的扩展Python功能与直接用其它语言写一个动态链接库,然后让Python ...
- Postman 是一个非常棒的Chrome扩展,提供功能强大的API & HTTP 请求调试
Postman 是一个非常棒的Chrome扩展,提供功能强大的API & HTTP 请求调试 需要FQ才能安装,使用时应该不用FQ了,除非使用postman的历史记录功能: 非常棒的C ...
随机推荐
- 从GO内存模型与调用协议理解defer closure的坑
资料参考: 官网defer介绍: https://blog.golang.org/defer-panic-and-recover 深入解析go: 多值返回: https://tiancaiamao.g ...
- Hibernate的Configuration对象的configure()方法
Configuration configuration=new Configuration(); configuration.configure(); 在Hibernate底层实现configure( ...
- Oracle日期时间操作大全
本文出自:http://www.cnblogs.com/hl3292/archive/2010/11/03/1868159.html oracle sql日期比较: 共三部分: 第一部分:oracle ...
- 教你在Java接口中定义方法
基本上所有的Java教程都会告诉我们Java接口的方法都是public.abstract类型的,没有方法体的. 但是在JDK8里面,你是可以突破这个界限的哦. 假设我们现在有一个接口:TimeClie ...
- Java实现CORS跨域请求
问题 使用前后端分离模式开发项目时,往往会遇到这样一个问题 -- 无法跨域获取服务端数据 这是由于浏览器的同源策略导致的,目的是为了安全.在前后端分离开发模式备受青睐的今天,前端和后台项目往往会在不同 ...
- day09<面向对象+>
面向对象(多态的概述及其代码体现) 面向对象(多态中的成员访问特点之成员变量) 面向对象(多态中的成员访问特点之成员方法) 面向对象(多态中的成员访问特点之静态成员方法) 面向对象(超人的故事) 面向 ...
- 保存数据到sdcard中去
这里只贴上核心的代码:其它自行脑补!
- 利用Docker快速创建Nginx负载均衡节点
本文版权归博客园和作者吴双本人共同所有 转载和爬虫请注明原文地址 www.cnblogs.com/tdws 一.Self-Host Kestrel 1. 在vs2017中新建dotnet core2. ...
- 【DDD】领域驱动设计实践 —— UI层实现
前面几篇blog主要介绍了DDD落地架构及业务建模战术,后续几篇blog会在此基础上,讲解具体的架构实现,通过完整代码demo的形式,更好地将DDD的落地方案呈现出来.本文是架构实现讲解的第一篇,主要 ...
- 静态页面如何实现 include 引入公用代码
一直以来,我司的前端都是用 php 的 include 函数来实现引入 header .footer 这些公用代码的,就像下面这样: <!-- index.php --> <!DOC ...