spring 之 ObjectPostProcessor

一、背景

在學習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{
    @Autowire
 	private Person person;
    
    public void afterPropertiesSet() {
		log.info(person.getName())}
}
1new 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 {

	@Bean
	public 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 AutowireBeanFactoryObjectPostProcessor
		implements 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()
	 */
	@Override
	public 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處理 AutowireBeanFactoryObjectPostProcessor
		webSecurity = 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,自動配置初始化信息
			// AutowireBeanFactoryObjectPostProcessor
			WebSecurityConfigurerAdapter 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
   @EnableWebSecurity
   public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
  
   	@Override
   	public void configure(WebSecurity web) throws Exception {
   		web.ignoring()
   		// Spring Security should completely ignore URLs starting with /resources/
   				.antMatchers("/resources/**");
   	}
  
   	@Override
   	protected 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();
   	}
  
   	@Override
   	protected 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的實現進行了大概的瞭解哦,不錯的週末。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章