Shiro源码分析 - ShiroFilterFactoryBean初始化
2017-08-04 00:00
633 查看
本文讲解 ShiroFilterFactoryBean初始化过程,由于原文中有些地方讲的有点模糊,所以用红色做了一些批注。
===============================================
网上有很多介绍shiro框架的文章,但是没有讲解 shiro 如何和 web spring 框架相结合的文章。由于实际项目的需要,这里首先顺带分析一下shiro中FormAuthenticationFilter的源码。
先看一段Spring中applicationContext.xml的配置。
下面就看一下ShiroFilterFactoryBean。
ShiroFilterFactoryBean
ShiroFilterFactoryBean的构造函数
很简单,再来看几个set函数,Spring框架会根据这几个set函数注入相应的bean。
这里根据applicationContext.xml设置了securityManager,filters(customAuthenticationFilter)。还有setFilterChainDefinitions函数,传入它的String参数definitions便是“/test = anon,/** = authc”,该函数读取这些配置,构造相应的section,并放入filterChainDefinitionMap中,这里就不详细分析里面的函数了。
注意注意,由于ShiroFilterFactoryBean实现了FactoryBean接口,上层通过getBean方法返回的不是ShiroFilterFactoryBean本身,而是 ShiroFilterFactoryBean的getObject()方法所返回的对象,相当于ShiroFilterFactoryBean的getObject()方法代理了getBean()方法。返回的对象类型由getObjectType()方法指定,是否为单例由方法isSingleton()指定。下面一口气看ShiroFilterFactoryBean中的这三个函数,
因此通过Spring配置文件构造的其实是SpringShiroFilter这个过滤器,构造它的函数在createInstance中。
createInstance
createInstance里面就是构造了一个FilterChainManager和PathMatchingFilterChainResolver,然后将FilterChainManager设置到PathMatchingFilterChainResolver中。下面一一来看。PathMatchingFilterChainResolver就是一个简单的构造函数,如下所示
下面重点分析createFilterChainManager这个函数。
createFilterChainManager
首先构造了一个DefaultFilterChainManager,如下所示
addDefaultFilters用于添加默认的过滤器,参数false表示不对这些添加的过滤器进行初始化。
那么默认的过滤器都有那些呢?这里简单看一下。
回到createFilterChainManager函数,接下来做了三件事情,第一是对每一个默认的过滤器调用applyGlobalPropertiesIfNecessary进行设置,第二是对每一个自定义的过滤器进行设置并添加到过滤器管理器DefaultFilterChainManager中,第三是调用createChain构造chain(这里叫它过滤器链吧)。过滤器链是什么,就是记录一个url和过滤器之间一对多的关系。例如前面在applicationContext.xml中设置的“/test = anon,/** = authc”,这里的url指的就是“/test”和“/**”,过滤器则由anon和authc来指定。
批注:在createFilterChainManager方法中,首先,将会把默认的过滤器实例化,添加到过滤器链管理器。遍历默认的过滤器,设置全局属性(loginUrl、successUrl、unauthorizedUrl),只有继承自AccessControlFilter才设置loginUrl,AuthenticationFilter->successUrl,AuthorizationFilter-》unauthorizedUrl。然后,获取自定义的过滤器,遍历它们设置全局属性,添加到过滤器链。最后,建立过滤链,添加到FilterChainManager。
补充一张图,看一下filterChainDefinitionMap的结构。以第一个entry为例,url为/logout,chainDefinition为logout,即filter的名称。
下面是DefaultFilterChainManager的createChain方法。
splitChainDefinition用于将url和过滤器名字分开,例如/test = anon就变为/test和anon。toNameConfigPair则是将anon这个字段进一步分开,因为这里只有anon,调用过后nameConfigPair[0]=anon,nameConfigPair[1]=null。然后调用addToChain添加到过滤器链中。
批注:上面的表述有误。splitChainDefinition其实用来切割该URL对应的过滤器,因为URL可以映射多个过滤器,下面来一张表看下splitChainDefinition的输出。
toNameConfigPair对filter的name继续切割,因为name里面还会添加有对应的角色获取权限。用个表继续说明一下toNameConfigPair的输入输出。
getFilter根据过滤器名称获取过滤器,例如这里为anon,则取出AnonymousFilter这个过滤器。applyChainConfig将chainName和chainSpecificFilterConfig设置到filter的成员变量appliedPaths里,第二章会用到这个appliedPaths。
批注:在addToChain(String chainName, String filterName, String chainSpecificFilterConfig) 中,第一个参数是要过滤的URL,第二个参数是过滤器的名字,第三个是上面分解的过滤器的配置。第三个参数会保存到对应filter的数据结构appliedPaths中,它是个map,映射关系是url->config,在applyChainConfig中保存配置。
NamedFilterList就代表了一个过滤器链了,ensureChain的代码如下
ensureChain其实就是构造了一个SimpleNamedFilterList,然后设置到filterChains中。
回到addToChain中,最后就是将过滤器添加到ensureChain中构造的SimpleNamedFilterList中。
批注:
filterChains的结构:
Map<String, NamedFilterList> filterChains
key为url路径,value是NamedFilterList。这里NamedFilterList的实现是SimpleNamedFilterList,它有两个重要的成员变量:
PathMatchingFilterChainResolver
最后构造一个SpringShiroFilter,看一下SpringShiroFilter的整个类。
这个构造函数就是简单的赋值。AbstractShiroFilter里面有个重要的doFilterInternal函数,下一章再来分析这个函数。
这里重点再看一下ShiroFilterFactoryBean实现的另一个接口BeanPostProcessor,网上有很多介绍这个接口的文章。如http://uule.iteye.com/blog/2094549所述:
BeanPostProcessor接口作用是:如果我们需要在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。
因此Spring中的BeanPostProcessor在实例化过程处于的位置,BeanPostProcessor接口有两个方法需要实现:postProcessBeforeInitialization和postProcessAfterInitialization。postProcessAfterInitialization为空函数,因此回过头来看一下ShiroFilterFactoryBean中的这个函数。
postProcessBeforeInitialization
这里传入的filter便是前面在applicationContext.xml中定义的customAuthenticationFilter。applyGlobalPropertiesIfNecessary主要和设置url有关,然后将该filter放入ShiroFilterFactoryBean管理的map中。
applyGlobalPropertiesIfNecessary
applyGlobalPropertiesIfNecessary主要就做一件事情,就是设置customAuthenticationFilter中的loginUrl,SuccessUrl和unauthorizedUrl。(由于CustomAuthenticationFilter主要和验证模块相关,并没有继承自AuthorizationFilter,因此关于授权的url就为空)
applyLoginUrlIfNecessary
这里简单来说就是做一件事情,如果customAuthenticationFilter中调用的getLoginUrl不为login.jsp(AccessControlFilter.DEFAULT_LOGIN_URL),则保留customAuthenticationFilter的loginUrl。反之,则将customAuthenticationFilter中的loginUrl设置为ShiroFilterFactoryBean中的loginUrl。
applySuccessUrlIfNecessary
该函数与applyLoginUrlIfNecessary类似,选择设置或者保留customAuthenticationFilter中的successUrl。默认的AuthenticationFilter.DEFAULT_SUCCESS_URL为”/”(一般为首页)。
applyUnauthorizedUrlIfNecessary
这个函数也和前面两个函数类似,这里就不详细说明了。
好了,关于ShiroFilterFactoryBean的构建大概就这样了,下面一节会开始介绍框架是如何调用的,例如loginUrl是在哪被使用的,以及实现一个自定义的FormAuthenticationFilter。
===============================================
网上有很多介绍shiro框架的文章,但是没有讲解 shiro 如何和 web spring 框架相结合的文章。由于实际项目的需要,这里首先顺带分析一下shiro中FormAuthenticationFilter的源码。
先看一段Spring中applicationContext.xml的配置。
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="filters"> <util:map> <entry key="authc" value-ref="customAuthenticationFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /test = anon /** = authc </value> </property> </bean>
下面就看一下ShiroFilterFactoryBean。
ShiroFilterFactoryBean
public class ShiroFilterFactoryBean implements FactoryBean, BeanPostProcessor
ShiroFilterFactoryBean的构造函数
public ShiroFilterFactoryBean() { this.filters = new LinkedHashMap<String, Filter>(); this.filterChainDefinitionMap = new LinkedHashMap<String, String>(); //order matters! }
很简单,再来看几个set函数,Spring框架会根据这几个set函数注入相应的bean。
public void setSecurityManager(SecurityManager securityManager) { this.securityManager = securityManager; } public void setFilters(Map<String, Filter> filters) { this.filters = filters; public void setFilterChainDefinitions(String definitions) { Ini ini = new Ini(); ini.load(definitions); Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS); if (CollectionUtils.isEmpty(section)) { section = ini.getSection(Ini.DEFAULT_SECTION_NAME); } setFilterChainDefinitionMap(section); }
这里根据applicationContext.xml设置了securityManager,filters(customAuthenticationFilter)。还有setFilterChainDefinitions函数,传入它的String参数definitions便是“/test = anon,/** = authc”,该函数读取这些配置,构造相应的section,并放入filterChainDefinitionMap中,这里就不详细分析里面的函数了。
注意注意,由于ShiroFilterFactoryBean实现了FactoryBean接口,上层通过getBean方法返回的不是ShiroFilterFactoryBean本身,而是 ShiroFilterFactoryBean的getObject()方法所返回的对象,相当于ShiroFilterFactoryBean的getObject()方法代理了getBean()方法。返回的对象类型由getObjectType()方法指定,是否为单例由方法isSingleton()指定。下面一口气看ShiroFilterFactoryBean中的这三个函数,
private AbstractShiroFilter instance; public Object getObject() throws Exception { if (instance == null) { instance = createInstance(); } return instance; } public Class getObjectType() { return SpringShiroFilter.class; } public boolean isSingleton() { return true; }
因此通过Spring配置文件构造的其实是SpringShiroFilter这个过滤器,构造它的函数在createInstance中。
createInstance
protected AbstractShiroFilter createInstance() throws Exception { log.debug("Creating Shiro Filter instance."); SecurityManager securityManager = getSecurityManager(); if (securityManager == null) { String msg = "SecurityManager property must be set."; throw new BeanInitializationException(msg); } if (!(securityManager instanceof WebSecurityManager)) { String msg = "The security manager does not implement the WebSecurityManager interface."; throw new BeanInitializationException(msg); } FilterChainManager manager = createFilterChainManager(); PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver(); chainResolver.setFilterChainManager(manager); return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver); }
createInstance里面就是构造了一个FilterChainManager和PathMatchingFilterChainResolver,然后将FilterChainManager设置到PathMatchingFilterChainResolver中。下面一一来看。PathMatchingFilterChainResolver就是一个简单的构造函数,如下所示
public PathMatchingFilterChainResolver() { this.pathMatcher = new AntPathMatcher(); this.filterChainManager = new DefaultFilterChainManager(); }
下面重点分析createFilterChainManager这个函数。
createFilterChainManager
protected FilterChainManager createFilterChainManager() { DefaultFilterChainManager manager = new DefaultFilterChainManager(); Map<String, Filter> defaultFilters = manager.getFilters(); //apply global settings if necessary: for (Filter filter : defaultFilters.values()) { applyGlobalPropertiesIfNecessary(filter); } //Apply the acquired and/or configured filters: Map<String, Filter> filters = getFilters(); if (!CollectionUtils.isEmpty(filters)) { for (Map.Entry<String, Filter> entry : filters.entrySet()) { String name = entry.getKey(); Filter filter = entry.getValue(); applyGlobalPropertiesIfNecessary(filter); if (filter instanceof Nameable) { ((Nameable) filter).setName(name); } //'init' argument is false, since Spring-configured filters should be initialized //in Spring (i.e. 'init-method=blah') or implement InitializingBean: manager.addFilter(name, filter, false); } } //build up the chains: Map<String, String> chains = getFilterChainDefinitionMap(); if (!CollectionUtils.isEmpty(chains)) { for (Map.Entry<String, String> entry : chains.entrySet()) { String url = entry.getKey(); String chainDefinition = entry.getValue(); manager.createChain(url, chainDefinition); } } return manager; }
首先构造了一个DefaultFilterChainManager,如下所示
public DefaultFilterChainManager() { this.filters = new LinkedHashMap<String, Filter>(); this.filterChains = new LinkedHashMap<String, NamedFilterList>(); addDefaultFilters(false); }
addDefaultFilters用于添加默认的过滤器,参数false表示不对这些添加的过滤器进行初始化。
protected void addDefaultFilters(boolean init) { for (DefaultFilter defaultFilter : DefaultFilter.values()) { addFilter(defaultFilter.name(), defaultFilter.newInstance(), init, false); } }
那么默认的过滤器都有那些呢?这里简单看一下。
anon(AnonymousFilter.class), authc(FormAuthenticationFilter.class), authcBasic(BasicHttpAuthenticationFilter.class), logout(LogoutFilter.class), noSessionCreation(NoSessionCreationFilter.class), perms(PermissionsAuthorizationFilter.class), port(PortFilter.class), rest(HttpMethodPermissionFilter.class), roles(RolesAuthorizationFilter.class), ssl(SslFilter.class), user(UserFilter.class);
回到createFilterChainManager函数,接下来做了三件事情,第一是对每一个默认的过滤器调用applyGlobalPropertiesIfNecessary进行设置,第二是对每一个自定义的过滤器进行设置并添加到过滤器管理器DefaultFilterChainManager中,第三是调用createChain构造chain(这里叫它过滤器链吧)。过滤器链是什么,就是记录一个url和过滤器之间一对多的关系。例如前面在applicationContext.xml中设置的“/test = anon,/** = authc”,这里的url指的就是“/test”和“/**”,过滤器则由anon和authc来指定。
批注:在createFilterChainManager方法中,首先,将会把默认的过滤器实例化,添加到过滤器链管理器。遍历默认的过滤器,设置全局属性(loginUrl、successUrl、unauthorizedUrl),只有继承自AccessControlFilter才设置loginUrl,AuthenticationFilter->successUrl,AuthorizationFilter-》unauthorizedUrl。然后,获取自定义的过滤器,遍历它们设置全局属性,添加到过滤器链。最后,建立过滤链,添加到FilterChainManager。
补充一张图,看一下filterChainDefinitionMap的结构。以第一个entry为例,url为/logout,chainDefinition为logout,即filter的名称。
下面是DefaultFilterChainManager的createChain方法。
public void createChain(String chainName, String chainDefinition) { if (!StringUtils.hasText(chainName)) { throw new NullPointerException("chainName cannot be null or empty."); } if (!StringUtils.hasText(chainDefinition)) { throw new NullPointerException("chainDefinition cannot be null or empty."); } if (log.isDebugEnabled()) { log.debug("Creating chain [" + chainName + "] from String definition [" + chainDefinition + "]"); } String[] filterTokens = splitChainDefinition(chainDefinition); for (String token : filterTokens) { String[] nameConfigPair = toNameConfigPair(token); addToChain(chainName, nameConfigPair[0], nameConfigPair[1]); } }
splitChainDefinition用于将url和过滤器名字分开,例如/test = anon就变为/test和anon。toNameConfigPair则是将anon这个字段进一步分开,因为这里只有anon,调用过后nameConfigPair[0]=anon,nameConfigPair[1]=null。然后调用addToChain添加到过滤器链中。
批注:上面的表述有误。splitChainDefinition其实用来切割该URL对应的过滤器,因为URL可以映射多个过滤器,下面来一张表看下splitChainDefinition的输出。
输入 | 输出 |
authc, roles[admin,user], perms[file:edit] | { "authc", "roles[admin,user]", "perms[file:edit]" } |
logout,anon | {logout,anon} |
输入 | 输出 |
logout | nameConfigPair[0] = login;nameConfigPair[1] = null |
roles[admin,user] | nameConfigPair[0] = roles;nameConfigPair[1] =admin,user |
public void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) { if (!StringUtils.hasText(chainName)) { throw new IllegalArgumentException("chainName cannot be null or empty."); } Filter filter = getFilter(filterName); if (filter == null) { throw new IllegalArgumentException("There is no filter with name '" + filterName + "' to apply to chain [" + chainName + "] in the pool of available Filters. Ensure a " + "filter with that name/path has first been registered with the addFilter method(s)."); } applyChainConfig(chainName, filter, chainSpecificFilterConfig); NamedFilterList chain = ensureChain(chainName); chain.add(filter); }
getFilter根据过滤器名称获取过滤器,例如这里为anon,则取出AnonymousFilter这个过滤器。applyChainConfig将chainName和chainSpecificFilterConfig设置到filter的成员变量appliedPaths里,第二章会用到这个appliedPaths。
批注:在addToChain(String chainName, String filterName, String chainSpecificFilterConfig) 中,第一个参数是要过滤的URL,第二个参数是过滤器的名字,第三个是上面分解的过滤器的配置。第三个参数会保存到对应filter的数据结构appliedPaths中,它是个map,映射关系是url->config,在applyChainConfig中保存配置。
NamedFilterList就代表了一个过滤器链了,ensureChain的代码如下
protected NamedFilterList ensureChain(String chainName) { NamedFilterList chain = getChain(chainName); if (chain == null) { chain = new SimpleNamedFilterList(chainName); this.filterChains.put(chainName, chain); } return chain; }
ensureChain其实就是构造了一个SimpleNamedFilterList,然后设置到filterChains中。
回到addToChain中,最后就是将过滤器添加到ensureChain中构造的SimpleNamedFilterList中。
批注:
filterChains的结构:
Map<String, NamedFilterList> filterChains
key为url路径,value是NamedFilterList。这里NamedFilterList的实现是SimpleNamedFilterList,它有两个重要的成员变量:
private String name; //也就是SimpleNamedFilterList的名字,其实就是URL private List<Filter> backingList; // 处理该URL下的filter集合
PathMatchingFilterChainResolver
最后构造一个SpringShiroFilter,看一下SpringShiroFilter的整个类。
private static final class SpringShiroFilter extends AbstractShiroFilter { protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) { super(); if (webSecurityManager == null) { throw new IllegalArgumentException("WebSecurityManager property cannot be null."); } setSecurityManager(webSecurityManager); if (resolver != null) { setFilterChainResolver(resolver); } } }
这个构造函数就是简单的赋值。AbstractShiroFilter里面有个重要的doFilterInternal函数,下一章再来分析这个函数。
这里重点再看一下ShiroFilterFactoryBean实现的另一个接口BeanPostProcessor,网上有很多介绍这个接口的文章。如http://uule.iteye.com/blog/2094549所述:
BeanPostProcessor接口作用是:如果我们需要在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。
因此Spring中的BeanPostProcessor在实例化过程处于的位置,BeanPostProcessor接口有两个方法需要实现:postProcessBeforeInitialization和postProcessAfterInitialization。postProcessAfterInitialization为空函数,因此回过头来看一下ShiroFilterFactoryBean中的这个函数。
postProcessBeforeInitialization
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof Filter) { log.debug("Found filter chain candidate filter '{}'", beanName); Filter filter = (Filter) bean; applyGlobalPropertiesIfNecessary(filter); getFilters().put(beanName, filter); } else { log.trace("Ignoring non-Filter bean '{}'", beanName); } return bean; }
这里传入的filter便是前面在applicationContext.xml中定义的customAuthenticationFilter。applyGlobalPropertiesIfNecessary主要和设置url有关,然后将该filter放入ShiroFilterFactoryBean管理的map中。
applyGlobalPropertiesIfNecessary
private void applyGlobalPropertiesIfNecessary(Filter filter) { applyLoginUrlIfNecessary(filter); applySuccessUrlIfNecessary(filter); applyUnauthorizedUrlIfNecessary(filter); }
applyGlobalPropertiesIfNecessary主要就做一件事情,就是设置customAuthenticationFilter中的loginUrl,SuccessUrl和unauthorizedUrl。(由于CustomAuthenticationFilter主要和验证模块相关,并没有继承自AuthorizationFilter,因此关于授权的url就为空)
applyLoginUrlIfNecessary
private void applyLoginUrlIfNecessary(Filter filter) { String loginUrl = getLoginUrl(); if (StringUtils.hasText(loginUrl) && (filter instanceof AccessControlFilter)) { AccessControlFilter acFilter = (AccessControlFilter) filter; String existingLoginUrl = acFilter.getLoginUrl(); if (AccessControlFilter.DEFAULT_LOGIN_URL.equals(existingLoginUrl)) { acFilter.setLoginUrl(loginUrl); } } }
这里简单来说就是做一件事情,如果customAuthenticationFilter中调用的getLoginUrl不为login.jsp(AccessControlFilter.DEFAULT_LOGIN_URL),则保留customAuthenticationFilter的loginUrl。反之,则将customAuthenticationFilter中的loginUrl设置为ShiroFilterFactoryBean中的loginUrl。
applySuccessUrlIfNecessary
private void applySuccessUrlIfNecessary(Filter filter) { String successUrl = getSuccessUrl(); if (StringUtils.hasText(successUrl) && (filter instanceof AuthenticationFilter)) { AuthenticationFilter authcFilter = (AuthenticationFilter) filter; //only apply the successUrl if they haven't explicitly configured one already: String existingSuccessUrl = authcFilter.getSuccessUrl(); if (AuthenticationFilter.DEFAULT_SUCCESS_URL.equals(existingSuccessUrl)) { authcFilter.setSuccessUrl(successUrl); } } }
该函数与applyLoginUrlIfNecessary类似,选择设置或者保留customAuthenticationFilter中的successUrl。默认的AuthenticationFilter.DEFAULT_SUCCESS_URL为”/”(一般为首页)。
applyUnauthorizedUrlIfNecessary
private void applyUnauthorizedUrlIfNecessary(Filter filter) { String unauthorizedUrl = getUnauthorizedUrl(); if (StringUtils.hasText(unauthorizedUrl) && (filter instanceof AuthorizationFilter)) { AuthorizationFilter authzFilter = (AuthorizationFilter) filter; //only apply the unauthorizedUrl if they haven't explicitly configured one already: String existingUnauthorizedUrl = authzFilter.getUnauthorizedUrl(); if (existingUnauthorizedUrl == null) { authzFilter.setUnauthorizedUrl(unauthorizedUrl); } } }
这个函数也和前面两个函数类似,这里就不详细说明了。
好了,关于ShiroFilterFactoryBean的构建大概就这样了,下面一节会开始介绍框架是如何调用的,例如loginUrl是在哪被使用的,以及实现一个自定义的FormAuthenticationFilter。
相关文章推荐
- ShiroFilterFactoryBean源码及拦截原理深入分析
- ShiroFilterFactoryBean源码及阻截原理深入分析
- ShiroFilterFactoryBean源码及阻截原理深入分析
- shiro源码分析之shiroFilter初始化过程
- ShiroFilterFactoryBean分析
- Spring-shiro源码陶冶-DelegatingFilterProxy和ShiroFilterFactoryBean
- Shiro的Filter机制详解---源码分析
- spring初始化refresh()方法中obtainFreshBeanFactory()源码走读。
- 【Spring源码分析】非懒加载的单例Bean初始化过程(上篇)
- 【Spring源码分析】非懒加载的单例Bean初始化过程(下篇)
- Spring源码分析之ProxyFactoryBean方式实现Aop功能的分析
- Spring IOC/BeanFactory/ApplicationContext的工作流程/实现原理/初始化/依赖注入源码详解
- 2、Spring的LocalSessionFactoryBean创建过程源码分析
- 做一个合格的程序猿之浅析Spring IoC源码(二)BeanFactory初始化
- Shiro的Filter机制详解---源码分析
- 做一个合格的程序猿之浅析Spring IoC源码(二)BeanFactory初始化
- Spring源码分析之BeanPostProcessor接口和BeanFactoryPostProcessor接口方法不执行原因分析
- spring源码分析(1)——AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner的初始化
- Spring Security3源码分析-FilterChainProxy初始化
- 分析spring源码第一篇:DefaultListableBeanFactory