一、背景

在学习spring security的时候,有了解过一下官方的文档,Post Processing Configured Objects 这个玩意,主要的意思。Spring Security 的 Java 配置不会公开其配置的每个对象的每个属性。这简化了大多数用户的配置。毕竟,如果每个属性都公开,用户可以使用标准 bean 配置。
虽然有充分的理由不直接公开每个属性,但用户可能仍然需要更高级的配置选项。为了解决这个问题,Spring Security 引入了,它可以用来修改或替换 Java 配置创建的许多对象实例。例如,如果要在 filtersecurity拦截器上配置 filtersecuritypublicauthorizationsuccess 属性,则可以使用。
如下的意思:当有个对象实例实现了FilterSecurityInterceptor,进行对象postProcess增强的时候被修改属性咯,达到一种可以让开发者自动增强的效果。

@Override
protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {public <O extends FilterSecurityInterceptor> O postProcess(O fsi) {fsi.setPublishAuthorizationSuccess(true);return fsi;}});
}

这里有两个很关键的字眼,修改或者替换掉Java创建的对象,意思就是当有一个对象在调用postProcess方法后可以给予争强,或者直接替换掉,换一个新的对象来处理哦。和之前了解的BeanProcess、BeanFactoryProcess 概念上是差不多的意思,都是针对实例进行争强的处理,这里的ObjectPostProcessor 和前面两个有区别,不是在spring 声明周期内进行的,这个是通过人工手工的调用处理。有点那种自己创建了一个new Bean ,然后(自己调用spring的方法去初始化、去填充属性)手工的设置这个对象的信息。


二、spring security-ObjectPostProcessor

2.1 基本概念

spring security 中有很多的Bean都不是通过自动的扫描创建的,而是运行时动态的创建,而这个ObjectPostProcessor进行为了运行时动态让开发者、让spring security框架本身进行相关数据的扩展和填充。这里就有了一个基本的问题?假设,没有了自动扫描,我们如何创建一个Bean呢? 前提一下:这里是在spring 容器初始化完成之后哦,不能在spring 初始化之前自己编程注入BeanDefine 。
脱离spring容器创建的类实例,如何把spring容器内的对象注入到这些类实例内呢?

步骤

  • 创建一个实例
  • 这里就是一些回调,后置处理器增强 Initialize the given raw bean, applying factory callbacks such as setBeanName and setBeanFactory, also applying all bean post processors (including ones which might wrap the given raw bean).

org.springframework.beans.factory.config.AutowireCapableBeanFactory#initializeBean

  • Bean 属性填充 Populate the given bean instance through applying after-instantiation callbacks and bean property post-processing (e.g. for annotation-driven injection).

    org.springframework.beans.factory.config.AutowireCapableBeanFactory#autowireBean
    其实这个都是从Spring 官方自动配置工程中copy 下来的解释,非常的容易理解,当时自我本身还是要对于spring的容器机制有一定的了解哟,才能轻松方便的了解ObjectPostProcessor的实现原理。

伪代码

Class ObjectEg implements InitializingBean{@Autowireprivate Person person;public void afterPropertiesSet() {log.info(person.getName());}
}
1、new ObjectEg
2、autowireBeanFactory.initializeBean(objectEg,object.toString())
3、autowireBeanFactory.autowireBean(objectEg)eg:因此这个对象Person 被自动装配咯,afterPropertiesSet这个生命周期对象的方法也会被处理哦

2.2 spring 实现自动手动装配

spring security 在配置@EableSecurity 的时候会自动的将 EnableGlobalAuthentication 装配,然后装配@AuthenticationConfiguration,然后导入了@Import(ObjectPostProcessorConfiguration.class),也就是本文中重点了解的一个对象.

Spring Configuration that exports the default ObjectPostProcessor. This class is not intended to be imported manually rather it is imported automatically when using EnableWebSecurity or EnableGlobalMethodSecurity. 本类不是为了自动装配的场景,而是在这两个注解中使用来手动进行Spring Bean 手动装配的处理哦!

ObjectPostProcessorConfiguration

org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration

@Configuration(proxyBeanMethods = false)
public class ObjectPostProcessorConfiguration {@Beanpublic ObjectPostProcessor<Object> objectPostProcessor(AutowireCapableBeanFactory beanFactory) {return new AutowireBeanFactoryObjectPostProcessor(beanFactory);}
}

AutowireBeanFactoryObjectPostProcessor

对象自动装配处理的后置处理器哦,通过手动的进行管理
Allows registering Objects to participate with an AutowireCapableBeanFactory’s post processing of Aware methods, InitializingBean.afterPropertiesSet() , and DisposableBean.destroy().
代码非常的简单通过手工的进行spring 生命周期的管理,对于有类似spring security这里配置动态需求比较高的场景需要自己手动的进行装配的可以学习了解整个功能的实现原理哦。
org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor

final class AutowireBeanFactoryObjectPostProcessorimplements ObjectPostProcessor<Object>, DisposableBean, SmartInitializingSingleton {private final Log logger = LogFactory.getLog(getClass());private final AutowireCapableBeanFactory autowireBeanFactory;private final List<DisposableBean> disposableBeans = new ArrayList<>();private final List<SmartInitializingSingleton> smartSingletons = new ArrayList<>();AutowireBeanFactoryObjectPostProcessor(AutowireCapableBeanFactory autowireBeanFactory) {Assert.notNull(autowireBeanFactory, "autowireBeanFactory cannot be null");this.autowireBeanFactory = autowireBeanFactory;}/** (non-Javadoc)** @see* org.springframework.security.config.annotation.web.Initializer#initialize(java.* lang.Object)*/@SuppressWarnings("unchecked")public <T> T postProcess(T object) {if (object == null) {return null;}T result = null;try {result = (T) this.autowireBeanFactory.initializeBean(object,object.toString());}catch (RuntimeException e) {Class<?> type = object.getClass();throw new RuntimeException("Could not postProcess " + object + " of type " + type, e);}this.autowireBeanFactory.autowireBean(object);if (result instanceof DisposableBean) {this.disposableBeans.add((DisposableBean) result);}if (result instanceof SmartInitializingSingleton) {this.smartSingletons.add((SmartInitializingSingleton) result);}return result;}/* (non-Javadoc)* @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated()*/@Overridepublic void afterSingletonsInstantiated() {for (SmartInitializingSingleton singleton : smartSingletons) {singleton.afterSingletonsInstantiated();}}/** (non-Javadoc)** @see org.springframework.beans.factory.DisposableBean#destroy()*/public void destroy() {for (DisposableBean disposable : this.disposableBeans) {try {disposable.destroy();}catch (Exception error) {this.logger.error(error);}}}}

2.3 spring security 随处可见的手动装配

这个是spring security的入口配置类,这里重点关注WebSecurityConfiguration中的手动装配的逻辑,有了之前AutowireBeanFactoryObjectPostProcessor 的了解,对于这个装配逻辑的理解还是十分的简单

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,SpringWebMvcImportSelector.class,OAuth2ImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {/*** Controls debugging support for Spring Security. Default is false.* @return if true, enables debug support with Spring Security*/boolean debug() default false;
}

WebSecurityConfiguration

org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration,当前类中自动注入了**private **ObjectPostProcessor objectObjectPostProcessor;用来初始化spring security中非常重要的对象 WebSecurity **webSecurity,**一个默认的实现WebSecurityConfigurerAdapter。

WebSecurity的创建

1、Autowired 优先级由于@Bean 因此先调用了这个自动注入的方法创建了webSecurity
org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration#setFilterChainProxySecurityConfigurer,重点是WebSecurity的创建

/*** Sets the {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>}* instances used to create the web configuration.** @param objectPostProcessor the {@link ObjectPostProcessor} used to create a* {@link WebSecurity} instance* @param webSecurityConfigurers the* {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>} instances used to* create the web configuration* @throws Exception*/@Autowired(required = false)public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)throws Exception {//自动创建了一个WebSecurity,处理内部的注入依赖,通过objectPostProcessor处理 AutowireBeanFactoryObjectPostProcessorwebSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));if (debugEnabled != null) {webSecurity.debug(debugEnabled);}webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);Integer previousOrder = null;Object previousConfig = null;for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {Integer order = AnnotationAwareOrderComparator.lookupOrder(config);if (previousOrder != null && previousOrder.equals(order)) {throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of "+ order + " was already used on " + previousConfig + ", so it cannot be used on "+ config + " too.");}previousOrder = order;previousConfig = config;}for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {webSecurity.apply(webSecurityConfigurer);}this.webSecurityConfigurers = webSecurityConfigurers;}

WebSecurityConfigurerAdapter的创建

WebSecurityConfigurerAdapter中有一些自动注入的Autowired的属性

/*** Creates the Spring Security Filter Chain* @return the {@link Filter} that represents the security filter chain* @throws Exception*/@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)public Filter springSecurityFilterChain() throws Exception {boolean hasConfigurers = webSecurityConfigurers != null&& !webSecurityConfigurers.isEmpty();if (!hasConfigurers) {//新创建一个WebSecurityConfigurerAdapter 然后使用objectObjectPostProcessor,自动配置初始化信息// AutowireBeanFactoryObjectPostProcessorWebSecurityConfigurerAdapter adapter = objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {});webSecurity.apply(adapter);}//这里是整个过滤链条创建的入口哦return webSecurity.build();}

2.4 spring security 配置

Add this annotation to an @Configuration class to have the Spring Security configuration defined in any WebSecurityConfigurer or more likely by extending the WebSecurityConfigurerAdapter base class and overriding
这个是官方的实例demo 源码里面的,WebSecurity、HttpSecurity都是通过objectObjectPostProcessor手动的初始配置处理的,这种动态性对于spring security本身工程还是扩展性提供了良好的扩展哦,因此回到了例子,Post Processing Configured Objects 官方文档里面说的那样子。

   @Configuration@EnableWebSecuritypublic class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring()// Spring Security should completely ignore URLs starting with /resources/.antMatchers("/resources/**");}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/public/**").permitAll().anyRequest().hasRole("USER").and()// Possibly more configuration ....formLogin() // enable form based log in// set permitAll for all URLs associated with Form Login.permitAll();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth// enable in memory based authentication with a user named "user" and "admin".inMemoryAuthentication().withUser("user").password("password").roles("USER").and().withUser("admin").password("password").roles("USER", "ADMIN");}// Possibly more overridden methods ...}

三、总结

看了看spring security的文档,对于ObjectPostProcessor的实现进行了大概的了解哦,不错的周末。

spring 之 ObjectPostProcessor相关推荐

  1. 透过源码详解Spring Security 初始化流程

    Spring Security在3.2版本之后支持Java Configuration,即:通过Java编码形式配置Spring Security,可不再依赖XML文件配置,本文采用Java Conf ...

  2. spring security自定义指南

    序 本文主要研究一下几种自定义spring security的方式 主要方式 自定义UserDetailsService 自定义passwordEncoder 自定义filter 自定义Authent ...

  3. Spring Security 实战:Spring Boot 下的自动配置

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | 公众号「码农小胖哥」 1. 前言 我们在前几篇 ...

  4. 一起搞清楚 Spring Security 中的 UserDetails

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 170元买400元书的机会又来啦! 1. 前言 前一篇介绍了 Spring Security ...

  5. spring security源码分析心得

    看了半天的文档及源码,终于理出了spring-security的一些总体思路,spring security主要分认证(authentication)和授权(authority). 1.认证authe ...

  6. spring security默认登录页面登录用户,和自定义数据源

    一.默认登录页面 请求 /hello 接口,在引入 spring security 之后会先经过一些列过滤器 在请求到达 FilterSecurityInterceptor时,发现请求并未认证.请求拦 ...

  7. Spring Security——实现登录后跳转到登录前页面

    基本概念 暂无. 官方文档 https://docs.spring.io/spring-security/site/docs/5.3.1.BUILD-SNAPSHOT/reference/html5/ ...

  8. Spring Security源码解析(一)——认证和鉴权

    目录 认证过程 AuthenticationManager Authentication AbstractAuthenticationToken UsernamePasswordAuthenticat ...

  9. Spring Security源码解析(二)——引入

    目录 Spring Security的引入 AuthenticationConfiguration WebSecurityConfiguration 引入 FilterChain. 设置FilterC ...

最新文章

  1. 【OpenCV 】Remapping 重映射¶
  2. Css Font 详细研究
  3. pearson相关系数_Pearson(皮尔逊)相关系数
  4. Hive之 hive的三种使用方式(CLI、HWI、Thrift)
  5. 机器视觉光源学习总结——平行背光源
  6. uos系统虚拟机_UOS开箱体验
  7. CCIE学习(40)—— OSPF设计与LSA类型(三)
  8. T-SQL:谓词和运算符(六)
  9. 怎么添加usb虚拟打印机端口_佳能LBP2900,夏普等特殊打印机使用教程
  10. 无法卸载office,一招搞定
  11. MapReducer Counter计数器的使用,Combiner ,Partitioner,Sort,Grop的使用,
  12. 【电脑常用办公软件】万彩办公大师教程丨截屏大师工具的应用
  13. 无人机实时流怎么开_直播解决方案,如何利用无人机进行直播
  14. python 经纬度 地址批量转换
  15. Charles抓包遇到Not allowed POST https://xxxxxxxxxxx/xxxxxxxxxx connection dropped
  16. WordPress搜索引擎蜘蛛统计分析插件:Spider Analyser
  17. 200用户的oa文件服务器配置,oa服务器主要配置
  18. mysql中的BIT_LENGTH和LENGTH以及CHAR_LENGTH的区别
  19. Java值传递与引用传递的区别
  20. 参考文献中各字母的含义

热门文章

  1. 同城外卖APP开发高级功能详情
  2. win10计算机未连接到网络适配器,Win10系统上网络适配器处于未连接状态该怎么解决?...
  3. 服务器上zip 解压
  4. 谈谈什么是数据质量管理
  5. python小游戏贪吃蛇下载_python小游戏之贪吃蛇
  6. Pylint 常见问题文档
  7. html div自适应布局,css两个div自适应宽度布局方法大全(精华)
  8. baocms伪静态_PHP源码:BAOCMS v5.0白金版 本地O2O生活电商门户系统+微信+同步wap手机版宝...
  9. 导购网站 云服务器配置,导购网站 云服务器配置
  10. 大数据Kudu(七):Kudu分区策略