前言
今天想给spring security框架服务之间校验权限的功能加一个免服务内部校验,找到了全局方法权限配置的配置类GlobalMethodSecurityConfiguration。看到了类和方法上的两句话
一个开启全局方法的配置,子类可以通过继承他来自定义默认值,但是必须要在子类上定义EnableGlobalMethodSecurity注解
子类可以override这个方法来提供一个不同的方法拦截器
最后实现效果是,定义一个类,只要继承这个类,这个类不用定义成Configuration,也不用将override的方法定义成bean,最终注册的bean是我们自定义的这个。
而且,除了这种方法以外,其他的方法(在启动类上加注解,在相同目录下定义一个子类但是加了Configuration注解或者Component注解)都没法覆盖
/**
* @author: 大胡子
*/
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MyGlobalMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override
public MethodInterceptor methodSecurityInterceptor(MethodSecurityMetadataSource methodSecurityMetadataSource) {
return new AspectJMethodSecurityInterceptor();
}
}
最后有两个问题
1 为什么EnableGlobalMethodSecurity注解+子类能覆盖
2 为什么其他方式就不能覆盖
为什么EnableGlobalMethodSecurity注解+子类能覆盖
spring应用上下文启动的几个主要步骤前面发过一次,看监听器可以找到主要步骤,这个问题的关键节点在刷新上下文阶段。
刷新上下文以入口类为起点,对所有的ComponentScan和Import注解做处理,代码见
ConfigurationClassParser.doProcessConfigurationClass,关键处理在源码里都有注释。
主要处理步骤是ComponentScan和Import的处理,在处理ComponentScan注解时会先找到我们自定义的类MyGlobalMethodSecurityConfiguration。在处理我们定义的这个类的过程中会递归处理我们类定义的所有注解。
我们类定义的注解只有一个@EnableGlobalMethodSecurity,且这个注解的内部套了两个import,所以在处理我们类的过程中会进处理Import的逻辑,但是和主要问题无关,省略。
这里都处理完后最后进到获取父类的逻辑
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
这里又被当做Configuration处理了一次,这一次,因为他的父类里定义了3个Bean,所以进了bean处理的逻辑。
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
这里在初始化beanMethod的时候,他会把这个方法的类定义从configClass参数里来读取,这个参数是子类的值。
最终实现了注释里的效果。
简单讲就是:
1 从我们自定义的Application里作为入口,开始执行componentScan的处理
2 scan到了我们自定义的MyGlobalMethodSecurityConfiguration,开始对这个类进行处理
3 处理MyGlobalMethodSecurityConfiguration完后开始处理我们自定义类的父类(处理当前类的所有注解后开始处理他的父类是spring定义的处理步骤)
4 处理父类GlobalMethodSecurityConfiguration的过程中发现这个类定义了3个Bean,开始处理bean
5 spring处理bean的逻辑是,把入口类当做bean的定义类,而不是当前处理的父类,所以最终我们的overrider方法能覆盖security提供的默认方法