/* * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.security.config.method; import static org.springframework.security.config.Elements.*; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.config.AopNamespaceUtils; import org.springframework.aop.framework.ProxyFactoryBean; import org.springframework.aop.target.LazyInitTargetSource; import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanReference; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.parsing.CompositeComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource; import org.springframework.security.access.annotation.Jsr250Voter; import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource; import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory; import org.springframework.security.access.expression.method.ExpressionBasedPostInvocationAdvice; import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice; import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; import org.springframework.security.access.intercept.AfterInvocationProviderManager; import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor; import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor; import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor; import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource; import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource; import org.springframework.security.access.prepost.PostInvocationAdviceProvider; import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter; import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource; import org.springframework.security.access.vote.AffirmativeBased; import org.springframework.security.access.vote.AuthenticatedVoter; import org.springframework.security.access.vote.RoleVoter; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.BeanIds; import org.springframework.security.config.Elements; import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean; import org.springframework.security.config.core.GrantedAuthorityDefaults; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; /** * Processes the top-level "global-method-security" element. * * @author Ben Alex * @author Luke Taylor * @author Rob Winch * @since 2.0 */ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser { private final Log logger = LogFactory.getLog(getClass()); private static final String ATT_AUTHENTICATION_MANAGER_REF = "authentication-manager-ref"; private static final String ATT_ACCESS = "access"; private static final String ATT_EXPRESSION = "expression"; private static final String ATT_ACCESS_MGR = "access-decision-manager-ref"; private static final String ATT_RUN_AS_MGR = "run-as-manager-ref"; private static final String ATT_USE_JSR250 = "jsr250-annotations"; private static final String ATT_USE_SECURED = "secured-annotations"; private static final String ATT_USE_PREPOST = "pre-post-annotations"; private static final String ATT_REF = "ref"; private static final String ATT_MODE = "mode"; private static final String ATT_ADVICE_ORDER = "order"; private static final String ATT_META_DATA_SOURCE_REF = "metadata-source-ref"; public BeanDefinition parse(Element element, ParserContext pc) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition( element.getTagName(), pc.extractSource(element)); pc.pushContainingComponent(compositeDef); Object source = pc.extractSource(element); // The list of method metadata delegates ManagedList<BeanMetadataElement> delegates = new ManagedList<BeanMetadataElement>(); boolean jsr250Enabled = "enabled".equals(element.getAttribute(ATT_USE_JSR250)); boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED)); boolean prePostAnnotationsEnabled = "enabled".equals(element .getAttribute(ATT_USE_PREPOST)); boolean useAspectJ = "aspectj".equals(element.getAttribute(ATT_MODE)); BeanDefinition preInvocationVoter = null; ManagedList<BeanMetadataElement> afterInvocationProviders = new ManagedList<BeanMetadataElement>(); // Check for an external SecurityMetadataSource, which takes priority over other // sources String metaDataSourceId = element.getAttribute(ATT_META_DATA_SOURCE_REF); if (StringUtils.hasText(metaDataSourceId)) { delegates.add(new RuntimeBeanReference(metaDataSourceId)); } if (prePostAnnotationsEnabled) { Element prePostElt = DomUtils.getChildElementByTagName(element, INVOCATION_HANDLING); Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, EXPRESSION_HANDLER); if (prePostElt != null && expressionHandlerElt != null) { pc.getReaderContext().error( INVOCATION_HANDLING + " and " + EXPRESSION_HANDLER + " cannot be used together ", source); } BeanDefinitionBuilder preInvocationVoterBldr = BeanDefinitionBuilder .rootBeanDefinition(PreInvocationAuthorizationAdviceVoter.class); // After-invocation provider to handle post-invocation filtering and // authorization expression annotations. BeanDefinitionBuilder afterInvocationBldr = BeanDefinitionBuilder .rootBeanDefinition(PostInvocationAdviceProvider.class); // The metadata source for the security interceptor BeanDefinitionBuilder mds = BeanDefinitionBuilder .rootBeanDefinition(PrePostAnnotationSecurityMetadataSource.class); if (prePostElt != null) { // Customized override of expression handling system String attributeFactoryRef = DomUtils.getChildElementByTagName( prePostElt, INVOCATION_ATTRIBUTE_FACTORY).getAttribute("ref"); String preAdviceRef = DomUtils.getChildElementByTagName(prePostElt, PRE_INVOCATION_ADVICE).getAttribute("ref"); String postAdviceRef = DomUtils.getChildElementByTagName(prePostElt, POST_INVOCATION_ADVICE).getAttribute("ref"); mds.addConstructorArgReference(attributeFactoryRef); preInvocationVoterBldr.addConstructorArgReference(preAdviceRef); afterInvocationBldr.addConstructorArgReference(postAdviceRef); } else { // The default expression-based system String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref"); if (StringUtils.hasText(expressionHandlerRef)) { logger.info("Using bean '" + expressionHandlerRef + "' as method ExpressionHandler implementation"); RootBeanDefinition lazyInitPP = new RootBeanDefinition( LazyInitBeanDefinitionRegistryPostProcessor.class); lazyInitPP.getConstructorArgumentValues().addGenericArgumentValue( expressionHandlerRef); pc.getReaderContext().registerWithGeneratedName(lazyInitPP); BeanDefinitionBuilder lazyMethodSecurityExpressionHandlerBldr = BeanDefinitionBuilder .rootBeanDefinition(LazyInitTargetSource.class); lazyMethodSecurityExpressionHandlerBldr.addPropertyValue( "targetBeanName", expressionHandlerRef); BeanDefinitionBuilder expressionHandlerProxyBldr = BeanDefinitionBuilder .rootBeanDefinition(ProxyFactoryBean.class); expressionHandlerProxyBldr.addPropertyValue("targetSource", lazyMethodSecurityExpressionHandlerBldr.getBeanDefinition()); expressionHandlerProxyBldr.addPropertyValue("proxyInterfaces", MethodSecurityExpressionHandler.class); expressionHandlerRef = pc.getReaderContext().generateBeanName( expressionHandlerProxyBldr.getBeanDefinition()); pc.registerBeanComponent(new BeanComponentDefinition( expressionHandlerProxyBldr.getBeanDefinition(), expressionHandlerRef)); } else { RootBeanDefinition expressionHandler = registerWithDefaultRolePrefix(pc, DefaultMethodSecurityExpressionHandlerBeanFactory.class); expressionHandlerRef = pc.getReaderContext().generateBeanName( expressionHandler); pc.registerBeanComponent(new BeanComponentDefinition( expressionHandler, expressionHandlerRef)); logger.info("Expressions were enabled for method security but no SecurityExpressionHandler was configured. " + "All hasPermision() expressions will evaluate to false."); } BeanDefinitionBuilder expressionPreAdviceBldr = BeanDefinitionBuilder .rootBeanDefinition(ExpressionBasedPreInvocationAdvice.class); expressionPreAdviceBldr.addPropertyReference("expressionHandler", expressionHandlerRef); preInvocationVoterBldr.addConstructorArgValue(expressionPreAdviceBldr .getBeanDefinition()); BeanDefinitionBuilder expressionPostAdviceBldr = BeanDefinitionBuilder .rootBeanDefinition(ExpressionBasedPostInvocationAdvice.class); expressionPostAdviceBldr.addConstructorArgReference(expressionHandlerRef); afterInvocationBldr.addConstructorArgValue(expressionPostAdviceBldr .getBeanDefinition()); BeanDefinitionBuilder annotationInvocationFactory = BeanDefinitionBuilder .rootBeanDefinition(ExpressionBasedAnnotationAttributeFactory.class); annotationInvocationFactory .addConstructorArgReference(expressionHandlerRef); mds.addConstructorArgValue(annotationInvocationFactory .getBeanDefinition()); } preInvocationVoter = preInvocationVoterBldr.getBeanDefinition(); afterInvocationProviders.add(afterInvocationBldr.getBeanDefinition()); delegates.add(mds.getBeanDefinition()); } if (useSecured) { delegates.add(BeanDefinitionBuilder.rootBeanDefinition( SecuredAnnotationSecurityMetadataSource.class).getBeanDefinition()); } if (jsr250Enabled) { RootBeanDefinition jsrMetadataSource = registerWithDefaultRolePrefix(pc, Jsr250MethodSecurityMetadataSourceBeanFactory.class); delegates.add(jsrMetadataSource); } // Now create a Map<String, ConfigAttribute> for each <protect-pointcut> // sub-element Map<String, List<ConfigAttribute>> pointcutMap = parseProtectPointcuts(pc, DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT)); if (pointcutMap.size() > 0) { if (useAspectJ) { pc.getReaderContext().error( "You can't use AspectJ mode with protect-pointcut definitions", source); } // Only add it if there are actually any pointcuts defined. BeanDefinition mapBasedMetadataSource = new RootBeanDefinition( MapBasedMethodSecurityMetadataSource.class); BeanReference ref = new RuntimeBeanReference(pc.getReaderContext() .generateBeanName(mapBasedMetadataSource)); delegates.add(ref); pc.registerBeanComponent(new BeanComponentDefinition(mapBasedMetadataSource, ref.getBeanName())); registerProtectPointcutPostProcessor(pc, pointcutMap, ref, source); } BeanReference metadataSource = registerDelegatingMethodSecurityMetadataSource(pc, delegates, source); // Check for additional after-invocation-providers.. List<Element> afterInvocationElts = DomUtils.getChildElementsByTagName(element, Elements.AFTER_INVOCATION_PROVIDER); for (Element elt : afterInvocationElts) { afterInvocationProviders.add(new RuntimeBeanReference(elt .getAttribute(ATT_REF))); } String accessManagerId = element.getAttribute(ATT_ACCESS_MGR); if (!StringUtils.hasText(accessManagerId)) { accessManagerId = registerAccessManager(pc, jsr250Enabled, preInvocationVoter); } String authMgrRef = element.getAttribute(ATT_AUTHENTICATION_MANAGER_REF); String runAsManagerId = element.getAttribute(ATT_RUN_AS_MGR); BeanReference interceptor = registerMethodSecurityInterceptor(pc, authMgrRef, accessManagerId, runAsManagerId, metadataSource, afterInvocationProviders, source, useAspectJ); if (useAspectJ) { BeanDefinitionBuilder aspect = BeanDefinitionBuilder .rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect"); aspect.setFactoryMethod("aspectOf"); aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); aspect.addPropertyValue("securityInterceptor", interceptor); String id = pc.getReaderContext().registerWithGeneratedName( aspect.getBeanDefinition()); pc.registerBeanComponent(new BeanComponentDefinition(aspect .getBeanDefinition(), id)); } else { registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER)); AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element); } pc.popAndRegisterContainingComponent(); return null; } /** * Register the default AccessDecisionManager. Adds the special JSR 250 voter jsr-250 * is enabled and an expression voter if expression-based access control is enabled. * @return */ @SuppressWarnings({ "unchecked", "rawtypes" }) private String registerAccessManager(ParserContext pc, boolean jsr250Enabled, BeanDefinition expressionVoter) { BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder .rootBeanDefinition(AffirmativeBased.class); ManagedList voters = new ManagedList(4); if (expressionVoter != null) { voters.add(expressionVoter); } voters.add(new RootBeanDefinition(RoleVoter.class)); voters.add(new RootBeanDefinition(AuthenticatedVoter.class)); if (jsr250Enabled) { voters.add(new RootBeanDefinition(Jsr250Voter.class)); } accessMgrBuilder.addConstructorArgValue(voters); BeanDefinition accessManager = accessMgrBuilder.getBeanDefinition(); String id = pc.getReaderContext().generateBeanName(accessManager); pc.registerBeanComponent(new BeanComponentDefinition(accessManager, id)); return id; } @SuppressWarnings("rawtypes") private BeanReference registerDelegatingMethodSecurityMetadataSource( ParserContext pc, ManagedList delegates, Object source) { RootBeanDefinition delegatingMethodSecurityMetadataSource = new RootBeanDefinition( DelegatingMethodSecurityMetadataSource.class); delegatingMethodSecurityMetadataSource.setSource(source); delegatingMethodSecurityMetadataSource.getConstructorArgumentValues() .addGenericArgumentValue(delegates); String id = pc.getReaderContext().generateBeanName( delegatingMethodSecurityMetadataSource); pc.registerBeanComponent(new BeanComponentDefinition( delegatingMethodSecurityMetadataSource, id)); return new RuntimeBeanReference(id); } private void registerProtectPointcutPostProcessor(ParserContext parserContext, Map<String, List<ConfigAttribute>> pointcutMap, BeanReference mapBasedMethodSecurityMetadataSource, Object source) { RootBeanDefinition ppbp = new RootBeanDefinition( ProtectPointcutPostProcessor.class); ppbp.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); ppbp.setSource(source); ppbp.getConstructorArgumentValues().addGenericArgumentValue( mapBasedMethodSecurityMetadataSource); ppbp.getPropertyValues().addPropertyValue("pointcutMap", pointcutMap); parserContext.getReaderContext().registerWithGeneratedName(ppbp); } private Map<String, List<ConfigAttribute>> parseProtectPointcuts( ParserContext parserContext, List<Element> protectPointcutElts) { Map<String, List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String, List<ConfigAttribute>>(); for (Element childElt : protectPointcutElts) { String accessConfig = childElt.getAttribute(ATT_ACCESS); String expression = childElt.getAttribute(ATT_EXPRESSION); if (!StringUtils.hasText(accessConfig)) { parserContext.getReaderContext().error("Access configuration required", parserContext.extractSource(childElt)); } if (!StringUtils.hasText(expression)) { parserContext.getReaderContext().error("Pointcut expression required", parserContext.extractSource(childElt)); } String[] attributeTokens = StringUtils .commaDelimitedListToStringArray(accessConfig); List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>( attributeTokens.length); for (String token : attributeTokens) { attributes.add(new SecurityConfig(token)); } pointcutMap.put(expression, attributes); } return pointcutMap; } private BeanReference registerMethodSecurityInterceptor(ParserContext pc, String authMgrRef, String accessManagerId, String runAsManagerId, BeanReference metadataSource, List<BeanMetadataElement> afterInvocationProviders, Object source, boolean useAspectJ) { BeanDefinitionBuilder bldr = BeanDefinitionBuilder .rootBeanDefinition(useAspectJ ? AspectJMethodSecurityInterceptor.class : MethodSecurityInterceptor.class); bldr.getRawBeanDefinition().setSource(source); bldr.addPropertyReference("accessDecisionManager", accessManagerId); RootBeanDefinition authMgr = new RootBeanDefinition( AuthenticationManagerDelegator.class); authMgr.getConstructorArgumentValues().addGenericArgumentValue(authMgrRef); bldr.addPropertyValue("authenticationManager", authMgr); bldr.addPropertyValue("securityMetadataSource", metadataSource); if (StringUtils.hasText(runAsManagerId)) { bldr.addPropertyReference("runAsManager", runAsManagerId); } if (!afterInvocationProviders.isEmpty()) { BeanDefinition afterInvocationManager; afterInvocationManager = new RootBeanDefinition( AfterInvocationProviderManager.class); afterInvocationManager.getPropertyValues().addPropertyValue("providers", afterInvocationProviders); bldr.addPropertyValue("afterInvocationManager", afterInvocationManager); } BeanDefinition bean = bldr.getBeanDefinition(); String id = pc.getReaderContext().generateBeanName(bean); pc.registerBeanComponent(new BeanComponentDefinition(bean, id)); return new RuntimeBeanReference(id); } private void registerAdvisor(ParserContext parserContext, BeanReference interceptor, BeanReference metadataSource, Object source, String adviceOrder) { if (parserContext.getRegistry().containsBeanDefinition( BeanIds.METHOD_SECURITY_METADATA_SOURCE_ADVISOR)) { parserContext.getReaderContext().error( "Duplicate <global-method-security> detected.", source); } RootBeanDefinition advisor = new RootBeanDefinition( MethodSecurityMetadataSourceAdvisor.class); if (StringUtils.hasText(adviceOrder)) { advisor.getPropertyValues().addPropertyValue("order", adviceOrder); } // advisor must be an infrastructure bean as Spring's // InfrastructureAdvisorAutoProxyCreator will ignore it // otherwise advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); advisor.setSource(source); advisor.getConstructorArgumentValues().addGenericArgumentValue( interceptor.getBeanName()); advisor.getConstructorArgumentValues().addGenericArgumentValue(metadataSource); advisor.getConstructorArgumentValues().addGenericArgumentValue( metadataSource.getBeanName()); parserContext.getRegistry().registerBeanDefinition( BeanIds.METHOD_SECURITY_METADATA_SOURCE_ADVISOR, advisor); } private RootBeanDefinition registerWithDefaultRolePrefix(ParserContext pc, Class<? extends AbstractGrantedAuthorityDefaultsBeanFactory> beanFactoryClass) { RootBeanDefinition beanFactoryDefinition = new RootBeanDefinition(beanFactoryClass); String beanFactoryRef = pc.getReaderContext().generateBeanName(beanFactoryDefinition); pc.getRegistry().registerBeanDefinition(beanFactoryRef, beanFactoryDefinition); RootBeanDefinition bean = new RootBeanDefinition(); bean.setFactoryBeanName(beanFactoryRef); bean.setFactoryMethodName("getBean"); return bean; } /** * Delays the lookup of the AuthenticationManager within MethodSecurityInterceptor, to * prevent issues like SEC-933. * * @author Luke Taylor * @since 3.0 */ static final class AuthenticationManagerDelegator implements AuthenticationManager, BeanFactoryAware { private AuthenticationManager delegate; private final Object delegateMonitor = new Object(); private BeanFactory beanFactory; private final String authMgrBean; AuthenticationManagerDelegator(String authMgrBean) { this.authMgrBean = StringUtils.hasText(authMgrBean) ? authMgrBean : BeanIds.AUTHENTICATION_MANAGER; } public Authentication authenticate(Authentication authentication) throws AuthenticationException { synchronized (delegateMonitor) { if (delegate == null) { Assert.state(beanFactory != null, "BeanFactory must be set to resolve " + authMgrBean); try { delegate = beanFactory.getBean(authMgrBean, AuthenticationManager.class); } catch (NoSuchBeanDefinitionException e) { if (BeanIds.AUTHENTICATION_MANAGER.equals(e.getBeanName())) { throw new NoSuchBeanDefinitionException( BeanIds.AUTHENTICATION_MANAGER, AuthenticationManagerFactoryBean.MISSING_BEAN_ERROR_MESSAGE); } throw e; } } } return delegate.authenticate(authentication); } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } } static class Jsr250MethodSecurityMetadataSourceBeanFactory extends AbstractGrantedAuthorityDefaultsBeanFactory { private Jsr250MethodSecurityMetadataSource source = new Jsr250MethodSecurityMetadataSource(); public Jsr250MethodSecurityMetadataSource getBean() { source.setDefaultRolePrefix(this.rolePrefix); return source; } } static class DefaultMethodSecurityExpressionHandlerBeanFactory extends AbstractGrantedAuthorityDefaultsBeanFactory { private DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler(); public DefaultMethodSecurityExpressionHandler getBean() { handler.setDefaultRolePrefix(this.rolePrefix); return handler; } } static abstract class AbstractGrantedAuthorityDefaultsBeanFactory implements ApplicationContextAware { protected String rolePrefix = "ROLE_"; @Override public final void setApplicationContext(ApplicationContext applicationContext) throws BeansException { String[] grantedAuthorityDefaultsBeanNames = applicationContext.getBeanNamesForType(GrantedAuthorityDefaults.class); if(grantedAuthorityDefaultsBeanNames.length == 1) { GrantedAuthorityDefaults grantedAuthorityDefaults = applicationContext.getBean(grantedAuthorityDefaultsBeanNames[0], GrantedAuthorityDefaults.class); this.rolePrefix = grantedAuthorityDefaults.getRolePrefix(); } } } /** * Delays setting a bean of a given name to be lazyily initialized until after all the * beans are registered. * * @author Rob Winch * @since 3.2 */ private static final class LazyInitBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { private final String beanName; private LazyInitBeanDefinitionRegistryPostProcessor(String beanName) { this.beanName = beanName; } public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { if (!registry.containsBeanDefinition(beanName)) { return; } BeanDefinition beanDefinition = registry.getBeanDefinition(beanName); beanDefinition.setLazyInit(true); } public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } } }