自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

自己 new 出來的對(duì)象一樣也可以被 Spring 容器管理!

存儲(chǔ) 存儲(chǔ)軟件
按理說自己 new 出來的對(duì)象和容器是沒有關(guān)系的,但是在 Spring Security 框架中也 new 了很多對(duì)象出來,一樣也可以被容器管理,那么它是怎么做到的?

按理說自己 new 出來的對(duì)象和容器是沒有關(guān)系的,但是在 Spring Security 框架中也 new 了很多對(duì)象出來,一樣也可以被容器管理,那么它是怎么做到的?

[[330985]]

今天來和大家聊一個(gè)略微冷門的話題,Spring Security 中的 ObjectPostProcessor 到底是干嘛用的?

如果大家研究過松哥的微人事項(xiàng)目,就會(huì)發(fā)現(xiàn)里邊的動(dòng)態(tài)權(quán)限配置有這樣一行代碼:

  1. @Configuration 
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter { 
  3.  
  4.     @Override 
  5.     protected void configure(HttpSecurity http) throws Exception { 
  6.         http.authorizeRequests() 
  7.                 .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() { 
  8.                     @Override 
  9.                     public <O extends FilterSecurityInterceptor> O postProcess(O object) { 
  10.                         object.setAccessDecisionManager(customUrlDecisionManager); 
  11.                         object.setSecurityMetadataSource(customFilterInvocationSecurityMetadataSource); 
  12.                         return object; 
  13.                     } 
  14.                 }) 
  15.                 .and() 
  16.                 ... 
  17.     } 

這里的 withObjectPostProcessor 到底該如何理解?

今天松哥就來和大家揭開謎題。

1.ObjectPostProcessor 的作用

我們先來看下 ObjectPostProcessor 到底有啥作用,先來看一下這個(gè)接口的定義:

  1. package org.springframework.security.config.annotation; 
  2. public interface ObjectPostProcessor<T> { 
  3.  <O extends T> O postProcess(O object); 

接口中就只有一個(gè) postProcess 方法。

我們?cè)賮砜纯?ObjectPostProcessor 的繼承關(guān)系:

兩個(gè)比較重要的實(shí)現(xiàn)類,其中 AutowireBeanFactoryObjectPostProcessor 值得一說,來看下 AutowireBeanFactoryObjectPostProcessor 的定義:

  1. final class AutowireBeanFactoryObjectPostProcessor 
  2.   implements ObjectPostProcessor<Object>, DisposableBean, SmartInitializingSingleton { 
  3.  AutowireBeanFactoryObjectPostProcessor( 
  4.    AutowireCapableBeanFactory autowireBeanFactory) { 
  5.   this.autowireBeanFactory = autowireBeanFactory; 
  6.  } 
  7.  @SuppressWarnings("unchecked"
  8.  public <T> T postProcess(T object) { 
  9.   if (object == null) { 
  10.    return null
  11.   } 
  12.   T result = null
  13.   try { 
  14.    result = (T) this.autowireBeanFactory.initializeBean(object, 
  15.      object.toString()); 
  16.   } 
  17.   catch (RuntimeException e) { 
  18.    Class<?> type = object.getClass(); 
  19.    throw new RuntimeException( 
  20.      "Could not postProcess " + object + " of type " + type, e); 
  21.   } 
  22.   this.autowireBeanFactory.autowireBean(object); 
  23.   if (result instanceof DisposableBean) { 
  24.    this.disposableBeans.add((DisposableBean) result); 
  25.   } 
  26.   if (result instanceof SmartInitializingSingleton) { 
  27.    this.smartSingletons.add((SmartInitializingSingleton) result); 
  28.   } 
  29.   return result; 
  30.  } 

AutowireBeanFactoryObjectPostProcessor 的源碼很好理解:

  1. 首先在構(gòu)建 AutowireBeanFactoryObjectPostProcessor 對(duì)象時(shí),傳入了一個(gè) AutowireCapableBeanFactory 對(duì)象,看過 Spring 源碼的小伙伴就知道,AutowireCapableBeanFactory 可以幫助我們手動(dòng)的將一個(gè)實(shí)例注冊(cè)到 Spring 容器中。
  2. 在 postProcess 方法中,就是具體的注冊(cè)邏輯了,都很簡單,我就不再贅述。

由此可見,ObjectPostProcessor 的主要作用就是手動(dòng)注冊(cè)實(shí)例到 Spring 容器中去(并且讓實(shí)例走一遍 Bean 的生命周期)。

正常來說,我們項(xiàng)目中的 Bean 都是通過自動(dòng)掃描注入到 Spring 容器中去的,然而在 Spring Security 框架中,有大量的代碼不是通過自動(dòng)掃描注入到 Spring 容器中去的,而是直接 new 出來的,這樣做的本意是為了簡化項(xiàng)目配置。

這些直接 new 出來的代碼,如果想被 Spring 容器管理該怎么辦呢?那就得 ObjectPostProcessor 出場了。

2.框架舉例

接下來我隨便舉幾個(gè)框架中對(duì)象 new 的例子,大家看一下 ObjectPostProcessor 的作用:

HttpSecurity 初始化代碼(WebSecurityConfigurerAdapter#getHttp):

  1. protected final HttpSecurity getHttp() throws Exception { 
  2.  if (http != null) { 
  3.   return http; 
  4.  } 
  5.     ... 
  6.     ... 
  7.  http = new HttpSecurity(objectPostProcessor, authenticationBuilder, 
  8.    sharedObjects); 
  9.  ... 
  10.     ... 

WebSecurity 初始化代碼(WebSecurityConfiguration#setFilterChainProxySecurityConfigurer):

  1. public void setFilterChainProxySecurityConfigurer( 
  2.   ObjectPostProcessor<Object> objectPostProcessor, 
  3.   @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) 
  4.   throws Exception { 
  5.  webSecurity = objectPostProcessor 
  6.    .postProcess(new WebSecurity(objectPostProcessor)); 
  7.     ... 
  8.     ... 

Spring Security 框架源碼中,隨處可見手動(dòng)裝配。Spring Security 中,過濾器鏈中的所有過濾器都是通過對(duì)應(yīng)的 xxxConfigure 來進(jìn)行配置的,而所有的 xxxConfigure 都是繼承自 SecurityConfigurerAdapter,如下:

而在這些 xxxConfigure 的 configure 方法中,無一例外的都會(huì)讓他們各自配置的管理器去 Spring 容器中走一圈,例如 AbstractAuthenticationFilterConfigurer#configure 方法:

  1. public void configure(B http) throws Exception { 
  2.  ... 
  3.     ... 
  4.  F filter = postProcess(authFilter); 
  5.  http.addFilter(filter); 

其他的 xxxConfigurer#configure 方法也都有類似的實(shí)現(xiàn),小伙伴們可以自行查看,我就不再贅述了。

3.為什么這樣

直接將 Bean 通過自動(dòng)掃描注冊(cè)到 Spring 容器不好嗎?為什么要搞成這個(gè)樣子?

在 Spring Security 中,由于框架本身大量采用了 Java 配置,并且沒有將對(duì)象的各個(gè)屬性都暴露出來,這樣做的本意是為了簡化配置。然而這樣帶來的一個(gè)問題就是需要我們手動(dòng)將 Bean 注冊(cè)到 Spring 容器中去,ObjectPostProcessor 就是為了解決該問題。

一旦將 Bean 注冊(cè)到 Spring 容器中了,我們就有辦法去增強(qiáng)一個(gè) Bean 的功能,或者需修改一個(gè) Bean 的屬性。

例如一開始提到的動(dòng)態(tài)權(quán)限配置代碼:

  1. @Configuration 
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter { 
  3.  
  4.     @Override 
  5.     protected void configure(HttpSecurity http) throws Exception { 
  6.         http.authorizeRequests() 
  7.                 .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() { 
  8.                     @Override 
  9.                     public <O extends FilterSecurityInterceptor> O postProcess(O object) { 
  10.                         object.setAccessDecisionManager(customUrlDecisionManager); 
  11.                         object.setSecurityMetadataSource(customFilterInvocationSecurityMetadataSource); 
  12.                         return object; 
  13.                     } 
  14.                 }) 
  15.                 .and() 
  16.                 ... 
  17.     } 

權(quán)限管理本身是由 FilterSecurityInterceptor 控制的,系統(tǒng)默認(rèn)的 FilterSecurityInterceptor 已經(jīng)創(chuàng)建好了,而且我也沒辦法修改它的屬性,那么怎么辦呢?我們可以利用 withObjectPostProcessor 方法,去修改 FilterSecurityInterceptor 中的相關(guān)屬性。

上面這個(gè)配置生效的原因之一是因?yàn)?FilterSecurityInterceptor 在創(chuàng)建成功后,會(huì)重走一遍 postProcess 方法,這里通過重寫 postProcess 方法就能實(shí)現(xiàn)屬性修改,我們可以看下配置 FilterSecurityInterceptor 的方法(AbstractInterceptUrlConfigurer#configure):

  1. abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConfigurer<C, H>, H extends HttpSecurityBuilder<H>> 
  2.   extends AbstractHttpConfigurer<C, H> { 
  3.  @Override 
  4.  public void configure(H http) throws Exception { 
  5.   FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http); 
  6.   if (metadataSource == null) { 
  7.    return
  8.   } 
  9.   FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor( 
  10.     http, metadataSource, http.getSharedObject(AuthenticationManager.class)); 
  11.   if (filterSecurityInterceptorOncePerRequest != null) { 
  12.    securityInterceptor 
  13.      .setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest); 
  14.   } 
  15.   securityInterceptor = postProcess(securityInterceptor); 
  16.   http.addFilter(securityInterceptor); 
  17.   http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor); 
  18.  } 

可以看到,securityInterceptor 對(duì)象創(chuàng)建成功后,還是會(huì)去 postProcess 方法中走一遭。

看懂了上面的代碼,接下來我再舉一個(gè)例子小伙伴們應(yīng)該一下就能明白:

  1. @Configuration 
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter { 
  3.  
  4.     @Override 
  5.     protected void configure(HttpSecurity http) throws Exception { 
  6.         http.authorizeRequests() 
  7.                 .antMatchers("/admin/**").hasRole("admin"
  8.                 ... 
  9.                 .and() 
  10.                 .formLogin() 
  11.                 .withObjectPostProcessor(new ObjectPostProcessor<UsernamePasswordAuthenticationFilter>() { 
  12.                     @Override 
  13.                     public <O extends UsernamePasswordAuthenticationFilter> O postProcess(O object) { 
  14.                         object.setUsernameParameter("name"); 
  15.                         return object; 
  16.                     } 
  17.                 }) 
  18.                 ... 
  19.     } 

在這里,我把配置好的 UsernamePasswordAuthenticationFilter 過濾器再拎出來,修改一下用戶名的 key(正常來說,修改用戶名的 key 不用這么麻煩,這里主要是給大家演示 ObjectPostProcessor 的效果),修改完成后,以后用戶登錄時(shí),用戶名就不是 username 而是 name 了。

4.小結(jié)

好了,只要小伙伴們掌握了上面的用法,以后在 Spring Security 中,如果想修改某一個(gè)對(duì)象的屬性,但是卻不知道從哪里下手,那么不妨試試 withObjectPostProcessor!

本文轉(zhuǎn)載自微信公眾號(hào)「江南一點(diǎn)雨」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系江南一點(diǎn)雨公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: 江南一點(diǎn)雨
相關(guān)推薦

2020-09-10 13:55:53

VScodego開發(fā)工具

2011-03-14 16:51:24

2022-11-29 12:53:36

機(jī)器人物理MIT

2022-04-14 19:39:39

Java線程安全

2011-10-27 09:42:19

ASP.NET

2021-08-27 06:41:34

Docker ContainerdRun&Exec

2019-09-05 09:29:00

CAP理論分布式系統(tǒng)

2021-02-01 06:10:02

springaop機(jī)制開發(fā)

2012-03-07 17:24:10

戴爾咨詢

2012-12-20 10:17:32

IT運(yùn)維

2011-02-28 10:38:13

Windows 8

2009-06-12 15:26:02

2021-05-20 08:37:32

multiprocesPython線程

2021-08-12 06:08:15

CSS 技巧組件狀態(tài)

2015-08-25 09:52:36

云計(jì)算云計(jì)算產(chǎn)業(yè)云計(jì)算政策

2013-01-11 18:10:56

軟件

2020-11-12 08:30:38

Java微服務(wù)Go

2020-01-09 17:03:29

人工智能技術(shù)算法

2021-06-01 05:50:03

Spring@PostConstrLifecycle

2021-06-13 08:55:25

Spring NatiWebFluxJVM
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)