spring中的ObjectPostProcessor详解

 更新时间:2024年01月09日 10:32:30   作者:汪小哥  
这篇文章主要介绍了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

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

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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 快速排序的原理及java代码实现

    快速排序的原理及java代码实现

    网上关于快速排序的算法原理和算法实现都比较多,不过java是实现并不多,而且部分实现很难理解,和思路有点不搭调。所以整理了这篇文章。如果有不妥之处还请建议。
    2016-02-02
  • Java的异常处理体系详解

    Java的异常处理体系详解

    这篇文章主要介绍了Java的异常处理体系,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • JavaEE通过response实现请求重定向

    JavaEE通过response实现请求重定向

    这篇文章主要介绍了JavaEE通过response实现请求重定向的方法,非常的简单实用,有需要的朋友可以参考下
    2014-10-10
  • Java资源缓存 之 LruCache

    Java资源缓存 之 LruCache

    LruCache (此类在android-support-v4的包中提供) 这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。
    2016-08-08
  • Java获取中文拼音、中文首字母缩写和中文首字母的示例

    Java获取中文拼音、中文首字母缩写和中文首字母的示例

    本文主要介绍了Java获取中文拼音、中文首字母缩写和中文首字母,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2016-10-10
  • 详解maven BUILD FAILURE的解决办法

    详解maven BUILD FAILURE的解决办法

    这篇文章主要介绍了详解maven BUILD FAILURE的解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • Spring Bean的定义概念和使用

    Spring Bean的定义概念和使用

    这篇文章主要介绍了Spring Bean的定义概念和使用,Spring bean对象是构成应用程序的支柱,也是由Spring IoC容器管理的。bean是一个被实例化,组装,并通过Spring IoC容器所管理的对象。这些bean是由用容器提供的配置元数据创建的
    2023-04-04
  • SpringBoot项目中连接SQL Server的三种方式

    SpringBoot项目中连接SQL Server的三种方式

    连接SQL Server是许多Spring Boot项目中常见的需求之一,本文主要介绍了SpringBoot项目中连接SQL Server的三种方式,具有一定的参考价值 ,感兴趣的可以了解一下
    2023-09-09
  • Java递归简单实现n的阶乘

    Java递归简单实现n的阶乘

    这篇文章主要介绍了Java递归简单实现n的阶乘,递归(recursion)就是子程序(或函数)直接调用自己或通过一系列调用语句间接调用自己,是一种描述问题和解决问题的基本方法,下面我们举一个小小的例子详情了解一下,需要的朋友可以参考下
    2021-12-12
  • MyBatis Log 插件无法显示SQL语句的原因解析

    MyBatis Log 插件无法显示SQL语句的原因解析

    MyBatis Log是IDEA一款下载量非常高的插件,该插件可以对控制台打印的日志进行解析,然后将对应的SQL语句整理并拼接好对应的参数,非常方便。这篇文章给大家介绍MyBatis Log 插件无法显示SQL语句的原因,感兴趣的朋友跟随小编一起看看吧
    2020-09-09

最新评论