java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > spring的ObjectPostProcessor

spring中的ObjectPostProcessor详解

作者:汪小哥

这篇文章主要介绍了spring中的ObjectPostProcessor详解,Spring Security 的 Java 配置不会公开其配置的每个对象的每个属性,这简化了大多数用户的配置,毕竟,如果每个属性都公开,用户可以使用标准 bean 配置,需要的朋友可以参考下

一、背景

在学习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

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());
	}
}

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 {
	@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 因此先调用了这个自动注入的方法创建了webSecurityorg.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中的ObjectPostProcessor详解的文章就介绍到这了,更多相关spring的ObjectPostProcessor内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文