记录Shrio与SpringCache使用过程遇到的问题

问题

Spring Cache 和 Apache Shiro 整合时,自定义的shiroRealm中引用了service,会导致service的Cache相关注解作用失效

分析

关于BeanPostProcessor

  • BeanPostProcessor:构建Bean的时候调用,会处理所有符合条件的对象实例(扫描所有Bean进行处理,Aop实现就是通过BeanPostProcessor找到匹配的Pointcut进行自动代理)

image

  • 提供了postProcessBeforeInitialization与postProcessAfterInitialization方法,对所有实现了InitializingBean的Bean的afterPropertiesSet方法前后执行。
  • BeanPostProcessor本身也是一个Bean,一般而言其实例化时机要早过普通的Bean,但是BeanPostProcessor也会依赖一些Bean,这就导致了一些Bean的实例化早于BeanPostProcessor,由此会导致一些问题。

BeanPostProcessor启动阶段对其依赖的Bean造成的影响

  • AbstractApplicationContext refresh是Spring IOC容器的核心方法,这个方法的作用是创建加载Spring容器配置(包括.xml配置,property文件和数据库模式等)
  • AbstractApplicationContext refresh()——>registerBeanPostProcessors(beanFactory)方法会注册BeanPostProcessors:
public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		// 注册BeanPostProcessorChecker
		// 检查可在当前Bean上起作用的BeanPostProcessor个数与总的BeanPostProcessor个数,如果起作用的个数少于总数打印://xxx is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for //auto-proxying)
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
		List<String> orderedPostProcessorNames = new ArrayList<String>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				//getBean PriorityOrdered类型的BeanPostProcessor会预初始化
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// 1,注册实现 PriorityOrdered BeanPostProcessors
		sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// 2,注册实现 Ordered BeanPostProcessors
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(beanFactory, orderedPostProcessors);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// 3,注册所有无序(没有实现Ordered/ PriorityOrdered) BeanPostProcessors.
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		// 4, 注册所有内部(MergedBeanDefinitionPostProcessor) BeanPostProcessors.
		sortPostProcessors(beanFactory, internalPostProcessors);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

BeanPostProcessor执行顺序如下:

  1. 实现了PriorityOrdered接口的BeanPostProcessor
  2. 实现了Ordered接口的BeanPostProcessor
  3. 注册无实现任何接口的BeanPostProcessor
  4. 实现了MergedBeanDefinitionPostProcessor接口的BeanPostProcessor

关于PriorityOrdered

image

实现了PriorityOrdered的BeanPostProcessor先于其他BeanPostProcessor,并会影响到其他BeanPostProcessor的autowiring behavior

Spring的一些BeanPostProcessor

  • ScheduledAnnotationBeanPostProcessor:实现了Ordered
  • AsyncAnnotationBeanPostProcessor:实现了Ordered
  • AbstractAutoProxyCreator (Transactional|Cache):实现了Ordered

Shiro LifecycleBeanPostProcessor导致的问题

Spring整合shiro的系统中,需要在配置bean的时候加入LifecycleBeanPostProcessor(Shiro提供的一个BeanPostProcessor类),用来管理shiro一些bean的生命周期。

public class LifecycleBeanPostProcessor implements DestructionAwareBeanPostProcessor, PriorityOrdered 

LifecycleBeanPostProcessor实现了BeanPostProcessor与PriorityOrdered,postProcessBeforeInitialization方法,调用了自定义Realm(AuthorizingRealm)中实现了的 init() 方法初始化授权缓存,自定义Realm中依赖的一些Bean被提前初始化了,导致Spring某些BeanPostProcessor(Ordered级别下)不能拦截到这些Bean,造成依赖功能的失效(如Transaction ,Async,Cache…)

 protected void onInit() {
        super.onInit();
        //trigger obtaining the authorization cache if possible
        getAvailableAuthorizationCache();
    }


 private Cache<Object, AuthorizationInfo> getAvailableAuthorizationCache() {
        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
        if (cache == null && isAuthorizationCachingEnabled()) {
            cache = getAuthorizationCacheLazy();
        }
        return cache;
    }

image

  • 通过Debug查看registerBeanPostProcessors

image

@Lazy

@Lazy修饰Spring Bean类,用于指定该Bean是否取消预初始化。 容器初始化方法在AbstractApplicationContext的refresh()——>finishBeanFactoryInitialization(beanFactory)——>preInstantiateSingletons()

for (String beanName : beanNames) {
				RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
				//单例并且非Lazy类型的才会在容器初始化的时候被注入
				if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
					if (isFactoryBean(beanName)) {
						final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
								@Override
								public Boolean run() {
									return ((SmartFactoryBean<?>) factory).isEagerInit();
								}
							}, getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
					else {
						getBean(beanName);
					}
				}
			}

添加了@Lazy注解的Bean在容器初始化的过程中不会进行依赖注入,只有当第一个getBean的时候才会实例化Bean。

解决

通过对自定义Realm中依赖的Bean加上@Lazy,使其延迟加载。

image

参考