概述

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切面功能的更多相关文章

  1. 扩展Spring切面

    概述 Spring的切面(Spring动态代理)在Spring中应用十分广泛,例如还有事务管理,重试等等.网上介绍SpringAop源码很多,这里假设你对SpringAop有基本的了解.如果你认为Sp ...

  2. Spring Boot2.0+中,自定义配置类扩展springMVC的功能

    在spring boot1.0+,我们可以使用WebMvcConfigurerAdapter来扩展springMVC的功能,其中自定义的拦截器并不会拦截静态资源(js.css等). @Configur ...

  3. 实现WebMvcConfigurer接口扩展Spring MVC的功能

    前言: 先查看WebMvcConfigurer接口中都定义了哪些内容 public interface WebMvcConfigurer { default void configurePathMat ...

  4. [02] Spring主要功能模块概述

    1.Spring主要功能模块   1.1 Core Container Spring的核心容器模块,其中包括: Beans Core Context SpEL Beans和Core模块,是框架的基础部 ...

  5. Spring 核心功能演示

    Spring 核心功能演示 Spring Framework 简称 Spring,是 Java 开发中最常用的框架,地位仅次于 Java API,就连近几年比较流行的微服务框架 SpringBoot, ...

  6. Spring切面编程步骤

    什么是面向切面编程 面向对象的编程主要注重核心业务,而面向切面编程主要关注一些不是核心的业务,但又是必须的辅助功能,比如一个完整的系统中,记录平时系统运行时抛出的异常,需要我们去记录,以便我们对系统尽 ...

  7. 第5章 Spring Boot 功能

    Spring Boot 功能 本节将会介绍Spring Boot的一些细节. 在这里,您可以了解您将要使用和自定义的主要功能. 如果还没有准备好,您可能需要阅读第二部分“入门指南”和第三部分“使用 S ...

  8. 使用C++扩展Python的功能 转自:http://blog.csdn.net/magictong/article/details/8897568#comments

    使用C++扩展Python的功能 环境 VS2005Python2.5.4 Windows7(32位) 简介 长话短说,这里说的扩展Python功能与直接用其它语言写一个动态链接库,然后让Python ...

  9. Postman 是一个非常棒的Chrome扩展,提供功能强大的API & HTTP 请求调试

    Postman 是一个非常棒的Chrome扩展,提供功能强大的API & HTTP 请求调试   需要FQ才能安装,使用时应该不用FQ了,除非使用postman的历史记录功能:   非常棒的C ...

随机推荐

  1. 从GO内存模型与调用协议理解defer closure的坑

    资料参考: 官网defer介绍: https://blog.golang.org/defer-panic-and-recover 深入解析go: 多值返回: https://tiancaiamao.g ...

  2. Hibernate的Configuration对象的configure()方法

    Configuration configuration=new Configuration(); configuration.configure(); 在Hibernate底层实现configure( ...

  3. Oracle日期时间操作大全

    本文出自:http://www.cnblogs.com/hl3292/archive/2010/11/03/1868159.html oracle sql日期比较: 共三部分: 第一部分:oracle ...

  4. 教你在Java接口中定义方法

    基本上所有的Java教程都会告诉我们Java接口的方法都是public.abstract类型的,没有方法体的. 但是在JDK8里面,你是可以突破这个界限的哦. 假设我们现在有一个接口:TimeClie ...

  5. Java实现CORS跨域请求

    问题 使用前后端分离模式开发项目时,往往会遇到这样一个问题 -- 无法跨域获取服务端数据 这是由于浏览器的同源策略导致的,目的是为了安全.在前后端分离开发模式备受青睐的今天,前端和后台项目往往会在不同 ...

  6. day09<面向对象+>

    面向对象(多态的概述及其代码体现) 面向对象(多态中的成员访问特点之成员变量) 面向对象(多态中的成员访问特点之成员方法) 面向对象(多态中的成员访问特点之静态成员方法) 面向对象(超人的故事) 面向 ...

  7. 保存数据到sdcard中去

    这里只贴上核心的代码:其它自行脑补!

  8. 利用Docker快速创建Nginx负载均衡节点

    本文版权归博客园和作者吴双本人共同所有 转载和爬虫请注明原文地址 www.cnblogs.com/tdws 一.Self-Host Kestrel 1. 在vs2017中新建dotnet core2. ...

  9. 【DDD】领域驱动设计实践 —— UI层实现

    前面几篇blog主要介绍了DDD落地架构及业务建模战术,后续几篇blog会在此基础上,讲解具体的架构实现,通过完整代码demo的形式,更好地将DDD的落地方案呈现出来.本文是架构实现讲解的第一篇,主要 ...

  10. 静态页面如何实现 include 引入公用代码

    一直以来,我司的前端都是用 php 的 include 函数来实现引入 header .footer 这些公用代码的,就像下面这样: <!-- index.php --> <!DOC ...