记录Shrio与SpringCache使用过程遇到的问题
问题
Spring Cache 和 Apache Shiro 整合时,自定义的shiroRealm中引用了service,会导致service的Cache相关注解作用失效
分析
关于BeanPostProcessor
- BeanPostProcessor:构建Bean的时候调用,会处理所有符合条件的对象实例(扫描所有Bean进行处理,Aop实现就是通过BeanPostProcessor找到匹配的Pointcut进行自动代理)
- 提供了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执行顺序如下:
- 实现了PriorityOrdered接口的BeanPostProcessor
- 实现了Ordered接口的BeanPostProcessor
- 注册无实现任何接口的BeanPostProcessor
- 实现了MergedBeanDefinitionPostProcessor接口的BeanPostProcessor
关于PriorityOrdered
实现了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;
}
- 通过Debug查看registerBeanPostProcessors
@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,使其延迟加载。