概述

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切面-单线程简单权限判定

    spring切面简单模拟用户权限判定 需求: 游客:仅注册用户 用户:修改,注册 管理员:删除,查询,修改,注册 1,文件配置 导包 src下创建applicationContext.xml文件配置如 ...

  3. Spring 切面可以应用五种类型的通知?

    Spring 切面可以应用五种类型的通知: before:前置通知,在一个方法执行前被调用. after: 在方法执行之后调用的通知,无论方法执行是否成功. after-returning: 仅当方法 ...

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

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

  5. spring切面编程AOP 范例一

    参照网上的spring AOP编程实例进行配置,但是碰到了几个坑.这篇文章重点讲解一下我踩过的两个坑: 1.使用@Service自动装配的时候,基础扫描包配置要正确: 2.xml中切面配置中的exec ...

  6. Spring切面通知执行的顺序(Advice Order)

    问题描述 如果在Spring的程序中同时定义了环绕通知(Around)和前置通知(Before)..那么,有以下问题: 1.怎么让两个切面通知都起作用 2.或者让两者切面按自己指定的顺序进行执行? 3 ...

  7. Spring切面编程步骤

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

  8. Spring切面编程实践【原创】

    定义 什么叫Spring面向切面编程(AOP),请自行百度,这边就不做详细介绍了. 场景 有两个对象,字典和工程信息Bean,每次新增或修改对象时,记录新增和修改的时间. 基类定义 package m ...

  9. Dubbo实践(五)扩展Spring Schema

    先回顾Dubbo实践(一)中定义的dubbo-provider.xml: <?xml version="1.0" encoding="UTF-8"?> ...

随机推荐

  1. 在mvc4中多语言建站的实例

    环境:vs2012 asp.net mvc4. 实现方式:resource 资源文件,根据路由规则中Lang参数来判断载入哪种语言方式 在网上找到了相关资料,顺便自己做了个练习,新建工程之类的步骤就免 ...

  2. Line云端全自动加好友机器人

    一个 LINE 帐号可以加入 5,000 名好友,让这些 5,000 名好友收到 LINE 的主动提醒,好友会看到我的头像.主页照片.姓名与状态消息等,这种行为称为 LINE 的曝光. 如果我们要针对 ...

  3. shell脚本自动清理服务器日志、图片等信息

    在做性能测试的时候,linux服务器时常会产生大量数据,如日志信息,图片信息,文件信息等,压测一段时间后,导致服务器磁盘空间暂满而崩溃,每天手动清理比较麻烦, 利用shell脚本自动清理,脚本如下 1 ...

  4. c++const关键字---15

    原创博文,转载请标明出处--周学伟 http://www.cnblogs.com/zxouxuewei/ const是一个C++语言的限定符,它限定一个变量不允许被改变.使用const在一定程度上可以 ...

  5. 【高级算法】遗传算法解决3SAT问题(C++实现)

    转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46910079 1 SAT问题描写叙述 命题逻辑中合取范式 (CNF) 的可满足性问 ...

  6. Eclipse cdt解决github导入的项目无法打开声明的bug (cannot open declaration)

    概述: 我利用eclipse 的git插件clone github上的远程项目(C++)到本地时遇到一个问题:clone下来的项目没有C++特性,无法使用open declaration等操作,下面是 ...

  7. pip更换下载源(提升下载速度)

    经常在使用Python的时候需要安装各种模块,而pip是很强大的模块安装工具,但是由于国外官方pypi经常被墙,导致不可用,或者下载速度很慢,所以我们最好是将自己使用的pip源更换一下,这样就能解决被 ...

  8. IIS日志清理(VBS版,JS版)

    IIS默认日志记录在C:\WINDOWS\system32\LogFiles,时间一长,特别是子站点多的服务器,一个稍微有流量的网站,其日志每天可以达到上百兆,这些文件日积月累会严重的占用服务器磁盘空 ...

  9. iis下的php环境的配置

    1. 参考园友文章: http://www.cnblogs.com/zengxiangzhan/archive/2010/03/05/1679286.html 2.另外还可以参考一下文章: http: ...

  10. MVC的简单分页【转】

    传值的方式是通过querystring. 本例子是把整需要的数据查出来再分页的,因为当时做的时候数据很少,只有几十条. 如果数据多的话,可以在存储过程里分页,只是要传页码和记录的条数过来. 控制器: ...