扩展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 ...
随机推荐
- pyhton之路---面向对象
一.面向过程VS面向对象 面向过程: 优点:极大的降低了写程序的复杂度,只需要顺着执行的步骤,堆叠代码即可. 缺点:一套流水线或者流程就是来解决一个问题,代码就是牵一发而动全身 面 ...
- WEB前端面试真题 - 2000!大数的阶乘如何计算?
HTML5学堂-码匠:求某个数字的阶乘,很难吗?看上去这道题异常简单,却不曾想里面暗藏杀机,让不少前端面试的英雄好汉折戟沉沙. 面试真题题目 如何求"大数"的阶乘(如1000的阶乘 ...
- java最全时间类及用法
对于时间类,这篇主要说明各种现实情况下如何取值,怎么定向取值,得到自己想要的时间参数.在java中时间类主要有Date.Calendar,暂时只介绍 java.util.*下的时间类,对于java.s ...
- NDK调试
第一种(控制台输出): 1.配置好环境变量,这是为了方便起见.将你sdk和ndk的根目录放到环境变量path中.配置完成之后可以来个小检测: 在命令行分别输入adb和ndk-stack后点击回车,只要 ...
- CentOS服务器上的 git 包版本控制
本文衔接上文"记录一次无聊的(经历了Nodejs -> Shell -> C)的探索问题过程",服务器上git版本是1.8.3.1,使用的pm2来管理nodejs进程, ...
- 12 Nonlinear Transformation
一.二次假设 实际上线性假设的复杂度是受到限制的, 需要高次假设打破这个限制 假设数据不是线性可分的,但是可以被一个圆心在原点的圆分开, 需要我们重新设计基于该圆的PLA等算法吗 不用, 只需要通过非 ...
- 深入理解计算机系统chapter6
1. 2. 3. 存储器山
- 解决外部编辑器修改Eclipse文件延迟刷新【补充】
在之前的文章,使用gulp解决外部编辑器修改Eclipse文件延迟刷新,原理是用gulp把更改过的项目文件直接复制一份到Tomcat的webapp.root下, 现在补充另外一种方法,双击Server ...
- 风趣的JavaScript面向对象入门课程一
在我们程序猿界一直流传这这么一个joke,没女票我们可以new一个.没房子没票子没车子我们同样new一个!当然这听着更像是一种自嘲,毕竟我们程序猿都爱自嘲,哈哈,废话不多说,今天就由我带着你们来入Ja ...
- OpenVPN client端配置文件详细说明(转)
本文将介绍如何配置OpenVPN客户端的配置文件.在Windows系统中,该配置文件一般叫做client.ovpn:在Linux/BSD系统中,该配置文件一般叫做client.conf.虽然配置文件名 ...