From 289fa63ab463ed0677557c4f1664f0b1952fdc25 Mon Sep 17 00:00:00 2001 From: AmyliaY <471816751@qq.com> Date: Thu, 6 Feb 2020 22:41:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E7=BC=AE=E4=B9=8B=E5=89=8D=E7=9A=84?= =?UTF-8?q?=E5=8D=9A=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Spring/AOP/AOP源码实现及分析.md | 1711 +++++----- .../JDK动态代理的实现原理解析.md | 162 +- ...3、将BeanDefinition注册进IoC容器.md | 223 +- docs/Spring/IoC/4、依赖注入(DI).md | 2885 +++++++++-------- .../IoC容器在Web环境中的启动.md | 562 ++-- .../SpringMVC/SpringMVC的设计与实现.md | 243 +- 6 files changed, 2949 insertions(+), 2837 deletions(-) diff --git a/docs/Spring/AOP/AOP源码实现及分析.md b/docs/Spring/AOP/AOP源码实现及分析.md index 1a133a0..1ccb54c 100644 --- a/docs/Spring/AOP/AOP源码实现及分析.md +++ b/docs/Spring/AOP/AOP源码实现及分析.md @@ -1,103 +1,98 @@ -理论性的文字,我觉得就没必要再扯一遍咯,大道理讲这么多,越听越迷糊。不如直接看源码+注解来的明白痛快。所以话不多说,直接上源码。 +理论性的文字,我觉得就没必要再扯一遍咯,大道理讲这么多,越听越迷糊。不如直接看源码加注释来的明白痛快。所以话不多说,直接上源码。 -## 1、主要的接口 -### 1.1、Advice 通知 -定义了切面的增强方式,如:前置增强 BeforeAdvice,后置增强 AfterAdvice,异常增强 ThrowsAdvice 等。下面看两个主要的子接口的源码。 +## 1 主要的接口 +### 1.1 Advice 通知 +本接口定义了切面的增强方式,如:前置增强 BeforeAdvice,后置增强 AfterAdvice,异常增强 ThrowsAdvice 等。下面看两个主要的子接口的源码。 ```java public interface MethodBeforeAdvice extends BeforeAdvice { - /** - * 目标方法 method 要开始执行时,AOP 会回调此方法 - */ - void before(Method method, Object[] args, Object target) throws Throwable; - + /** + * 目标方法 method 开始执行前,AOP 会回调此方法 + */ + void before(Method method, Object[] args, Object target) throws Throwable; } public interface AfterReturningAdvice extends AfterAdvice { - /** - * 目标方法 method 执行后,AOP 会回调此方法,注意,它还传入了 method 的返回值 - */ - void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable; - + /** + * 目标方法 method 执行后,AOP 会回调此方法,注意,它还传入了 method 的返回值 + */ + void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable; } ``` -### 1.2、Pointcut 方法的横切面 -用来定义需要增强的目标方法的集合,一般使用正则表达式去匹配筛选指定范围内的所有满足条件的目标方法。Pointcut 接口有很多实现,我们主要看一下 JdkRegexpMethodPointcut 和 NameMatchMethodPointcut 的实现原理,前者主要通过正则表达式对方法名进行匹配,后者则通过匹配方法名进行匹配。 +### 1.2 Pointcut 方法的横切面 +本接口用来定义需要增强的目标方法的集合,一般使用正则表达式去匹配筛选指定范围内的所有满足条件的目标方法。Pointcut 接口有很多实现,我们主要看一下 JdkRegexpMethodPointcut 和 NameMatchMethodPointcut 的实现原理,前者主要通过正则表达式对方法名进行匹配,后者则通过匹配方法名进行匹配。 ```java - //JdkRegexpMethodPointcut 的实现源码 - private Pattern[] compiledPatterns = new Pattern[0]; - - protected boolean matches(String pattern, int patternIndex) { - Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern); - return matcher.matches(); - } - - //NameMatchMethodPointcut 的实现源码 - private List mappedNames = new LinkedList(); - - public boolean matches(Method method, Class targetClass) { - for (String mappedName : this.mappedNames) { - if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) { - return true; - } - } - return false; - } + // JdkRegexpMethodPointcut 的实现源码 + private Pattern[] compiledPatterns = new Pattern[0]; + + protected boolean matches(String pattern, int patternIndex) { + Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern); + return matcher.matches(); + } + + // NameMatchMethodPointcut 的实现源码 + private List mappedNames = new LinkedList(); + + public boolean matches(Method method, Class targetClass) { + for (String mappedName : this.mappedNames) { + if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) { + return true; + } + } + return false; + } ``` -### 1.3、Advisor 通知器 +### 1.3 Advisor 通知器 将 Pointcut 和 Advice 有效地结合在一起。它定义了在哪些方法(Pointcut)上执行哪些动作(Advice)。下面看一下 DefaultPointcutAdvisor 的源码实现,它通过持有 Pointcut 和 Advice 属性来将两者有效地结合在一起。 ```java public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable { - private Pointcut pointcut = Pointcut.TRUE; - - public DefaultPointcutAdvisor() { - } - - public DefaultPointcutAdvisor(Advice advice) { - this(Pointcut.TRUE, advice); - } - - /** - * 自己定义了 Pointcut,Advice 则使用父类中的定义 - */ - public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) { - this.pointcut = pointcut; - setAdvice(advice); - } + private Pointcut pointcut = Pointcut.TRUE; + + public DefaultPointcutAdvisor() { + } + + public DefaultPointcutAdvisor(Advice advice) { + this(Pointcut.TRUE, advice); + } + + /** + * 自己定义了 Pointcut属性,而 Advice属性 则使用父类中的定义 + */ + public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) { + this.pointcut = pointcut; + setAdvice(advice); + } } public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor { - //本类是一个抽象类,其持有 Advice 的引用,而对 Pointcut 的引用,则在具体的子类中持有 - private Advice advice; - - public void setAdvice(Advice advice) { - this.advice = advice; - } - - public Advice getAdvice() { - return this.advice; - } - - @Override - public String toString() { - return getClass().getName() + ": advice [" + getAdvice() + "]"; - } - + //本类是一个抽象类,其持有 Advice 的引用,而对 Pointcut 的引用,则在具体的子类中持有 + private Advice advice; + + public void setAdvice(Advice advice) { + this.advice = advice; + } + + public Advice getAdvice() { + return this.advice; + } + + @Override + public String toString() { + return getClass().getName() + ": advice [" + getAdvice() + "]"; + } } ``` -## 2、spring AOP 的设计与实现 -AOP 的实现代码中,主要使用了 JDK 动态代理,在特定场景下(被代理对象无 implements 的接口)也用到了 CGLIB 生成代理对象。通过 AOP 的源码设计可以看到,其先为目标对象建立了代理对象,这个代理对象的生成可以使用 JDK 动态代理或 CGLIB 完成。然后启动为代理对象配置的拦截器,对横切面(目标方法集合)进行相应的增强,将 AOP 的横切面设计和 Proxy 模式有机地结合起来,实现了在 AOP 中定义好的各种织入方式。 +## 2 Spring AOP 的设计与实现 +AOP 的实现代码中,主要使用了 JDK 动态代理,在特定场景下(被代理对象没有 implements 的接口)也用到了 CGLIB 生成代理对象。通过 AOP 的源码设计可以看到,其先为目标对象建立了代理对象,这个代理对象的生成可以使用 JDK 动态代理或 CGLIB 完成。然后启动为代理对象配置的拦截器,对横切面(目标方法集合)进行相应的增强,将 AOP 的横切面设计和 Proxy 模式有机地结合起来,实现了在 AOP 中定义好的各种织入方式。 -### 2.1、ProxyFactoryBean -这里我们主要以 ProxyFactoryBean 的实现为例,对 AOP 的实现原理进行分析。ProxyFactoryBean 主要持有目标对象 target 的代理对象 aopProxy,和 Advisor 通知器,而 Advisor 持有 Advice 和 Pointcut,这样就可以判断 aopProxy 中的方法 是否是某个指定的切面 Pointcut,然后根据其配置的织入方向(前置增强/后置增强),通过反射为其织入相应的增强行为 Advice。 - -先看一下 ProxyFactoryBean 的配置和使用。 +### 2.1 ProxyFactoryBean +这里我们主要以 ProxyFactoryBean 的实现为例,对 AOP 的实现原理进行分析。ProxyFactoryBean 主要持有目标对象 target 的代理对象 aopProxy,和 Advisor 通知器,而 Advisor 持有 Advice 和 Pointcut,这样就可以判断 aopProxy 中的方法 是否是某个指定的切面 Pointcut,然后根据其配置的织入方向(前置增强/后置增强),通过反射为其织入相应的增强行为 Advice。先看一下 ProxyFactoryBean 的配置和使用。 ```xml @@ -116,123 +111,120 @@ AOP 的实现代码中,主要使用了 JDK 动态代理,在特定场景下 ``` -### 2.2、ProxyFactoryBean 为配置的 target 生成 AopProxy 代理对象 +### 2.2 为配置的 target 生成 AopProxy 代理对象 ProxyFactoryBean 的 getObject() 方法先对通知器链进行了初始化,然后根据被代理对象类型的不同,生成代理对象。 ```java - /** - * 返回一个代理对象,当用户从 FactoryBean 中获取 bean 时调用, - * 创建此工厂要返回的 AOP 代理的实例,该实例将作为一个单例被缓存 - */ - public Object getObject() throws BeansException { - //初始化通知器链 - initializeAdvisorChain(); - //这里对 Singleton 和 prototype 的类型进行区分,生成对应的 proxy - if (isSingleton()) { - return getSingletonInstance(); - } - else { - if (this.targetName == null) { - logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + - "Enable prototype proxies by setting the 'targetName' property."); - } - return newPrototypeInstance(); - } - } + /** + * 返回一个代理对象,当用户从 FactoryBean 中获取 bean 时调用, + * 创建此工厂要返回的 AOP 代理的实例,该实例将作为一个单例被缓存 + */ + public Object getObject() throws BeansException { + // 初始化通知器链 + initializeAdvisorChain(); + // 这里对 Singleton 和 prototype 的类型进行区分,生成对应的 proxy + if (isSingleton()) { + return getSingletonInstance(); + } + else { + if (this.targetName == null) { + logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + + "Enable prototype proxies by setting the 'targetName' property."); + } + return newPrototypeInstance(); + } + } ``` -### 2.3、initializeAdvisorChain() 初始化 Advisor 链 +### 2.3 初始化 Advisor 链 ```java - /** - * 初始化 Advisor 链,可以发现,其中有通过对 IoC 容器的 getBean() 方法的调用来获取配置好的 advisor 通知器 - */ - private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { - //如果通知器链已经完成初始化,则直接返回 - if (this.advisorChainInitialized) { - return; - } - - if (!ObjectUtils.isEmpty(this.interceptorNames)) { - if (this.beanFactory == null) { - throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " + - "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames)); - } - - if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) && - this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) { - throw new AopConfigException("Target required after globals"); - } - - //这里添加了 Advisor 链的调用,下面的 interceptorNames 是在配置文件中 - //通过 interceptorNames 进行配置的。由于每一个 Advisor 都是被配置为 bean 的, - //所以通过遍历 interceptorNames 得到的 name,其实就是 bean 的 id,通过这个 name(id) - //我们就可以从 IoC 容器中获取对应的实例化 bean - for (String name : this.interceptorNames) { - if (logger.isTraceEnabled()) { - logger.trace("Configuring advisor or advice '" + name + "'"); - } - - if (name.endsWith(GLOBAL_SUFFIX)) { - if (!(this.beanFactory instanceof ListableBeanFactory)) { - throw new AopConfigException( - "Can only use global advisors or interceptors with a ListableBeanFactory"); - } - addGlobalAdvisor((ListableBeanFactory) this.beanFactory, - name.substring(0, name.length() - GLOBAL_SUFFIX.length())); - } - - else { - //对当前的 factoryBean 进行类型判断,是属于单例 bean 还是原型 bean - Object advice; - if (this.singleton || this.beanFactory.isSingleton(name)) { - //通过 beanFactory 的 getBean() 方法获取 advisor, - //这个 name 是从 interceptorNames 中获取的 - advice = this.beanFactory.getBean(name); - } - else { - //如果是原型 bean - advice = new PrototypePlaceholderAdvisor(name); - } - addAdvisorOnChainCreation(advice, name); - } - } - } - - this.advisorChainInitialized = true; - } + /** + * 初始化 Advisor 链,可以发现,其中有通过对 IoC 容器的 getBean() 方法的调用来获取配置好的 advisor 通知器 + */ + private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { + // 如果通知器链已经完成初始化,则直接返回 + if (this.advisorChainInitialized) { + return; + } + + if (!ObjectUtils.isEmpty(this.interceptorNames)) { + if (this.beanFactory == null) { + throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " + + "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames)); + } + + if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) && + this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) { + throw new AopConfigException("Target required after globals"); + } + + // 这里添加了 Advisor 链的调用,下面的 interceptorNames 是在配置文件中 + // 通过 interceptorNames 进行配置的。由于每一个 Advisor 都是被配置为 bean 的, + // 所以通过遍历 interceptorNames 得到的 name,其实就是 bean 的 id,通过这个 name(id) + // 我们就可以从 IoC 容器中获取对应的实例化 bean + for (String name : this.interceptorNames) { + if (logger.isTraceEnabled()) { + logger.trace("Configuring advisor or advice '" + name + "'"); + } + if (name.endsWith(GLOBAL_SUFFIX)) { + if (!(this.beanFactory instanceof ListableBeanFactory)) { + throw new AopConfigException( + "Can only use global advisors or interceptors with a ListableBeanFactory"); + } + addGlobalAdvisor((ListableBeanFactory) this.beanFactory, + name.substring(0, name.length() - GLOBAL_SUFFIX.length())); + } + else { + // 对当前的 factoryBean 进行类型判断,是属于单例 bean 还是原型 bean + Object advice; + if (this.singleton || this.beanFactory.isSingleton(name)) { + // 通过 beanFactory 的 getBean() 方法获取 advisor, + // 这个 name 是从 interceptorNames 中获取的 + advice = this.beanFactory.getBean(name); + } + else { + // 如果是原型 bean + advice = new PrototypePlaceholderAdvisor(name); + } + addAdvisorOnChainCreation(advice, name); + } + } + } + this.advisorChainInitialized = true; + } ``` 生成 singleton 的代理对象在 getSingletonInstance 方法中完成,这是 ProxyFactoryBean 生成 AopProxy 代理对象的调用入口。代理对象会封装对 target 对象的调用,针对 target 对象的方法调用会被这里生成的代理对象所拦截。 -### 2.4、getSingletonInstance() 生成单例代理对象 +### 2.4 生成单例代理对象 ```java - /** - * 返回此类代理对象的单例实例,如果尚未创建该实例,则使用单例模式的懒汉式 创建它 - */ - private synchronized Object getSingletonInstance() { - if (this.singletonInstance == null) { - this.targetSource = freshTargetSource(); - if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { - //根据 AOP 框架来判断需要代理的接口 - Class targetClass = getTargetClass(); - if (targetClass == null) { - throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy"); - } - //设置代理对象的接口 - setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); - } - super.setFrozen(this.freezeProxy); - //这里会通过 AopProxy 来得到代理对象 - this.singletonInstance = getProxy(createAopProxy()); - } - return this.singletonInstance; - } - - /** - * 通过 createAopProxy() 方法返回的 aopProxy 获取代理对象 - */ - protected Object getProxy(AopProxy aopProxy) { - return aopProxy.getProxy(this.proxyClassLoader); - } + /** + * 返回此类代理对象的单例实例,如果尚未创建该实例,则单例地创建它 + */ + private synchronized Object getSingletonInstance() { + if (this.singletonInstance == null) { + this.targetSource = freshTargetSource(); + if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { + // 根据 AOP 框架来判断需要代理的接口 + Class targetClass = getTargetClass(); + if (targetClass == null) { + throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy"); + } + // 设置代理对象的接口 + setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); + } + super.setFrozen(this.freezeProxy); + // 这里会通过 AopProxy 来得到代理对象 + this.singletonInstance = getProxy(createAopProxy()); + } + return this.singletonInstance; + } + + /** + * 通过 createAopProxy()方法 返回的 aopProxy 获取代理对象 + */ + protected Object getProxy(AopProxy aopProxy) { + return aopProxy.getProxy(this.proxyClassLoader); + } ``` 上面的 createAopProxy() 方法,调用了 ProxyFactoryBean 的父类 ProxyCreatorSupport 中的实现。 @@ -240,398 +232,457 @@ ProxyFactoryBean 的 getObject() 方法先对通知器链进行了初始化, ```java public class ProxyCreatorSupport extends AdvisedSupport { - private AopProxyFactory aopProxyFactory; - - public ProxyCreatorSupport() { - //注意这里实例化的是一个 DefaultAopProxyFactory,所以下面的 createAopProxy() 方法 - //中调用的也是 DefaultAopProxyFactory 的实现 - this.aopProxyFactory = new DefaultAopProxyFactory(); - } - - protected final synchronized AopProxy createAopProxy() { - if (!this.active) { - activate(); - } - //调用的是 DefaultAopProxyFactory 的实现 - return getAopProxyFactory().createAopProxy(this); - } - - public AopProxyFactory getAopProxyFactory() { - return this.aopProxyFactory; - } - - public AopProxyFactory getAopProxyFactory() { - return this.aopProxyFactory; - } - + private AopProxyFactory aopProxyFactory; + + public ProxyCreatorSupport() { + // 注意这里实例化的是一个 DefaultAopProxyFactory,所以下面的 createAopProxy() 方法 + // 中调用的也是 DefaultAopProxyFactory 的实现 + this.aopProxyFactory = new DefaultAopProxyFactory(); + } + + protected final synchronized AopProxy createAopProxy() { + if (!this.active) { + activate(); + } + //调用的是 DefaultAopProxyFactory 的实现 + return getAopProxyFactory().createAopProxy(this); + } + + public AopProxyFactory getAopProxyFactory() { + return this.aopProxyFactory; + } + + public AopProxyFactory getAopProxyFactory() { + return this.aopProxyFactory; + } } ``` -下面看一下 AopProxyFactory 接口的实现类 DefaultAopProxyFactory 的代码。 +下面看一下 AopProxyFactory 接口的实现类 DefaultAopProxyFactory 的 createAopProxy(AdvisedSupport config)方法。 ```java - public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { - //AopProxy 代理对象的生成过程: - //首先从 AdvisedSupport 对象中获取配置的 target 目标对象的类型 targetClass, - //然后根据 targetClass 是否为接口采取不同的生成代理对象的策略 - if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { - Class targetClass = config.getTargetClass(); - if (targetClass == null) { - throw new AopConfigException("TargetSource cannot determine target class: " + - "Either an interface or a target is required for proxy creation."); - } - - /** - * !!!!!!!!!!!!!!!!!!!!!!!!!! - * 如果目标类是接口,则使用 JDK 动态代理,否则使用 CGLIB - * !!!!!!!!!!!!!!!!!!!!!!!!!! - */ - if (targetClass.isInterface()) { - return new JdkDynamicAopProxy(config); - } - return CglibProxyFactory.createCglibProxy(config); - } - else { - return new JdkDynamicAopProxy(config); - } - } + public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { + // AopProxy 代理对象的生成过程: + // 首先从 AdvisedSupport 对象中获取配置的 target 目标对象的类型 targetClass, + // 然后根据 targetClass 是否为接口采取不同的生成代理对象的策略 + if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { + Class targetClass = config.getTargetClass(); + if (targetClass == null) { + throw new AopConfigException("TargetSource cannot determine target class: " + + "Either an interface or a target is required for proxy creation."); + } + + /** + * !!!!!!!!!!!!!!!!!!!!!!!!!! + * 如果目标类是接口,则使用 JDK 动态代理,否则使用 CGLIB + * !!!!!!!!!!!!!!!!!!!!!!!!!! + */ + if (targetClass.isInterface()) { + return new JdkDynamicAopProxy(config); + } + return CglibProxyFactory.createCglibProxy(config); + } + else { + return new JdkDynamicAopProxy(config); + } + } ``` -可以看到其根据目标对象是否实现了接口,而决定是使用 JDK 动态代理还是 CGLIB 去生成代理对象,而 AopProxy 接口的实现类也只有 JdkDynamicAopProxy 和 CglibAopProxy 这两个。 +可以看到其根据目标对象是否实现了接口,而决定是使用 JDK动态代理 还是 CGLIB 去生成代理对象,而 AopProxy 接口的实现类也只有 JdkDynamicAopProxy 和 CglibAopProxy 这两个。 -### 2.5、JDK 生成 AopProxy 代理对象 +### 2.5 JDK动态代理 生成 AopProxy代理对象 ```java +/** + * 可以看到,其实现了 InvocationHandler 接口,所以肯定也定义了一个 使用 java.lang.reflect.Proxy + * 动态生成代理对象的方法,并在实现的 invoke() 方法中为代理对象织入增强方法 + */ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { - public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { - Assert.notNull(config, "AdvisedSupport must not be null"); - if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) { - throw new AopConfigException("No advisors and no TargetSource specified"); - } - //这个 advised 是一个 AdvisedSupport 对象,可以通过它获取被代理对象 target - //这样,当 invoke() 方法被代理对象 aopProxy 调用时,就可以调用 target 的目标方法了 - this.advised = config; - } - - public Object getProxy() { - return getProxy(ClassUtils.getDefaultClassLoader()); - } - - public Object getProxy(ClassLoader classLoader) { - if (logger.isDebugEnabled()) { - logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); - } - - //获取代理类要实现的接口 - Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); - findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); - - //通过 Proxy 生成代理对象并返回 - return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); - } + /** AdvisedSupport 持有一个 List属性 */ + private final AdvisedSupport advised; + + public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { + Assert.notNull(config, "AdvisedSupport must not be null"); + if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) { + throw new AopConfigException("No advisors and no TargetSource specified"); + } + // 这个 advised 是一个 AdvisedSupport 对象,可以通过它获取被代理对象 target + // 这样,当 invoke()方法 被 代理对象aopProxy 调用时,就可以调用 target 的目标方法了 + this.advised = config; + } + + public Object getProxy() { + return getProxy(ClassUtils.getDefaultClassLoader()); + } + + public Object getProxy(ClassLoader classLoader) { + if (logger.isDebugEnabled()) { + logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); + } + + // 获取代理类要实现的接口 + Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); + findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); + + // 通过 java.lang.reflect.Proxy 生成代理对象并返回 + return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); + } } ``` -通过 JdkDynamicAopProxy 的源码可以非常清楚地看到,其使用了 JDK 动态代理的方式生成了代理对象。JdkDynamicAopProxy 实现了 InvocationHandler 接口,并通过 Proxy.newProxyInstance() 方法生成代理对象并返回。 +通过 JdkDynamicAopProxy 的源码可以非常清楚地看到,其使用了 JDK动态代理 的方式生成了 代理对象。JdkDynamicAopProxy 实现了 InvocationHandler 接口,并通过 java.lang.reflect.Proxy 的 newProxyInstance()静态方法 生成代理对象并返回。 -### 2.6、CGLIB 生成 AopProxy 代理对象(CglibAopProxy) +### 2.6 CGLIB 生成 AopProxy代理对象 ```java - public Object getProxy(ClassLoader classLoader) { - if (logger.isDebugEnabled()) { - logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource()); - } - - try { - Class rootClass = this.advised.getTargetClass(); - Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); - - Class proxySuperClass = rootClass; - if (ClassUtils.isCglibProxyClass(rootClass)) { - proxySuperClass = rootClass.getSuperclass(); - Class[] additionalInterfaces = rootClass.getInterfaces(); - for (Class additionalInterface : additionalInterfaces) { - this.advised.addInterface(additionalInterface); - } - } - - validateClassIfNecessary(proxySuperClass); - - //创建并配置 Enhancer 对象,Enhancer 是 CGLIB 中主要的操作类 - Enhancer enhancer = createEnhancer(); - if (classLoader != null) { - enhancer.setClassLoader(classLoader); - if (classLoader instanceof SmartClassLoader && - ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { - enhancer.setUseCache(false); - } - } - enhancer.setSuperclass(proxySuperClass); - enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class)); - enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); - enhancer.setInterceptDuringConstruction(false); - - Callback[] callbacks = getCallbacks(rootClass); - enhancer.setCallbacks(callbacks); - enhancer.setCallbackFilter(new ProxyCallbackFilter( - this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); - - Class[] types = new Class[callbacks.length]; - for (int x = 0; x < types.length; x++) { - types[x] = callbacks[x].getClass(); - } - enhancer.setCallbackTypes(types); - - //通过 enhancer 生成代理对象 - Object proxy; - if (this.constructorArgs != null) { - proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs); - } - else { - proxy = enhancer.create(); - } - - return proxy; - } - catch (CodeGenerationException ex) { - throw new AopConfigException("Could not generate CGLIB subclass of class [" + - this.advised.getTargetClass() + "]: " + - "Common causes of this problem include using a final class or a non-visible class", - ex); - } - catch (IllegalArgumentException ex) { - throw new AopConfigException("Could not generate CGLIB subclass of class [" + - this.advised.getTargetClass() + "]: " + - "Common causes of this problem include using a final class or a non-visible class", - ex); - } - catch (Exception ex) { - // TargetSource.getTarget() failed - throw new AopConfigException("Unexpected AOP exception", ex); - } - } +final class CglibAopProxy implements AopProxy, Serializable { + + /** AdvisedSupport 持有一个 List属性 */ + protected final AdvisedSupport advised; + + public Object getProxy(ClassLoader classLoader) { + if (logger.isDebugEnabled()) { + logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource()); + } + + try { + Class rootClass = this.advised.getTargetClass(); + Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); + + Class proxySuperClass = rootClass; + if (ClassUtils.isCglibProxyClass(rootClass)) { + proxySuperClass = rootClass.getSuperclass(); + Class[] additionalInterfaces = rootClass.getInterfaces(); + for (Class additionalInterface : additionalInterfaces) { + this.advised.addInterface(additionalInterface); + } + } + + validateClassIfNecessary(proxySuperClass); + + // 创建并配置 Enhancer对象,Enhancer 是 CGLIB 中主要的操作类 + Enhancer enhancer = createEnhancer(); + if (classLoader != null) { + enhancer.setClassLoader(classLoader); + if (classLoader instanceof SmartClassLoader && + ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { + enhancer.setUseCache(false); + } + } + enhancer.setSuperclass(proxySuperClass); + enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class)); + enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); + enhancer.setInterceptDuringConstruction(false); + + Callback[] callbacks = getCallbacks(rootClass); + enhancer.setCallbacks(callbacks); + enhancer.setCallbackFilter(new ProxyCallbackFilter( + this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); + + Class[] types = new Class[callbacks.length]; + for (int x = 0; x < types.length; x++) { + types[x] = callbacks[x].getClass(); + } + enhancer.setCallbackTypes(types); + + // 通过 enhancer 生成代理对象 + Object proxy; + if (this.constructorArgs != null) { + proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs); + } + else { + proxy = enhancer.create(); + } + + return proxy; + } + catch (CodeGenerationException ex) { + throw new AopConfigException("Could not generate CGLIB subclass of class [" + + this.advised.getTargetClass() + "]: " + + "Common causes of this problem include using a final class or a non-visible class", + ex); + } + catch (IllegalArgumentException ex) { + throw new AopConfigException("Could not generate CGLIB subclass of class [" + + this.advised.getTargetClass() + "]: " + + "Common causes of this problem include using a final class or a non-visible class", + ex); + } + catch (Exception ex) { + // TargetSource.getTarget() failed + throw new AopConfigException("Unexpected AOP exception", ex); + } + } ``` -为目标对象 target 生成代理对象之后,在调用代理对象的目标方法时,目标方法会进行 invoke() 回调或 callbacks() 回调,然后就可以在回调方法中对目标对象的目标方法进行拦截和增强处理了。 +为 目标对象target 生成 代理对象 之后,在调用 代理对象 的目标方法时,目标方法会进行 invoke()回调(JDK动态代理) 或 callbacks()回调(CGLIB),然后就可以在回调方法中对目标对象的目标方法进行拦截和增强处理了。 -## 3、spring AOP 拦截器调用的实现 -在 spring AOP 通过 JDK 的 Proxy 类生成代理对象时,相关的拦截器已经配置到了代理对象持有的 InvocationHandler(即,ProxyBeanFactory) 的 invoke() 方法中,拦截器最后起作用,是通过调用代理对象的目标方法时,在代理类中触发了 InvocationHandler 的 invoke() 回调。通过 CGLIB 实现的 AOP,原理与此相似。 +## 3 Spring AOP 拦截器调用的实现 +在 Spring AOP 通过 JDK 的 Proxy类 生成代理对象时,相关的拦截器已经配置到了代理对象持有的 InvocationHandler(即,ProxyBeanFactory) 的 invoke() 方法中,拦截器最后起作用,是通过调用代理对象的目标方法时,在代理类中触发了 InvocationHandler 的 invoke() 回调。通过 CGLIB 实现的 AOP,原理与此相似。 -### 3.1、JdkDynamicAopProxy 的 invoke() 拦截 -前面已经通过两种不同的方式生成了 AopProxy 代理对象,下面我们先看一下 JdkDynamicAopProxy 中的 invoke() 回调方法中对拦截器调用的实现。 +### 3.1 JdkDynamicAopProxy 的 invoke() 拦截 +前面已经通过两种不同的方式生成了 AopProxy 代理对象,下面我们先看一下 JdkDynamicAopProxy 中的 invoke()回调方法 中对拦截器调用的实现。 ```java - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - MethodInvocation invocation; - Object oldProxy = null; - boolean setProxyContext = false; - - //通过 targetSource 可以获取被代理对象 - TargetSource targetSource = this.advised.targetSource; - Class targetClass = null; - Object target = null; - - try { - //如果目标对象调用的是 Obejct 类中的基本方法,如:equals、hashCode 则进行相应的处理 - if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { - //如果目标对象没有重写 Object 类的基本方法:equals(Object other) - return equals(args[0]); - } - if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { - //如果目标对象没有重写 Object 类的基本方法:hashCode() - return hashCode(); - } - if (!this.advised.opaque && method.getDeclaringClass().isInterface() && - method.getDeclaringClass().isAssignableFrom(Advised.class)) { - //使用代理配置对 ProxyConfig 进行服务调用 - return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); - } - - Object retVal; - - if (this.advised.exposeProxy) { - //如果有必要,可以援引 - oldProxy = AopContext.setCurrentProxy(proxy); - setProxyContext = true; - } - - //获取目标对象,为目标方法的调用做准备 - target = targetSource.getTarget(); - if (target != null) { - targetClass = target.getClass(); - } - - //获取定义好的拦截器链 - List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); - - //如果没有配置拦截器,就直接调用目标对象 target 的 method 方法,并获取返回值 - if (chain.isEmpty()) { - retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); - } - else { - //如果有拦截器链,则需要先调用拦截器链中的拦截器,再调用目标的对应方法 - //这里通过构造 ReflectiveMethodInvocation 来实现 - invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); - //沿着拦截器链继续向下处理 - retVal = invocation.proceed(); - } - - //获取 method 返回值的类型 - Class returnType = method.getReturnType(); - if (retVal != null && retVal == target && returnType.isInstance(proxy) && - !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { - //特殊提醒:它返回“this”,方法的返回类型与类型兼容。 - //注意,如果 target 在另一个返回的对象中设置了对自身的引用,spring 将无法处理 - retVal = proxy; - } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { - throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method); - } - return retVal; - } - finally { - if (target != null && !targetSource.isStatic()) { - //必须来自 TargetSource. - targetSource.releaseTarget(target); - } - if (setProxyContext) { - //存储旧的 proxy. - AopContext.setCurrentProxy(oldProxy); - } - } - } +final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + MethodInvocation invocation; + Object oldProxy = null; + boolean setProxyContext = false; + + //通过 targetSource 可以获取被代理对象 + TargetSource targetSource = this.advised.targetSource; + Class targetClass = null; + Object target = null; + + try { + // 如果目标对象调用的是 Obejct类 中的基本方法,如:equals()、hashCode() 则进行相应的处理 + if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { + // 如果目标对象没有重写 Object类 的基本方法:equals(Object other) + return equals(args[0]); + } + if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { + // 如果目标对象没有重写 Object类 的基本方法:hashCode() + return hashCode(); + } + if (!this.advised.opaque && method.getDeclaringClass().isInterface() && + method.getDeclaringClass().isAssignableFrom(Advised.class)) { + // 使用代理配置对 ProxyConfig 进行服务调用 + return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); + } + + Object retVal; + + if (this.advised.exposeProxy) { + // 如果有必要,可以援引 + oldProxy = AopContext.setCurrentProxy(proxy); + setProxyContext = true; + } + + // 获取目标对象,为目标方法的调用做准备 + target = targetSource.getTarget(); + if (target != null) { + targetClass = target.getClass(); + } + + // 获取定义好的拦截器链,即 Advisor列表 + List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); + + // 如果没有配置拦截器,就直接通过反射调用目标对象 target 的 method对象,并获取返回值 + if (chain.isEmpty()) { + retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); + } + else { + // 如果有拦截器链,则需要先调用拦截器链中的拦截器,再调用目标的对应方法 + // 这里通过构造 ReflectiveMethodInvocation 来实现 + invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); + // 沿着拦截器链继续向下处理 + retVal = invocation.proceed(); + } + + // 获取 method 返回值的类型 + Class returnType = method.getReturnType(); + if (retVal != null && retVal == target && returnType.isInstance(proxy) && + !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { + // 特殊提醒:它返回“this”,方法的返回类型与类型兼容。 + // 注意,如果 target 在另一个返回的对象中设置了对自身的引用,Spring 将无法处理 + retVal = proxy; + } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { + throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method); + } + return retVal; + } + finally { + if (target != null && !targetSource.isStatic()) { + // 必须来自 TargetSource. + targetSource.releaseTarget(target); + } + if (setProxyContext) { + // 存储旧的 proxy. + AopContext.setCurrentProxy(oldProxy); + } + } + } +} ``` -### 3.2、CglibAopProxy 的 intercept() 拦截 +### 3.2 CglibAopProxy 的 intercept() 拦截 CglibAopProxy 的 intercept() 回调方法实现和 JdkDynamicAopProxy 的 invoke() 非常相似,只是在 CglibAopProxy 中构造 CglibMethodInvocation 对象来完成拦截器链的调用,而在 JdkDynamicAopProxy 中则是通过构造 ReflectiveMethodInvocation 对象来完成的。 ```java - public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { - Object oldProxy = null; - boolean setProxyContext = false; - Class targetClass = null; - Object target = null; - try { - if (this.advised.exposeProxy) { - oldProxy = AopContext.setCurrentProxy(proxy); - setProxyContext = true; - } - target = getTarget(); - if (target != null) { - targetClass = target.getClass(); - } - //从 adviced 对象中获取配置好的拦截器链,advised 是一个 AdvisedSupport 对象, - //而 AdvisedSupport 也是 ProxyFactoryBean 的父类之一。 - List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); - Object retVal; - //如果没有配置 AOP 通知,那么直接使用 CGLIB 的 MethodProxy 对象完成对目标方法的调用 - if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { - retVal = methodProxy.invoke(target, args); - } - else { - //通过 CglibMethodInvocation 来启动 advice 通知, - //CglibMethodInvocation 是 ReflectiveMethodInvocation 的子类 - //最终还是调用的 ReflectiveMethodInvocation 对象的 proceed() 方法 - retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); - } - retVal = processReturnType(proxy, target, method, retVal); - return retVal; - } - finally { - if (target != null) { - releaseTarget(target); - } - if (setProxyContext) { - // Restore old proxy. - AopContext.setCurrentProxy(oldProxy); - } - } - } +final class CglibAopProxy implements AopProxy, Serializable { + + public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { + Object oldProxy = null; + boolean setProxyContext = false; + Class targetClass = null; + Object target = null; + try { + if (this.advised.exposeProxy) { + oldProxy = AopContext.setCurrentProxy(proxy); + setProxyContext = true; + } + target = getTarget(); + if (target != null) { + targetClass = target.getClass(); + } + // 从 adviced 对象中获取配置好的拦截器链,advised 是一个 AdvisedSupport对象, + // 而 AdvisedSupport 也是 ProxyFactoryBean 的父类之一。 + List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); + Object retVal; + // 如果没有配置 AOP 通知,那么直接使用 CGLIB 的 MethodProxy 对象完成对目标方法的调用 + if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { + retVal = methodProxy.invoke(target, args); + } + else { + // 通过 CglibMethodInvocation 来启动 advice 通知, + // CglibMethodInvocation 是 ReflectiveMethodInvocation 的子类 + // 最终还是调用的 ReflectiveMethodInvocation 对象的 proceed()方法 + retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); + } + retVal = processReturnType(proxy, target, method, retVal); + return retVal; + } + finally { + if (target != null) { + releaseTarget(target); + } + if (setProxyContext) { + // Restore old proxy. + AopContext.setCurrentProxy(oldProxy); + } + } + } +} ``` -### 3.3、目标对象中目标方法的调用 -对目标对象中目标方法的调用,是在 AopUtils 工具类中利用反射机制完成的。具体代码如下: +### 3.3 目标对象中目标方法的调用 +对目标对象中目标方法的调用,是在 AopUtils 工具类中利用反射机制完成的,具体代码如下。 ```java public abstract class AopUtils { - /** - * 使用 spring 的反射机制,调用目标方法 method 的 invoke 方法 - */ - public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args) - throws Throwable { - - try { - //如果 method 是 private 等不可访问状态,则设置为 public 公开可访问 - ReflectionUtils.makeAccessible(method); - //最后利用反射完成调用 - return method.invoke(target, args); - } - catch (InvocationTargetException ex) { - throw ex.getTargetException(); - } - catch (IllegalArgumentException ex) { - throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" + - method + "] on target [" + target + "]", ex); - } - catch (IllegalAccessException ex) { - throw new AopInvocationException("Could not access method [" + method + "]", ex); - } - } + /** + * 使用 spring 的反射机制,调用目标方法 method 的 invoke 方法 + */ + public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args) + throws Throwable { + + try { + // 如果该 method 是 private的,则将其访问权限设为 public的 + ReflectionUtils.makeAccessible(method); + // 最后利用反射完成调用 + return method.invoke(target, args); + } + catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + catch (IllegalArgumentException ex) { + throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" + + method + "] on target [" + target + "]", ex); + } + catch (IllegalAccessException ex) { + throw new AopInvocationException("Could not access method [" + method + "]", ex); + } + } } ``` -### 3.4、AOP 拦截器链的调用 +### 3.4 AOP 拦截器链的调用 JdkDynamicAopProxy 和 CglibAopProxy 虽然使用了不同的代理对象,但对 AOP 拦截的处理却是相同的,都是通过 ReflectiveMethodInvocation 的 proceed() 方法实现的。 ```java - public Object proceed() throws Throwable { - //从拦截器链中按顺序依次调用拦截器,直到所有的拦截器调用完毕,开始调用目标方法, - //对目标方法的调用是在 invokeJoinpoint() 中通过 AopUtils 的 invokeJoinpointUsingReflection() 方法完成的 - if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { - //invokeJoinpoint() 直接通过 AopUtils 进行目标方法的调用 - return invokeJoinpoint(); - } - - //这里沿着定义好的 interceptorsAndDynamicMethodMatchers 拦截器链进行处理, - //它是一个 List,也没有定义泛型,interceptorOrInterceptionAdvice 是其中的一个元素, - Object interceptorOrInterceptionAdvice = - this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); - if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { - //这里通过拦截器的方法匹配器 methodMatcher 进行方法匹配, - //如果目标类的目标方法和配置的 Pointcut 匹配,那么这个增强行为 advice 将会被执行, - //Pointcut 定义了切面,advice 定义了增强的行为 - InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; - //目标类的目标方法是否为 Pointcut 所定义的切面 - if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { - //执行增强方法 - return dm.interceptor.invoke(this); - } - else { - //如果不匹配,那么 process() 方法会被递归调用,直到所有的拦截器都被运行过为止 - return proceed(); - } - } - else { - //如果 interceptorOrInterceptionAdvice 是一个 MethodInterceptor - //则直接调用其对应的方法 - return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); - } - } +public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable { + + protected final Object proxy; + + protected final Object target; + + protected final Method method; + + protected Object[] arguments; + + private final Class targetClass; + + /** MethodInterceptor和InterceptorAndDynamicMethodMatcher的集合 */ + protected final List interceptorsAndDynamicMethodMatchers; + + private int currentInterceptorIndex = -1; + + protected ReflectiveMethodInvocation(Object proxy, Object target, Method method, + Object[] arguments, Class targetClass, + List interceptorsAndDynamicMethodMatchers) { + + this.proxy = proxy; + this.target = target; + this.targetClass = targetClass; + this.method = BridgeMethodResolver.findBridgedMethod(method); + this.arguments = arguments; + this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers; + } + + public Object proceed() throws Throwable { + // 从拦截器链中按顺序依次调用拦截器,直到所有的拦截器调用完毕,开始调用目标方法,对目标方法的调用 + // 是在 invokeJoinpoint() 中通过 AopUtils 的 invokeJoinpointUsingReflection() 方法完成的 + if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { + // invokeJoinpoint() 直接通过 AopUtils 进行目标方法的调用 + return invokeJoinpoint(); + } + + // 这里沿着定义好的 interceptorsAndDynamicMethodMatchers拦截器链 进行处理, + // 它是一个 List,也没有定义泛型,interceptorOrInterceptionAdvice 是其中的一个元素 + Object interceptorOrInterceptionAdvice = + this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); + if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { + // 这里通过拦截器的 方法匹配器methodMatcher 进行方法匹配, + // 如果 目标类 的 目标方法 和配置的 Pointcut 匹配,那么这个 增强行为advice 将会被执行, + // Pointcut 定义了切面方法(要进行增强的方法),advice 定义了增强的行为 + InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; + // 目标类的目标方法是否为 Pointcut 所定义的切面 + if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { + // 执行当前这个 拦截器interceptor 的 增强方法 + return dm.interceptor.invoke(this); + } + else { + // 如果不匹配,那么 process()方法 会被递归调用,直到所有的拦截器都被运行过为止 + return proceed(); + } + } + else { + // 如果 interceptorOrInterceptionAdvice 是一个 MethodInterceptor + // 则直接调用其对应的方法 + return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); + } + } +} ``` -### 3.5、配置通知器 +### 3.5 配置通知器 AdvisedSupport 中实现了获取拦截器链的方法,并使用了缓存。 ```java - /** - * 获取拦截器链,为提高效率,同时设置了缓存 - */ - public List getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) { - //这里使用了缓存 cached,如果缓存中有就从缓存中获取拦截器链 - //没有,则调用 (DefaultAdvisorChainFactory)advisorChainFactory 的 - //getInterceptorsAndDynamicInterceptionAdvice() 方法进行获取,并缓存到 cached - MethodCacheKey cacheKey = new MethodCacheKey(method); - List cached = this.methodCache.get(cacheKey); - if (cached == null) { - //缓存中没有,则从 AdvisorChainFactory 中获取,然后放进缓存 - cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( - this, method, targetClass); - this.methodCache.put(cacheKey, cached); - } - return cached; - } +public class AdvisedSupport extends ProxyConfig implements Advised { + + /** TargetSource持有一个比较重要的属性,targetClass */ + TargetSource targetSource = EMPTY_TARGET_SOURCE; + + /** 缓存 Method对象 和其对应的 拦截器链列表List */ + private transient Map> methodCache; + + /** The AdvisorChainFactory to use */ + AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory(); + + /** + * 获取拦截器链,为提高效率,同时设置了缓存 + */ + public List getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) { + // 如果 缓存methodCache 中有就从缓存中获取 该Method对象 对应的拦截器链 + // 没有,则调用 (DefaultAdvisorChainFactory)advisorChainFactory 的 + // getInterceptorsAndDynamicInterceptionAdvice() 方法进行获取,并缓存到 methodCache 中 + MethodCacheKey cacheKey = new MethodCacheKey(method); + List cached = this.methodCache.get(cacheKey); + if (cached == null) { + // 缓存中没有,则从 AdvisorChainFactory 中获取,然后放进缓存 + cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( + this, method, targetClass); + this.methodCache.put(cacheKey, cached); + } + return cached; + } +} ``` 获取拦截器链的工作是由 AdvisorChainFactory 完成的,他是一个拦截器链的生成工厂。由于 AdvisorChainFactory 接口只有一个实现类 DefaultAdvisorChainFactory,所以我们直接看这个类中的实现就行咯。 @@ -639,333 +690,335 @@ AdvisedSupport 中实现了获取拦截器链的方法,并使用了缓存。 ```java public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable { - public List getInterceptorsAndDynamicInterceptionAdvice( - Advised config, Method method, Class targetClass) { - - //advisor 链已经在传进来的 config 中持有了,这里可以直接使用 - //advisor 中持有切面 和 增强行为的引用 - List interceptorList = new ArrayList(config.getAdvisors().length); - //判断 config 中的 Advisors 是否符合配置要求 - boolean hasIntroductions = hasMatchingIntroductions(config, targetClass); - - //获取注册器,这是一个单例模式的实现 - AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); - for (Advisor advisor : config.getAdvisors()) { - //advisor 如果是 PointcutAdvisor 的实例 - if (advisor instanceof PointcutAdvisor) { - PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; - if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) { - //拦截器链是通过 AdvisorAdapterRegistry 的实例对象 registry 来加入的, - //AdvisorAdapterRegistry 对 advisor 的织入起到了很大的作用 - MethodInterceptor[] interceptors = registry.getInterceptors(advisor); - //从 pointcutAdvisor 中获取切面的方法匹配器 - MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); - //使用 MethodMatchers 的 matches() 方法对目标类的目标方法进行匹配判断 - if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) { - if (mm.isRuntime()) { - for (MethodInterceptor interceptor : interceptors) { - interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); - } - } - else { - interceptorList.addAll(Arrays.asList(interceptors)); - } - } - } - } - //advisor 如果是 IntroductionAdvisor 的实例 - else if (advisor instanceof IntroductionAdvisor) { - IntroductionAdvisor ia = (IntroductionAdvisor) advisor; - if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) { - Interceptor[] interceptors = registry.getInterceptors(advisor); - interceptorList.addAll(Arrays.asList(interceptors)); - } - } - else { - Interceptor[] interceptors = registry.getInterceptors(advisor); - interceptorList.addAll(Arrays.asList(interceptors)); - } - } - return interceptorList; - } - - /** - * 判断 config 中的 Advisors 是否符合配置要求 - */ - private static boolean hasMatchingIntroductions(Advised config, Class targetClass) { - for (int i = 0; i < config.getAdvisors().length; i++) { - Advisor advisor = config.getAdvisors()[i]; - if (advisor instanceof IntroductionAdvisor) { - IntroductionAdvisor ia = (IntroductionAdvisor) advisor; - if (ia.getClassFilter().matches(targetClass)) { - return true; - } - } - } - return false; - } - + public List getInterceptorsAndDynamicInterceptionAdvice( + Advised config, Method method, Class targetClass) { + + // Advisor链 已经在传进来的 config 中持有了,这里可以直接使用。 + // Advisor 中持有 切面Pointcut 和 增强行为Advice 两个重要属性 + List interceptorList = new ArrayList(config.getAdvisors().length); + // 判断 config 中的 Advisors 是否符合配置要求 + boolean hasIntroductions = hasMatchingIntroductions(config, targetClass); + + // 获取注册器,这是一个单例模式的实现 + AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); + for (Advisor advisor : config.getAdvisors()) { + // advisor 如果是 PointcutAdvisor 的实例 + if (advisor instanceof PointcutAdvisor) { + PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; + if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) { + // 拦截器链是通过 AdvisorAdapterRegistry 的实例对象 registry 来加入的, + // AdvisorAdapterRegistry 对 advisor 的织入起到了很大的作用 + MethodInterceptor[] interceptors = registry.getInterceptors(advisor); + // 从 pointcutAdvisor 中获取切面的方法匹配器 + MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); + // 使用 MethodMatchers 的 matches()方法 对目标类的目标方法进行匹配判断 + if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) { + if (mm.isRuntime()) { + for (MethodInterceptor interceptor : interceptors) { + interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); + } + } + else { + interceptorList.addAll(Arrays.asList(interceptors)); + } + } + } + } + // advisor 如果是 IntroductionAdvisor 的实例 + else if (advisor instanceof IntroductionAdvisor) { + IntroductionAdvisor ia = (IntroductionAdvisor) advisor; + if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) { + Interceptor[] interceptors = registry.getInterceptors(advisor); + interceptorList.addAll(Arrays.asList(interceptors)); + } + } + else { + Interceptor[] interceptors = registry.getInterceptors(advisor); + interceptorList.addAll(Arrays.asList(interceptors)); + } + } + return interceptorList; + } + + /** + * 判断 config 中的 Advisors 是否符合配置要求 + */ + private static boolean hasMatchingIntroductions(Advised config, Class targetClass) { + for (int i = 0; i < config.getAdvisors().length; i++) { + Advisor advisor = config.getAdvisors()[i]; + if (advisor instanceof IntroductionAdvisor) { + IntroductionAdvisor ia = (IntroductionAdvisor) advisor; + if (ia.getClassFilter().matches(targetClass)) { + return true; + } + } + } + return false; + } } ``` 这里的 advisor 通知器是从 AdvisedSupport 中获取的,而 advisor 的初始化则是在 ProxyFactoryBean 的 getObject() 方法中完成的。 ```java - /** - * 返回一个代理对象,当用户从 FactoryBean 中获取 bean 时调用, - * 创建此工厂要返回的 AOP 代理的实例,该实例将作为一个单例被缓存 - */ - public Object getObject() throws BeansException { - //初始化通知器链 - initializeAdvisorChain(); - //这里对 Singleton 和 prototype 的类型进行区分,生成对应的 proxy - if (isSingleton()) { - return getSingletonInstance(); - } - else { - if (this.targetName == null) { - logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + - "Enable prototype proxies by setting the 'targetName' property."); - } - return newPrototypeInstance(); - } - } - - /** - * 初始化 Advisor 链,可以发现,其中有通过对 IoC 容器的 getBean() 方法的调用来获取配置好的 advisor 通知器 - */ - private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { - //如果通知器链已经完成初始化,则直接返回 - if (this.advisorChainInitialized) { - return; - } - - if (!ObjectUtils.isEmpty(this.interceptorNames)) { - if (this.beanFactory == null) { - throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " + - "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames)); - } - - if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) && - this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) { - throw new AopConfigException("Target required after globals"); - } - - //这里添加了 Advisor 链的调用,下面的 interceptorNames 是在配置文件中 - //通过 interceptorNames 进行配置的。由于每一个 Advisor 都是被配置为 bean 的, - //所以通过遍历 interceptorNames 得到的 name,其实就是 bean 的 id,通过这个 name(id) - //我们就可以从 IoC 容器中获取对应的实例化 bean - for (String name : this.interceptorNames) { - if (logger.isTraceEnabled()) { - logger.trace("Configuring advisor or advice '" + name + "'"); - } - - if (name.endsWith(GLOBAL_SUFFIX)) { - if (!(this.beanFactory instanceof ListableBeanFactory)) { - throw new AopConfigException( - "Can only use global advisors or interceptors with a ListableBeanFactory"); - } - addGlobalAdvisor((ListableBeanFactory) this.beanFactory, - name.substring(0, name.length() - GLOBAL_SUFFIX.length())); - } - - else { - //对当前的 factoryBean 进行类型判断,是属于单例 bean 还是原型 bean - Object advice; - if (this.singleton || this.beanFactory.isSingleton(name)) { - //advisor 在文件中配置为 bean,所以这里通过 beanFactory 的 getBean() 方法 - //获取 advisor,这个 name 是从 interceptorNames 中获取的 - advice = this.beanFactory.getBean(name); - } - else { - //如果是原型 bean - advice = new PrototypePlaceholderAdvisor(name); - } - //把从 IoC 容器中获取的 advice 放进 advisors 拦截器链,这个拦截器链是由 ProxyFactoryBean - //的父类 AdvisedSupport 持有的 - addAdvisorOnChainCreation(advice, name); - } - } - } - - this.advisorChainInitialized = true; - } +public class ProxyFactoryBean extends ProxyCreatorSupport + implements FactoryBean, BeanClassLoaderAware, BeanFactoryAware { + + /** + * 返回一个代理对象,当用户从 FactoryBean 中获取 bean 时调用, + * 创建此工厂要返回的 AOP 代理的实例,该实例将作为一个单例被缓存 + */ + public Object getObject() throws BeansException { + // 初始化通知器链 + initializeAdvisorChain(); + // 这里对 Singleton 和 Prototype 的类型进行区分,生成对应的 proxy + if (isSingleton()) { + return getSingletonInstance(); + } + else { + if (this.targetName == null) { + logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + + "Enable prototype proxies by setting the 'targetName' property."); + } + return newPrototypeInstance(); + } + } + + /** + * 初始化 Advisor链,可以发现,其中有通过对 IoC容器 的 getBean() 方法的调用来获取配置好的 advisor 通知器 + */ + private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { + // 如果通知器链已经完成初始化,则直接返回 + if (this.advisorChainInitialized) { + return; + } + + if (!ObjectUtils.isEmpty(this.interceptorNames)) { + if (this.beanFactory == null) { + throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " + + "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames)); + } + + if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) && + this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) { + throw new AopConfigException("Target required after globals"); + } + + // 这里添加了 Advisor链 的调用,下面的 interceptorNames 是在配置文件中 + // 通过 interceptorNames 进行配置的。由于每一个 Advisor 都是被配置为 bean 的, + // 所以通过遍历 interceptorNames 得到的 name,其实就是 bean(Advisor) 的 id,通过这个 name(id) + // 我们就可以从 IoC 容器中获取对应的实例化 bean(Advisor) + for (String name : this.interceptorNames) { + if (logger.isTraceEnabled()) { + logger.trace("Configuring advisor or advice '" + name + "'"); + } + + if (name.endsWith(GLOBAL_SUFFIX)) { + if (!(this.beanFactory instanceof ListableBeanFactory)) { + throw new AopConfigException( + "Can only use global advisors or interceptors with a ListableBeanFactory"); + } + addGlobalAdvisor((ListableBeanFactory) this.beanFactory, + name.substring(0, name.length() - GLOBAL_SUFFIX.length())); + } + + else { + // 对当前的 factoryBean 进行类型判断,是属于 单例bean,还是 原型bean + Object advice; + if (this.singleton || this.beanFactory.isSingleton(name)) { + // advisor 在文件中配置为 bean,所以这里通过 beanFactory 的 getBean()方法 + // 获取 advisor,这个 name 是从 interceptorNames 中获取的 + advice = this.beanFactory.getBean(name); + } + else { + // 如果是 原型bean + advice = new PrototypePlaceholderAdvisor(name); + } + // 把从 IoC容器 中获取的 advice 放进 advisors 拦截器链,这个拦截器链是由 ProxyFactoryBean + // 的父类 AdvisedSupport 持有的 + addAdvisorOnChainCreation(advice, name); + } + } + } + this.advisorChainInitialized = true; + } +} ``` -注意,Advisor 本身就被配置为 bean,所以它的获取也是通过 IoC 容器获得的。 +注意,Advisor 本身就被配置为 bean,所以它的获取也是通过 IoC容器 获得的。 + +### 3.6 Advice 通知的实现 -### 3.6、Advice 通知的实现 从 DefaultAdvisorChainFactory 类中的 getInterceptorsAndDynamicInterceptionAdvice() 方法我们可以看到,其通过 AdvisorAdapterRegistry 实例对象的 getInterceptors() 方法,利用配置的 advisor 完成了对拦截器的适配和注册。 ```java - public List getInterceptorsAndDynamicInterceptionAdvice( - Advised config, Method method, Class targetClass) { - - //advisor 链已经在传进来的 config 中持有了,这里可以直接使用 - //advisor 中持有切面 和 增强行为的引用 - List interceptorList = new ArrayList(config.getAdvisors().length); - //判断 config 中的 Advisors 是否符合配置要求 - boolean hasIntroductions = hasMatchingIntroductions(config, targetClass); - - //获取注册器,这是一个单例模式的实现 - AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); - for (Advisor advisor : config.getAdvisors()) { - //advisor 如果是 PointcutAdvisor 的实例 - if (advisor instanceof PointcutAdvisor) { - PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; - if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) { - //拦截器链是通过 AdvisorAdapterRegistry 的实例对象 registry 来加入的, - //AdvisorAdapterRegistry 对 advisor 的织入起到了很大的作用 - MethodInterceptor[] interceptors = registry.getInterceptors(advisor); - //从 pointcutAdvisor 中获取切面的方法匹配器 - MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); - //使用 MethodMatchers 的 matches() 方法对目标类的目标方法进行匹配判断 - if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) { - if (mm.isRuntime()) { - for (MethodInterceptor interceptor : interceptors) { - interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); - } - } - else { - interceptorList.addAll(Arrays.asList(interceptors)); - } - } - } - } - //advisor 如果是 IntroductionAdvisor 的实例 - else if (advisor instanceof IntroductionAdvisor) { - IntroductionAdvisor ia = (IntroductionAdvisor) advisor; - if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) { - Interceptor[] interceptors = registry.getInterceptors(advisor); - interceptorList.addAll(Arrays.asList(interceptors)); - } - } - else { - Interceptor[] interceptors = registry.getInterceptors(advisor); - interceptorList.addAll(Arrays.asList(interceptors)); - } - } - return interceptorList; - } +public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable { + + public List getInterceptorsAndDynamicInterceptionAdvice( + Advised config, Method method, Class targetClass) { + + // Advisor链 已经在传进来的 config 中持有了,这里可以直接使用 + // Advisor 中持有 切面Pointcut 和 增强行为Advice 的引用 + List interceptorList = new ArrayList(config.getAdvisors().length); + // 判断 config 中的 Advisors 是否符合配置要求 + boolean hasIntroductions = hasMatchingIntroductions(config, targetClass); + + // 获取注册器,这是一个单例模式的实现 + AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); + for (Advisor advisor : config.getAdvisors()) { + // advisor 如果是 PointcutAdvisor 的实例 + if (advisor instanceof PointcutAdvisor) { + PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; + if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) { + // 拦截器链是通过 AdvisorAdapterRegistry 的实例对象 registry 来加入的, + // AdvisorAdapterRegistry 对 advisor 的织入起到了很大的作用 + MethodInterceptor[] interceptors = registry.getInterceptors(advisor); + // 从 pointcutAdvisor 中获取切面的方法匹配器 + MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); + // 使用 MethodMatchers 的 matches()方法 对目标类的目标方法进行匹配判断 + if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) { + if (mm.isRuntime()) { + for (MethodInterceptor interceptor : interceptors) { + interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); + } + } + else { + interceptorList.addAll(Arrays.asList(interceptors)); + } + } + } + } + // advisor 如果是 IntroductionAdvisor 的实例 + else if (advisor instanceof IntroductionAdvisor) { + IntroductionAdvisor ia = (IntroductionAdvisor) advisor; + if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) { + Interceptor[] interceptors = registry.getInterceptors(advisor); + interceptorList.addAll(Arrays.asList(interceptors)); + } + } + else { + Interceptor[] interceptors = registry.getInterceptors(advisor); + interceptorList.addAll(Arrays.asList(interceptors)); + } + } + return interceptorList; + } +} ``` -DefaultAdvisorAdapterRegistry 的 getInterceptors() 方法封装了 advice 织入实现的入口。 +DefaultAdvisorAdapterRegistry 的 getInterceptors()方法 封装了 advice 织入实现的入口。 ```java public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable { - //持有 AdvisorAdapter 的 list,这个 list 中的 AdvisorAdapter 与 - //实现 spring AOP 的 advice 增强功能相对应 - private final List adapters = new ArrayList(3); - - /** - * 将已实现的 AdviceAdapter 加入 list - */ - public DefaultAdvisorAdapterRegistry() { - registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); - registerAdvisorAdapter(new AfterReturningAdviceAdapter()); - registerAdvisorAdapter(new ThrowsAdviceAdapter()); - } - - /** - * 如果 adviceObject 是 Advisor 的实例,则将 adviceObject 转换成 Advisor 类型并返回 - */ - public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { - if (adviceObject instanceof Advisor) { - return (Advisor) adviceObject; - } - if (!(adviceObject instanceof Advice)) { - throw new UnknownAdviceTypeException(adviceObject); - } - Advice advice = (Advice) adviceObject; - if (advice instanceof MethodInterceptor) { - return new DefaultPointcutAdvisor(advice); - } - for (AdvisorAdapter adapter : this.adapters) { - if (adapter.supportsAdvice(advice)) { - return new DefaultPointcutAdvisor(advice); - } - } - throw new UnknownAdviceTypeException(advice); - } - - public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { - List interceptors = new ArrayList(3); - - //从 Advisor 通知器中获取配置的 Advice - Advice advice = advisor.getAdvice(); - - //如果 advice 是 MethodInterceptor 类型的,直接加进 interceptors,不用适配 - if (advice instanceof MethodInterceptor) { - interceptors.add((MethodInterceptor) advice); - } - - //对通知进行适配,使用已经配置好的三种 AdvisorAdapter,然后从对应的 - //adapter 中取出封装好的 AOP 编织功能的拦截器 - for (AdvisorAdapter adapter : this.adapters) { - //adapter.supportsAdvice(advice) 方法中对 advice 的 - //类型进行校验 - if (adapter.supportsAdvice(advice)) { - interceptors.add(adapter.getInterceptor(advisor)); - } - } - if (interceptors.isEmpty()) { - throw new UnknownAdviceTypeException(advisor.getAdvice()); - } - return interceptors.toArray(new MethodInterceptor[interceptors.size()]); - } + // 持有 AdvisorAdapter 的 list,这个 list 中的 AdvisorAdapter 与 + // 实现 Spring AOP 的 advice 增强功能相对应 + private final List adapters = new ArrayList(3); + + /** + * 将已实现的 AdviceAdapter 加入 list + */ + public DefaultAdvisorAdapterRegistry() { + registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); + registerAdvisorAdapter(new AfterReturningAdviceAdapter()); + registerAdvisorAdapter(new ThrowsAdviceAdapter()); + } + + /** + * 如果 adviceObject 是 Advisor 的实例,则将 adviceObject 转换成 Advisor 类型并返回 + */ + public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { + if (adviceObject instanceof Advisor) { + return (Advisor) adviceObject; + } + if (!(adviceObject instanceof Advice)) { + throw new UnknownAdviceTypeException(adviceObject); + } + Advice advice = (Advice) adviceObject; + if (advice instanceof MethodInterceptor) { + return new DefaultPointcutAdvisor(advice); + } + for (AdvisorAdapter adapter : this.adapters) { + if (adapter.supportsAdvice(advice)) { + return new DefaultPointcutAdvisor(advice); + } + } + throw new UnknownAdviceTypeException(advice); + } + + public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { + List interceptors = new ArrayList(3); + + // 从 Advisor 通知器中获取配置的 Advice + Advice advice = advisor.getAdvice(); + + // 如果 advice 是 MethodInterceptor 类型的,直接加进 interceptors,不用适配 + if (advice instanceof MethodInterceptor) { + interceptors.add((MethodInterceptor) advice); + } + + // 对通知进行适配,使用已经配置好的三种 AdvisorAdapter,然后从对应的 + // adapter 中取出封装好的 AOP 编织功能的拦截器 + for (AdvisorAdapter adapter : this.adapters) { + // adapter.supportsAdvice(advice) 方法中对 advice 的类型进行校验 + if (adapter.supportsAdvice(advice)) { + interceptors.add(adapter.getInterceptor(advisor)); + } + } + if (interceptors.isEmpty()) { + throw new UnknownAdviceTypeException(advisor.getAdvice()); + } + return interceptors.toArray(new MethodInterceptor[interceptors.size()]); + } } ``` -从 DefaultAdvisorAdapterRegistry 的实现中可以看到,其使用了一系列的 AdviceAdapter 适配器,如:MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter,它们完全和 advice 的类型 -一一对应,它们都是实现了 AdviceAdapter 接口的同一层次类,各自承担着不同的适配任务,一对一地服务于不同的 advice 实现。下面我们以 MethodBeforeAdviceAdapter 为例,看一下其源码实现。 +从 DefaultAdvisorAdapterRegistry 的实现中可以看到,其使用了一系列的 AdviceAdapter 适配器,如:MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter,它们完全和 Advice 的类型一一对应,它们都是实现了 AdviceAdapter 接口的同一层次类,各自承担着不同的适配任务,一对一地服务于不同的 Advice 实现。下面我们以 MethodBeforeAdviceAdapter 为例,看一下其源码实现。 ```java class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable { - public boolean supportsAdvice(Advice advice) { - return (advice instanceof MethodBeforeAdvice); - } - - public MethodInterceptor getInterceptor(Advisor advisor) { - MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); - return new MethodBeforeAdviceInterceptor(advice); - } - + public boolean supportsAdvice(Advice advice) { + return (advice instanceof MethodBeforeAdvice); + } + + public MethodInterceptor getInterceptor(Advisor advisor) { + MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); + return new MethodBeforeAdviceInterceptor(advice); + } } ``` -可以看到,其中的 getInterceptor() 方法把 advice 从 advisor 中取出来,然后创建了一个 MethodBeforeAdviceInterceptor 对象,并返回,这个对象中持有对 advice 的引用。下面我们看一下 MethodBeforeAdviceInterceptor 拦截器的源码实现。 +可以看到,其中的 getInterceptor()方法 把 Advice 从 Advisor 中取出来,然后创建了一个 MethodBeforeAdviceInterceptor对象,并返回,这个对象中持有对 Advice 的引用。下面我们看一下 MethodBeforeAdviceInterceptor 拦截器的源码实现。 ```java public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable { - private MethodBeforeAdvice advice; - - /** - * 为指定的 advice 创建对应的 MethodBeforeAdviceInterceptor 对象 - */ - public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { - Assert.notNull(advice, "Advice must not be null"); - this.advice = advice; - } - - /** - * 这个 invoke 方法是拦截器的回调方法,会在代理对象的方法被调用时触发回调 - */ - public Object invoke(MethodInvocation mi) throws Throwable { - //首先触发了 advice 的 before() 方法的回调 - //然后才是 MethodInvocation 的 process() 方法回调 - this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); - return mi.proceed(); - } - + private MethodBeforeAdvice advice; + + /** + * 为指定的 advice 创建对应的 MethodBeforeAdviceInterceptor 对象 + */ + public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { + Assert.notNull(advice, "Advice must not be null"); + this.advice = advice; + } + + /** + * 这个 invoke()方法 是拦截器的回调方法,会在代理对象的方法被调用时触发回调 + */ + public Object invoke(MethodInvocation mi) throws Throwable { + // 首先触发了 advice对象 的 before()方法 的回调 + // 然后才是 MethodInvocation 的 process()方法 回调 + this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); + return mi.proceed(); + } } ``` -可以看到,MethodBeforeAdviceInterceptor 的 invoke() 方法先是触发了 advice 的 before() 方法,然后才是 MethodInvocation 的 proceed() 方法调用。 - -回顾一下之前的代码,在 AopProxy 代理对象触发的 ReflectiveMethodInvocation 的 proceed() 中,在取得拦截器 interceptor 后调用了其 invoke() 方法。按照 AOP 的配置规则,ReflectiveMethodInvocation 触发的拦截器 invoke() 回调,最终会根据 advice 类型的不同,触发 spring 对不同的 advice 的拦截器封装,比如 MethodBeforeAdvice 最终会触发 MethodBeforeAdviceInterceptor 的 invoke() 回调,其它两个以此类推,这里就不逐一分析咯。 +可以看到,MethodBeforeAdviceInterceptor 的 invoke()方法 先是触发了 advice 的 before()方法,然后才是 MethodInvocation 的 proceed()方法调用。 -另外,可以结合我 GitHub 上对 spring 框架源码的阅读及个人理解一起看,会更有助于各位开发大佬理解,如果对你们有帮助的,还望各位老爷 watch,star,fork,素质三连一波,地址:https://github.com/AmyliaY/spring-aop-reading +回顾一下之前的代码,在 AopProxy代理对象 触发的 ReflectiveMethodInvocation 的 proceed() 中,在取得 拦截器interceptor 后调用了其 invoke()方法。按照 AOP 的配置规则,ReflectiveMethodInvocation 触发的拦截器 invoke()回调,最终会根据 Advice 类型的不同,触发 Spring 对不同的 Advice 的拦截器封装,比如 MethodBeforeAdvice 最终会触发 MethodBeforeAdviceInterceptor 的 invoke()回调,其它两个以此类推,这里就不逐一分析咯。 +另外,可以结合我 GitHub 上对 Spring框架源码 的阅读及个人理解一起看,会更有助于各位开发大佬理解,如果本内容对你们有帮助的,还望各位同学 watch,star,fork,素质三连一波,地址: +https://github.com/AmyliaY/spring-aop-reading \ No newline at end of file diff --git a/docs/Spring/AOP/JDK动态代理的实现原理解析.md b/docs/Spring/AOP/JDK动态代理的实现原理解析.md index 2729d0a..ade4061 100644 --- a/docs/Spring/AOP/JDK动态代理的实现原理解析.md +++ b/docs/Spring/AOP/JDK动态代理的实现原理解析.md @@ -1,43 +1,42 @@ -最近在看spring AOP部分的源码,所以对JDK动态代理具体是如何实现的这件事产生了很高的兴趣,而且能从源码上了解这个原理的话,也有助于对spring-aop模块的理解。话不多说,上代码。 +最近在看 Spring AOP 部分的源码,所以对JDK动态代理具体是如何实现的这件事产生了很高的兴趣,而且能从源码上了解这个原理的话,也有助于对 spring-aop 模块的理解。话不多说,上代码。 ```java /** - * 一般会使用实现了 InvocationHandler 的类作为代理对象的生产工厂, - * 并且通过持有被代理对象target,来在invoke()方法中对被代理对象的目标方法进行调用和增强, - * 这些我们都能通过下面这段代码看懂,但代理对象是如何生成的?invoke()方法又是如何被调用的呢? + * 一般会使用实现了 InvocationHandler接口 的类作为代理对象的生产工厂, + * 并且通过持有 被代理对象target,来在 invoke()方法 中对被代理对象的目标方法进行调用和增强, + * 这些我们都能通过下面这段代码看懂,但代理对象是如何生成的?invoke()方法 又是如何被调用的呢? */ -public class ProxyFactory implements InvocationHandler{ +public class ProxyFactory implements InvocationHandler { - private Object target = null; - - public Object getInstanse(Object target){ - - this.target = target; - return Proxy.newProxyInstance(target.getClass().getClassLoader(), - target.getClass().getInterfaces(), this); - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable { - - Object ret = null; - System.out.println("前置增强"); - ret = method.invoke(target, args); - System.out.println("后置增强"); - return ret; - } + private Object target = null; + + public Object getInstanse(Object target){ + + this.target = target; + return Proxy.newProxyInstance(target.getClass().getClassLoader(), + target.getClass().getInterfaces(), this); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + + Object ret = null; + System.out.println("前置增强"); + ret = method.invoke(target, args); + System.out.println("后置增强"); + return ret; + } } /** - * 实现了接口MyInterface和接口的play()方法,可以作为被代理类 + * 实现了 接口MyInterface 和接口的 play()方法,可以作为被代理类 */ public class TargetObject implements MyInterface { - @Override - public void play() { - System.out.println("妲己,陪你玩 ~"); - - } + @Override + public void play() { + System.out.println("妲己,陪你玩 ~"); + } } /** @@ -45,58 +44,57 @@ public class TargetObject implements MyInterface { */ public class ProxyTest { - public static void main(String[] args) { - TargetObject target = new TargetObject(); - // ProxyFactory 实现了 InvocationHandler接口,其中的 getInstanse() 方法利用 Proxy 类 - // 生成了target目标对象的代理对象,并返回;且ProxyFactory持有对target的引用,可以在 - // invoke() 中完成对 target 相应方法的调用,以及目标方法前置后置的增强处理 - ProxyFactory proxyFactory = new ProxyFactory(); - // 这个mi就是JDK的 Proxy 类动态生成的代理类 $Proxy0 的实例,该实例中的方法都持有对 - // invoke() 方法的回调,所以当调用其方法时,就能够执行 invoke() 中的增强处理 - MyInterface mi = (MyInterface)proxyFactory.getInstanse(target); - // 这样可以看到 mi 的 Class 到底是什么 - System.out.println(mi.getClass()); - // 这里实际上调用的就是 $Proxy0代理类中对 play() 方法的实现,结合下面的代码可以看到 - // play() 方法通过 super.h.invoke() 完成了对 InvocationHandler对象(proxyFactory)中 - // invoke()方法的回调,所以我们才能够通过 invoke() 方法实现对 target 对象方法的 - // 前置后置增强处理 - mi.play(); - // 总的来说,就是在invoke()方法中完成target目标方法的调用,及前置后置增强, - // JDK动态生成的代理类中对 invoke() 方法进行了回调 - } - - /** - * 将ProxyGenerator生成的动态代理类的输出到文件中,利用反编译工具luyten等就可 - * 以看到生成的代理类的源码咯,下面给出了其反编译好的代码实现 - */ - @Test - public void generatorSrc(){ - byte[] bytesFile = ProxyGenerator.generateProxyClass("$Proxy0", TargetObject.class.getInterfaces()); - FileOutputStream fos = null; - try{ - String path = System.getProperty("user.dir") + "\\$Proxy0.class"; - File file = new File(path); - fos = new FileOutputStream(file); - fos.write(bytesFile); - fos.flush(); - } catch (Exception e){ - e.printStackTrace(); - } finally{ - try { - fos.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } + public static void main(String[] args) { + TargetObject target = new TargetObject(); + // ProxyFactory 实现了 InvocationHandler接口,其中的 getInstanse()方法 利用 Proxy类 + // 生成了 target目标对象 的代理对象,并返回;且 ProxyFactory 持有对 target 的引用,可以在 + // invoke() 中完成对 target 相应方法的调用,以及目标方法前置后置的增强处理 + ProxyFactory proxyFactory = new ProxyFactory(); + // 这个 mi 就是 JDK 的 Proxy类 动态生成的代理类 $Proxy0 的实例,该实例中的方法都持有对 + // invoke()方法 的回调,所以当调用其方法时,就能够执行 invoke() 中的增强处理 + MyInterface mi = (MyInterface) proxyFactory.getInstanse(target); + // 这样可以看到 mi 的 Class 到底是什么 + System.out.println(mi.getClass()); + // 这里实际上调用的就是 $Proxy0代理类 中对 play()方法 的实现,结合下面的代码可以看到 + // play()方法 通过 super.h.invoke() 完成了对 InvocationHandler对象(proxyFactory)中 + // invoke()方法 的回调,所以我们才能够通过 invoke()方法 实现对 target对象 方法的 + // 前置后置增强处理 + mi.play(); + // 总的来说,就是在 invoke()方法 中完成 target目标方法 的调用,及前置后置增强, + // JDK 动态生成的代理类中对 invoke()方法 进行了回调 + } + + /** + * 将 ProxyGenerator 生成的动态代理类的输出到文件中,利用反编译工具 luyten 等就可 + * 以看到生成的代理类的源码咯,下面给出了其反编译好的代码实现 + */ + @Test + public void generatorSrc(){ + byte[] bytesFile = ProxyGenerator.generateProxyClass("$Proxy0", TargetObject.class.getInterfaces()); + FileOutputStream fos = null; + try{ + String path = System.getProperty("user.dir") + "\\$Proxy0.class"; + File file = new File(path); + fos = new FileOutputStream(file); + fos.write(bytesFile); + fos.flush(); + } catch (Exception e){ + e.printStackTrace(); + } finally{ + try { + fos.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } } /** - * Proxy生成的代理类,可以看到,其继承了Proxy,并且实现了被代理类的接口 + * Proxy 生成的代理类,可以看到,其继承了 Proxy,并且实现了 被代理类的接口MyInterface */ -public final class $Proxy0 extends Proxy implements MyInterface -{ +public final class $Proxy0 extends Proxy implements MyInterface { private static Method m1; private static Method m0; private static Method m3; @@ -106,7 +104,7 @@ public final class $Proxy0 extends Proxy implements MyInterface try { $Proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); $Proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class[])new Class[0]); - //实例化MyInterface的play方法 + // 实例化 MyInterface 的 play()方法 $Proxy0.m3 = Class.forName("com.shuitu.test.MyInterface").getMethod("play", (Class[])new Class[0]); $Proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class[])new Class[0]); } @@ -124,9 +122,9 @@ public final class $Proxy0 extends Proxy implements MyInterface public final void play() { try { - // 这个 h 其实就是我们调用 Proxy.newProxyInstance() 方法时传进去的ProxyFactory(InvocationHandler对象), - // 该对象的 invoke() 方法中实现了对目标对象的目标方法的增强。看到这里,利用动态代理实现方法增强的 - // 实现原理就全部理清咯 + // 这个 h 其实就是我们调用 Proxy.newProxyInstance()方法 时传进去的 ProxyFactory对象(它实现了 + // InvocationHandler接口),该对象的 invoke()方法 中实现了对目标对象的目标方法的增强。 + // 看到这里,利用动态代理实现方法增强的实现原理就全部理清咯 super.h.invoke(this, $Proxy0.m3, null); } catch (Error | RuntimeException error) { diff --git a/docs/Spring/IoC/3、将BeanDefinition注册进IoC容器.md b/docs/Spring/IoC/3、将BeanDefinition注册进IoC容器.md index bf6fb44..7c0759b 100644 --- a/docs/Spring/IoC/3、将BeanDefinition注册进IoC容器.md +++ b/docs/Spring/IoC/3、将BeanDefinition注册进IoC容器.md @@ -1,116 +1,133 @@ -这篇文章分享一下 spring IoC 容器初始化第三部分的代码,也就是将前面解析得到的 BeanDefinition 注册进 IoC 容器,其实就是存入一个 ConcurrentHashMap 中。 - -(PS:可以结合我 GitHub 上对 spring 框架源码的翻译注解一起看,会更有助于各位同学理解,地址: - -spring-beans https://github.com/AmyliaY/spring-beans-reading +## 前言 +这篇文章分享一下 spring IoC 容器初始化第三部分的代码,也就是将前面解析出来的 BeanDefinition对象 注册进 IoC 容器,其实就是存入一个 ConcurrentHashMap 中。 +(PS:可以结合我 GitHub 上对 Spring 框架源码的翻译注释一起看,会更有助于各位同学理解,地址: +spring-beans https://github.com/AmyliaY/spring-beans-reading spring-context https://github.com/AmyliaY/spring-context-reading ) -## 1、回过头看一下前面在 DefaultBeanDefinitionDocumentReader 中实现的 processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法 + +## 正文 +回过头看一下前面在 DefaultBeanDefinitionDocumentReader 中实现的 processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法。 ```java - // 解析 Bean 定义资源 Document 对象的普通元素 - protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { - - // BeanDefinitionHolder 是对 BeanDefinition 的封装,即 BeanDefinition 的封装类 - // 对 Document 对象中 元素的解析由 BeanDefinitionParserDelegate 实现 - BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); - if (bdHolder != null) { - // 对 bdHolder 进行包装处理 - bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); - try { - /** - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * 向 Spring IoC 容器注册解析 BeanDefinition,这是 BeanDefinition 向 IoC 容器注册的入口 - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - */ - BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); - } - catch (BeanDefinitionStoreException ex) { - getReaderContext().error("Failed to register bean definition with name '" + - bdHolder.getBeanName() + "'", ele, ex); - } - // 在完成向 Spring IOC 容器注册解析得到的 Bean 定义之后,发送注册事件 - getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); - } - } +/** + * 将 .xml 文件中的元素解析成 BeanDefinition对象,并注册到 IoC容器 中 + */ +protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { + + // BeanDefinitionHolder 是对 BeanDefinition 的进一步封装,它持有一个 BeanDefinition 对象 及其对应 + // 的 beanName、aliases别名。 + // 对 Document 对象中 元素的解析由 BeanDefinitionParserDelegate 实现 + BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); + if (bdHolder != null) { + // 对 bdHolder 进行包装处理 + bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); + try { + /** + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * 向 IoC 容器注册解析完成的 BeanDefinition对象,这是 BeanDefinition 向 IoC 容器注册的入口 + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); + } + catch (BeanDefinitionStoreException ex) { + getReaderContext().error("Failed to register bean definition with name '" + + bdHolder.getBeanName() + "'", ele, ex); + } + // 在完成向 IOC容器 注册 BeanDefinition对象 之后,发送注册事件 + getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); + } +} ``` -## 2、BeanDefinitionReaderUtils 的 registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) 方法 +接着看一下 BeanDefinitionReaderUtils 的 registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) 方法。 ```java - // 将解析的 BeanDefinitionHold 注册到容器中 - public static void registerBeanDefinition( - BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) - throws BeanDefinitionStoreException { +/** + * 将解析到的 BeanDefinition对象 注册到 IoC容器 + */ +public static void registerBeanDefinition( + BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) + throws BeanDefinitionStoreException { - // 获取解析的 BeanDefinition 的名称 - String beanName = definitionHolder.getBeanName(); - /** - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * 开始向 IOC 容器注册 BeanDefinition - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - */ - registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); + // 获取解析的 元素 的名称 beanName + String beanName = definitionHolder.getBeanName(); + /** + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * 开始向 IoC容器 注册 BeanDefinition对象 + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); - // 如果解析的 BeanDefinition 有别名,向容器为其注册别名 - String[] aliases = definitionHolder.getAliases(); - if (aliases != null) { - for (String aliase : aliases) { - registry.registerAlias(beanName, aliase); - } - } - } + // 如果解析的 元素 有别名alias,向容器中注册别名 + String[] aliases = definitionHolder.getAliases(); + if (aliases != null) { + for (String aliase : aliases) { + registry.registerAlias(beanName, aliase); + } + } +} ``` -## 3、BeanDefinitionRegistry 中的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法在 DefaultListableBeanFactory 实现类中的具体实现 +BeanDefinitionRegistry 中的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法在 DefaultListableBeanFactory 实现类中的具体实现。 ```java - // 向 IoC 容器注册解析的 BeanDefinito - public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) - throws BeanDefinitionStoreException { +public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory + implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { - Assert.hasText(beanName, "Bean name must not be empty"); - Assert.notNull(beanDefinition, "BeanDefinition must not be null"); + /** 按注册顺序排列的 beanDefinition名称列表(即 beanName) */ + private final List beanDefinitionNames = new ArrayList(); - // 校验解析的 BeanDefiniton - if (beanDefinition instanceof AbstractBeanDefinition) { - try { - ((AbstractBeanDefinition) beanDefinition).validate(); - } - catch (BeanDefinitionValidationException ex) { - throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, - "Validation of bean definition failed", ex); - } - } - - // 注册的过程中需要线程同步,以保证数据的一致性 - synchronized (this.beanDefinitionMap) { - Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); - - // 检查是否有同名的 BeanDefinition 已经在 IOC 容器中注册,如果已经注册, - // 并且不允许覆盖已注册的 BeanDefinition,则抛出注册失败异常, - // allowBeanDefinitionOverriding 默认为 true - if (oldBeanDefinition != null) { - if (!this.allowBeanDefinitionOverriding) { - throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, - "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + - "': There is already [" + oldBeanDefinition + "] bound."); - } - else {// 如果允许覆盖,则同名的 Bean,后注册的覆盖先注册的 - if (this.logger.isInfoEnabled()) { - this.logger.info("Overriding bean definition for bean '" + beanName + - "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); - } - } - } - else {// IOC 容器中没有已经注册同名的 Bean,按正常注册流程注册 - this.beanDefinitionNames.add(beanName); - this.frozenBeanDefinitionNames = null; - } - this.beanDefinitionMap.put(beanName, beanDefinition); - } - // 重置所有已经注册过的 BeanDefinition 的缓存 - resetBeanDefinition(beanName); - } -``` -## 最后看一下 spring 的 IoC 容器在代码中最直接的体现 -```java - // 存储注册信息的 BeanDefinition 集合,也就是所谓的 IoC 容器 - private final Map beanDefinitionMap = new ConcurrentHashMap(64); + /** IoC容器 的实际体现,key --> beanName,value --> BeanDefinition对象 */ + private final Map beanDefinitionMap = new ConcurrentHashMap(64); + + /** + * 向 IoC容器 注册解析的 beanName 和 BeanDefinition对象 + */ + public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) + throws BeanDefinitionStoreException { + + Assert.hasText(beanName, "Bean name must not be empty"); + Assert.notNull(beanDefinition, "BeanDefinition must not be null"); + + // 校验解析的 BeanDefiniton对象 + if (beanDefinition instanceof AbstractBeanDefinition) { + try { + ((AbstractBeanDefinition) beanDefinition).validate(); + } + catch (BeanDefinitionValidationException ex) { + throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, + "Validation of bean definition failed", ex); + } + } + + // 注册的过程中需要线程同步,以保证数据的一致性 + synchronized (this.beanDefinitionMap) { + Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); + + // 检查是否有同名(beanName)的 BeanDefinition 存在于 IoC容器 中,如果已经存在,且不允许覆盖 + // 已注册的 BeanDefinition,则抛出注册异常,allowBeanDefinitionOverriding 默认为 true + if (oldBeanDefinition != null) { + if (!this.allowBeanDefinitionOverriding) { + throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, + "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + + "': There is already [" + oldBeanDefinition + "] bound."); + } + // 如果允许覆盖同名的 bean,后注册的会覆盖先注册的 + else { + if (this.logger.isInfoEnabled()) { + this.logger.info("Overriding bean definition for bean '" + beanName + + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); + } + } + } + // 若该 beanName 在 IoC容器 中尚未注册,将其注册到 IoC容器中, + else { + // 将 beanName 注册到 beanDefinitionNames列表 + this.beanDefinitionNames.add(beanName); + this.frozenBeanDefinitionNames = null; + } + // beanDefinitionMap 是 IoC容器 的最主要体现,他是一个 ConcurrentHashMap, + // 直接存储了 bean的唯一标识 beanName,及其对应的 BeanDefinition对象 + this.beanDefinitionMap.put(beanName, beanDefinition); + } + // 重置所有已经注册过的 BeanDefinition 的缓存 + resetBeanDefinition(beanName); + } +} ``` \ No newline at end of file diff --git a/docs/Spring/IoC/4、依赖注入(DI).md b/docs/Spring/IoC/4、依赖注入(DI).md index 24d77a2..e501f8f 100644 --- a/docs/Spring/IoC/4、依赖注入(DI).md +++ b/docs/Spring/IoC/4、依赖注入(DI).md @@ -1,1448 +1,1499 @@ -前面我们主要分析了 FileSystemXmlApplicationContext 这个具体的 IoC 容器的初始化源码实现,在 IoC 容器中建立了 BeanDefinition 的数据映射,将其和 beanName 一起绑定在一个 ConcurrentHashMap 中。现在我们来看一下 spring 是如何将 IoC 容器中的 Bean 根据配置关联在一起的。 +## 前言 +前面我们主要分析了 FileSystemXmlApplicationContext 这个具体的 IoC容器实现类 的初始化源码,在 IoC容器 中建立了 beanName 到 BeanDefinition 的数据映射,通过一个 ConcurrentHashMap。现在我们来看一下 Spring 是如何将 IoC 容器中存在依赖关系的 bean 根据配置联系在一起的。 -Spring 中触发 IoC 容器“依赖注入”的方式有两种,一个是通过 getBean() 向容器索要 bean 时触发依赖注入;另一个是给 bean 配置 lazy-init 属性,spring 会自动调用此 bean 的 getBean() 方法,提前完成依赖注入。总的来说,想提高运行时获取 bean 的效率,可以考虑配置此属性。 +Spring 中触发 IoC容器“依赖注入” 的方式有两种,一个是应用程序通过 getBean()方法 向容器索要 bean实例 时触发依赖注入;另一个是提前给 bean 配置了 lazy-init 属性为 false,Spring 在 IoC容器 初始化会自动调用此 bean 的 getBean() 方法,提前完成依赖注入。总的来说,想提高运行时获取 bean 的效率,可以考虑配置此属性。 -下面我将分别解读这两种依赖注入的触发方式,先看 getBean() 的,因为 lazy-init 最后也是通过调用 getBean 完成的依赖注入。 +下面我将分别解读这两种依赖注入的触发方式,先看 getBean() 的,因为 lazy-init 最后也是通过调用 getBean() 完成的依赖注入。 -(PS:可以结合我 GitHub 上对 spring 框架源码的阅读及个人理解一起看,会更有助于各位开发姥爷理解,地址: - -spring-beans https://github.com/AmyliaY/spring-beans-reading - +(PS:可以结合我 GitHub 上对 Spring 框架源码的阅读及个人理解一起看,会更有助于各位开发姥爷理解,地址: +spring-beans https://github.com/AmyliaY/spring-beans-reading spring-context https://github.com/AmyliaY/spring-context-reading ) -## 1、AbstractBeanFactory 中的 getBean() 系列方法及 doGetBean() 具体实现 -```java - //--------------------------------------------------------------------- - // BeanFactory 接口的实现,下列的 getBean() 方法不论是哪种重载,最后都会走 - // doGetBean(final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) 的具体实现 - //--------------------------------------------------------------------- - - // 获取 IOC 容器中指定名称的 Bean - public Object getBean(String name) throws BeansException { - return doGetBean(name, null, null, false); - } - - // 获取 IOC 容器中指定名称和类型的 Bean - public T getBean(String name, Class requiredType) throws BeansException { - return doGetBean(name, requiredType, null, false); - } - - // 获取 IOC 容器中指定名称和参数的 Bean - public Object getBean(String name, Object... args) throws BeansException { - return doGetBean(name, null, args, false); - } - - // 获取 IOC 容器中指定名称、类型和参数的 Bean - public T getBean(String name, Class requiredType, Object... args) throws BeansException { - return doGetBean(name, requiredType, args, false); - } - - // 真正实现向 IOC 容器获取 Bean 的功能,也是触发依赖注入 (DI) 功能的地方 - @SuppressWarnings("unchecked") - protected T doGetBean(final String name, final Class requiredType, final Object[] args, - boolean typeCheckOnly) throws BeansException { - - // 根据用户指定的名称获取 IoC 容器中与 BeanDefinition 对应的 beanName - // 如果指定的是别名,则将别名转换为规范的 beanName - final String beanName = transformedBeanName(name); - Object bean; - - // 先查看缓存中是否有对应的,已创建的单例 Bean,对于单例 Bean,整个 IOC 容器中只创建一次 - Object sharedInstance = getSingleton(beanName); - if (sharedInstance != null && args == null) { - if (logger.isDebugEnabled()) { - if (isSingletonCurrentlyInCreation(beanName)) { - logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + - "' that is not fully initialized yet - a consequence of a circular reference"); - } - else { - logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); - } - } - // 获取给定 Bean 的实例对象,主要是完成 FactoryBean 的相关处理 - // 注意:BeanFactory 本质上是一个 IoC 容器,而 FactoryBean 是 IoC 容器中一种特殊的工厂 bean - // 能够生产其他对象,注意两者之间的区别 - bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); - } - - else { - if (isPrototypeCurrentlyInCreation(beanName)) { - throw new BeanCurrentlyInCreationException(beanName); - } - - // 获取当前容器的父容器 - BeanFactory parentBeanFactory = getParentBeanFactory(); - // 如果当前容器中没有指定的 bean,且当前容器的父容器不为空 - // 则从父容器中去找,如果父容器也没有,则沿着当前容器的继承体系一直向上查找 - if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { - // 解析指定 Bean 名称的原始名称 - String nameToLookup = originalBeanName(name); - if (args != null) { - // 委派父级容器根据指定名称和显式的参数查找 - return (T) parentBeanFactory.getBean(nameToLookup, args); - } - else { - // 委派父容器根据指定名称和类型查找 - return parentBeanFactory.getBean(nameToLookup, requiredType); - } - } - - // 创建的 Bean 是否需要进行类型验证,一般不需要 - if (!typeCheckOnly) { - // 向容器标记指定的 Bean 已经被创建 - markBeanAsCreated(beanName); - } - - try { - // 根据 beanName 获取对应的 RootBeanDefinition - final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); - checkMergedBeanDefinition(mbd, beanName, args); - - // 获取当前 Bean 依赖的所有 Bean,下面的 getBean(dependsOnBean) 方法会触发 getBean() 的递归调用, - // 直到取到一个不依赖任何其它 bean 的 bean 为止 - String[] dependsOn = mbd.getDependsOn(); - if (dependsOn != null) { - for (String dependsOnBean : dependsOn) { - // 递归调用 getBean() 方法,获取当前 Bean 所依赖的 bean - getBean(dependsOnBean); - // 把当前 bean 所依赖的 bean 进行注入 - //(也就是通过 setter 或构造方法将依赖的 bean 赋值给当前 bean 对应的属性) - registerDependentBean(dependsOnBean, beanName); - } - } - // 创建单例模式 bean 的实例对象 - if (mbd.isSingleton()) { - // 这里使用了一个匿名内部类,创建 Bean 实例对象,并且注册给所依赖的对象 - sharedInstance = getSingleton(beanName, new ObjectFactory() { - public Object getObject() throws BeansException { - try { - // 创建一个指定 Bean 实例对象,如果有父级继承,则合并子类和父类的定义 - return createBean(beanName, mbd, args); - } - catch (BeansException ex) { - destroySingleton(beanName); - throw ex; - } - } - }); - // 获取给定 Bean 的实例对象 - bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); - } - - // IoC 容器创建原型模式 Bean 实例对象 - else if (mbd.isPrototype()) { - // 原型模式 (Prototype) 是每次都会创建一个新的对象 - Object prototypeInstance = null; - try { - // 回调 beforePrototypeCreation 方法,默认的功能是注册当前创建的原型对象 - beforePrototypeCreation(beanName); - // 创建指定 Bean 对象实例 - prototypeInstance = createBean(beanName, mbd, args); - } - finally { - // 回调 afterPrototypeCreation 方法,默认的功能告诉 IoC 容器指定 Bean 的原型对象不再创建了 - afterPrototypeCreation(beanName); - } - // 获取给定 Bean 的实例对象 - bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); - } - - // 要创建的 Bean 既不是单例模式,也不是原型模式,则根据 Bean 定义资源中 - // 配置的生命周期范围,选择实例化 Bean 的合适方法,这种在 Web 应用程序中 - // 比较常用,如:request、session、application 等的生命周期 - else { - // 获取此 bean 生命周期的范围 - String scopeName = mbd.getScope(); - final Scope scope = this.scopes.get(scopeName); - // Bean 定义资源中没有配置生命周期范围,则 Bean 定义不合法 - if (scope == null) { - throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'"); - } - try { - // 这里又使用了一个匿名内部类,获取一个指定生命周期范围的实例 - Object scopedInstance = scope.get(beanName, new ObjectFactory() { - public Object getObject() throws BeansException { - beforePrototypeCreation(beanName); - try { - return createBean(beanName, mbd, args); - } - finally { - afterPrototypeCreation(beanName); - } - } - }); - // 获取给定 Bean 的实例对象 - bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); - } - catch (IllegalStateException ex) { - throw new BeanCreationException(beanName, - "Scope '" + scopeName + "' is not active for the current thread; " + - "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", - ex); - } - } - } - catch (BeansException ex) { - cleanupAfterBeanCreationFailure(beanName); - throw ex; - } - } - - // 对创建的 bean 实例对象进行非空验证和类型检查,如果没问题就返回这个已经完成依赖注入的 bean - if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { - try { - return getTypeConverter().convertIfNecessary(bean, requiredType); - } - catch (TypeMismatchException ex) { - if (logger.isDebugEnabled()) { - logger.debug("Failed to convert bean '" + name + "' to required type [" + - ClassUtils.getQualifiedName(requiredType) + "]", ex); - } - throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); - } - } - return (T) bean; - } +## 正文 +首先看一下 AbstractBeanFactory 中的 getBean() 系列方法及 doGetBean() 具体实现。 +```java +public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { + + //--------------------------------------------------------------------- + // BeanFactory 接口的实现,下列的 getBean() 方法不论是哪种重载,最后都会走 + // doGetBean(final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) 的具体实现 + //--------------------------------------------------------------------- + + // 获取 IoC容器 中指定名称的 bean + public Object getBean(String name) throws BeansException { + return doGetBean(name, null, null, false); + } + + // 获取 IoC容器 中指定名称和类型的 bean + public T getBean(String name, Class requiredType) throws BeansException { + return doGetBean(name, requiredType, null, false); + } + + // 获取 IoC容器 中指定名称和参数的 bean + public Object getBean(String name, Object... args) throws BeansException { + return doGetBean(name, null, args, false); + } + + // 获取 IoC容器 中指定名称、类型和参数的 bean + public T getBean(String name, Class requiredType, Object... args) throws BeansException { + return doGetBean(name, requiredType, args, false); + } + + // 真正实现向 IoC容器 获取 bean 的功能,也是触发 依赖注入(DI) 的地方 + @SuppressWarnings("unchecked") + protected T doGetBean(final String name, final Class requiredType, final Object[] args, + boolean typeCheckOnly) throws BeansException { + + // 根据用户给定的名称(也可能是别名alias) 获取 IoC容器 中与 BeanDefinition 唯一对应的 beanName + final String beanName = transformedBeanName(name); + Object bean; + + // 根据 beanName 查看缓存中是否有已实例化的 单例bean,对于 单例bean,整个 IoC容器 只创建一次 + Object sharedInstance = getSingleton(beanName); + if (sharedInstance != null && args == null) { + if (logger.isDebugEnabled()) { + if (isSingletonCurrentlyInCreation(beanName)) { + logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + + "' that is not fully initialized yet - a consequence of a circular reference"); + } + else { + logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); + } + } + // 获取给定 bean 的实例对象,主要是完成 FactoryBean 的相关处理 + // 注意:BeanFactory 是一个 IoC容器,它保存了 bean 的基本配置信息。 + // 而 FactoryBean 是 IoC容器 中一种特殊的 bean,它能够实例化 bean对象,注意两者之间的区别 + bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); + } + // 如果应用程序要获取的 bean 还未创建 + else { + if (isPrototypeCurrentlyInCreation(beanName)) { + throw new BeanCurrentlyInCreationException(beanName); + } + + // 获取当前容器的父容器 + BeanFactory parentBeanFactory = getParentBeanFactory(); + // 如果当前容器中没有指定的 bean,且当前容器的父容器不为空 + // 则从父容器中去找,如果父容器也没有,则沿着当前容器的继承体系一直向上查找 + if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { + // 根据用户传入的 name(有可能是别名alias),获取唯一标识的 beanName + String nameToLookup = originalBeanName(name); + if (args != null) { + // 委派父级容器根据指定名称和显式的参数查找 + return (T) parentBeanFactory.getBean(nameToLookup, args); + } + else { + // 委派父容器根据指定名称和类型查找 + return parentBeanFactory.getBean(nameToLookup, requiredType); + } + } + + // 创建的 bean 是否需要进行类型验证,一般不需要 + if (!typeCheckOnly) { + // 向容器标记指定的 bean 已经被创建 + markBeanAsCreated(beanName); + } + + try { + // 根据 beanName 获取对应的 RootBeanDefinition + final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); + checkMergedBeanDefinition(mbd, beanName, args); + + // 获取当前 bean 所依赖bean 的 beanName,下面的 getBean(dependsOnBean) 方法会触发 + // getBean() 的递归调用,直到取到一个不依赖任何其它 bean 的 bean 为止。 + // 比如:beanA 依赖了 beanB,而 beanB 依赖了 beanC,那么在实例化 beanA 时会先实例化 + // beanC,然后实例化 beanB 并将 beanC 注入进去,最后实例化 beanA 时将 beanB 注入 + String[] dependsOn = mbd.getDependsOn(); + if (dependsOn != null) { + for (String dependsOnBean : dependsOn) { + // 递归调用 getBean() 方法,从末级节点依次实例化 依赖的bean + getBean(dependsOnBean); + // 把 当前bean 直接依赖的bean 进行注册 + //(也就是通过 setter 或构造方法将依赖的 bean 赋值给当前 bean 对应的属性) + registerDependentBean(dependsOnBean, beanName); + } + } + + // 如果当前 bean 是单例的 + if (mbd.isSingleton()) { + // 这里使用了一个匿名内部类,创建 bean实例对象 + sharedInstance = getSingleton(beanName, new ObjectFactory() { + public Object getObject() throws BeansException { + try { + // 根据给定的 beanName 及 RootBeanDefinition对象,创建 bean 实例对象 + return createBean(beanName, mbd, args); + } + catch (BeansException ex) { + destroySingleton(beanName); + throw ex; + } + } + }); + // 获取给定 bean 的实例对象 + bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); + } + + // 创建原型模式的 bean 实例对象 + else if (mbd.isPrototype()) { + // 原型模式 (Prototype) 每次都会创建一个新的对象 + Object prototypeInstance = null; + try { + // 回调 beforePrototypeCreation() 方法,默认的功能是注册当前创建的原型对象 + beforePrototypeCreation(beanName); + // 创建指定 bean 对象实例 + prototypeInstance = createBean(beanName, mbd, args); + } + finally { + // 回调 afterPrototypeCreation() 方法,默认的功能是告诉 IoC容器 + // 指定 bean 的原型对象不再创建了 + afterPrototypeCreation(beanName); + } + // 获取给定 bean 的实例对象 + bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); + } + + // 要创建的 bean 既不是单例模式,也不是原型模式,则根据该 bean元素 在配置文件中 + // 配置的生命周期范围,选择实例化 bean 的合适方法,这种在 Web 应用程序中 + // 比较常用,如:request、session、application 等的生命周期 + else { + // 获取此 bean 生命周期的范围 + String scopeName = mbd.getScope(); + final Scope scope = this.scopes.get(scopeName); + // bean 定义资源中没有配置生命周期范围,则该 bean 的配置不合法 + if (scope == null) { + throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'"); + } + try { + // 这里又使用了一个 ObjectFactory 的匿名内部类,获取一个指定生命周期范围的实例 + Object scopedInstance = scope.get(beanName, new ObjectFactory() { + public Object getObject() throws BeansException { + beforePrototypeCreation(beanName); + try { + return createBean(beanName, mbd, args); + } + finally { + afterPrototypeCreation(beanName); + } + } + }); + // 获取给定 bean 的实例对象 + bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); + } + catch (IllegalStateException ex) { + throw new BeanCreationException(beanName, + "Scope '" + scopeName + "' is not active for the current thread; " + + "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", + ex); + } + } + } + catch (BeansException ex) { + cleanupAfterBeanCreationFailure(beanName); + throw ex; + } + } + + // 对要返回的 bean实例对象 进行非空验证和类型检查,如果没问题就返回这个已经完成 依赖注入的bean + if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { + try { + return getTypeConverter().convertIfNecessary(bean, requiredType); + } + catch (TypeMismatchException ex) { + if (logger.isDebugEnabled()) { + logger.debug("Failed to convert bean '" + name + "' to required type [" + + ClassUtils.getQualifiedName(requiredType) + "]", ex); + } + throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); + } + } + return (T) bean; + } +} ``` -总的来说,getBean() 方法是依赖注入的起点,之后会调用 createBean(),根据 BeanDefinition 的定义生成 bean 对象,下面我们看看 AbstractBeanFactory 的子类 AbstractAutowireCapableBeanFactory 中对 createBean() 的具体实现。 - -## 2、AbstractAutowireCapableBeanFactory 中的 createBean() 和 doCreateBean() 具体实现 +总的来说,getBean() 方法是依赖注入的起点,之后会调用 createBean(),根据之前解析生成的 BeanDefinition对象 生成 bean 对象,下面我们看看 AbstractBeanFactory 的子类 AbstractAutowireCapableBeanFactory 中对 createBean() 的具体实现。 ```java - // 创建指定的 bean 实例对象 - @Override - protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) - throws BeanCreationException { - - if (logger.isDebugEnabled()) { - logger.debug("Creating instance of bean '" + beanName + "'"); - } - // 判断需要创建的 Bean 是否可以实例化,是否可以通过当前的类加载器加载 - resolveBeanClass(mbd, beanName); - - try { - // 校验和准备 Bean 中的方法覆盖 - mbd.prepareMethodOverrides(); - } - catch (BeanDefinitionValidationException ex) { - throw new BeanDefinitionStoreException(mbd.getResourceDescription(), - beanName, "Validation of method overrides failed", ex); - } - - try { - // 如果 Bean 配置了后置处理器 PostProcessor,则这里返回一个 proxy 代理对象 - Object bean = resolveBeforeInstantiation(beanName, mbd); - if (bean != null) { - return bean; - } - } - catch (Throwable ex) { - throw new BeanCreationException(mbd.getResourceDescription(), beanName, - "BeanPostProcessor before instantiation of bean failed", ex); - } - - // 创建 Bean 实例对象的具体实现 - Object beanInstance = doCreateBean(beanName, mbd, args); - if (logger.isDebugEnabled()) { - logger.debug("Finished creating instance of bean '" + beanName + "'"); - } - return beanInstance; - } - - // 创建 Bean 实例对象的具体实现,spring 中以 do 开头的都是方法的具体实现 - protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { - - // 封装被创建的 Bean 对象 - BeanWrapper instanceWrapper = null; - // 如果这个 bean 是单例的,则从缓存中获取这个 BeanWrapper 实例并清除 - if (mbd.isSingleton()) { - instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); - } - if (instanceWrapper == null) { - - /** - * !!!!!!!!!!!!! - * 创建实例对象 - * !!!!!!!!!!!!! - */ - instanceWrapper = createBeanInstance(beanName, mbd, args); - } - - // 获取实例化对象和其类型 - final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); - Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); - - // 调用 PostProcessor 后置处理器 - synchronized (mbd.postProcessingLock) { - if (!mbd.postProcessed) { - applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); - mbd.postProcessed = true; - } - } - - // 向容器中缓存单例模式的 Bean 对象,以防循环引用 - boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && - isSingletonCurrentlyInCreation(beanName)); - if (earlySingletonExposure) { - if (logger.isDebugEnabled()) { - logger.debug("Eagerly caching bean '" + beanName + - "' to allow for resolving potential circular references"); - } - // 这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用 - addSingletonFactory(beanName, new ObjectFactory() { - public Object getObject() throws BeansException { - return getEarlyBeanReference(beanName, mbd, bean); - } - }); - } - - // Bean 对象的初始化,依赖注入在此触发 - // 这个 exposedObject 在初始化完成之后,将返回作为依赖注入完成后的 Bean - Object exposedObject = bean; - try { - /** - * !!!!!!!!!!!!!!!!!!!!!!!!!!! - * 把生成的 bean 对象的依赖关系设置好,完成整个依赖注入过程 - * !!!!!!!!!!!!!!!!!!!!!!!!!!! - */ - populateBean(beanName, mbd, instanceWrapper); - if (exposedObject != null) { - // 初始化 Bean 对象 - // 在对 Bean 实例对象生成和依赖注入完成以后,开始对 Bean 实例对象 - // 进行初始化 ,为 Bean 实例对象应用 BeanPostProcessor 后置处理器 - exposedObject = initializeBean(beanName, exposedObject, mbd); - } - } - catch (Throwable ex) { - if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { - throw (BeanCreationException) ex; - } - else { - throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); - } - } - - if (earlySingletonExposure) { - // 获取指定名称的已注册的单例模式 Bean 对象 - Object earlySingletonReference = getSingleton(beanName, false); - if (earlySingletonReference != null) { - // 如果根据名称获取的已注册的 Bean 和正在实例化的 Bean 是同一个 - if (exposedObject == bean) { - // 当前实例化的 Bean 初始化完成 - exposedObject = earlySingletonReference; - } - // 如果当前 Bean 依赖其他 Bean,并且当发生循环引用时不允许新创建实例对象 - else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { - String[] dependentBeans = getDependentBeans(beanName); - Set actualDependentBeans = new LinkedHashSet(dependentBeans.length); - // 获取当前 Bean 所依赖的其他 Bean - for (String dependentBean : dependentBeans) { - // 对依赖 Bean 进行类型检查 - if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { - actualDependentBeans.add(dependentBean); - } - } - if (!actualDependentBeans.isEmpty()) { - throw new BeanCurrentlyInCreationException(beanName, - "Bean with name '" + beanName + "' has been injected into other beans [" + - StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + - "] in its raw version as part of a circular reference, but has eventually been " + - "wrapped. This means that said other beans do not use the final version of the " + - "bean. This is often the result of over-eager type matching - consider using " + - "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); - } - } - } - } - - try { - // 注册完成依赖注入的 Bean - registerDisposableBeanIfNecessary(beanName, bean, mbd); - } - catch (BeanDefinitionValidationException ex) { - throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); - } - - // 为应用返回所需要的实例对象 - return exposedObject; - } - +public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory + implements AutowireCapableBeanFactory { + + /** + * 创建指定的 bean 实例对象 + */ + @Override + protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) + throws BeanCreationException { + + if (logger.isDebugEnabled()) { + logger.debug("Creating instance of bean '" + beanName + "'"); + } + // 判断需要创建的 bean 是否可实例化,是否可以通过当前的类加载器加载 + resolveBeanClass(mbd, beanName); + + try { + // 校验和准备 bean 中的方法覆盖 + mbd.prepareMethodOverrides(); + } + catch (BeanDefinitionValidationException ex) { + throw new BeanDefinitionStoreException(mbd.getResourceDescription(), + beanName, "Validation of method overrides failed", ex); + } + + try { + // 如果 bean 配置了后置处理器 PostProcessor,则这里返回一个 proxy 代理对象 + Object bean = resolveBeforeInstantiation(beanName, mbd); + if (bean != null) { + return bean; + } + } + catch (Throwable ex) { + throw new BeanCreationException(mbd.getResourceDescription(), beanName, + "BeanPostProcessor before instantiation of bean failed", ex); + } + + // 创建 bean 实例对象的具体实现 + Object beanInstance = doCreateBean(beanName, mbd, args); + if (logger.isDebugEnabled()) { + logger.debug("Finished creating instance of bean '" + beanName + "'"); + } + return beanInstance; + } + + /** + * 创建 bean 实例对象的具体实现,Spring 中以 do 开头的都是方法的具体实现 + */ + protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { + + BeanWrapper instanceWrapper = null; + // 如果这个 bean 是单例的,则从缓存中获取这个 beanName 对应的 BeanWrapper实例,并清除 + if (mbd.isSingleton()) { + instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); + } + if (instanceWrapper == null) { + /** + * !!!!!!!!!!!!! + * 创建实例对象 + * !!!!!!!!!!!!! + */ + instanceWrapper = createBeanInstance(beanName, mbd, args); + } + + // 获取实例化对象和其类型 + final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); + Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); + + // 调用 PostProcessor 后置处理器 + synchronized (mbd.postProcessingLock) { + if (!mbd.postProcessed) { + applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); + mbd.postProcessed = true; + } + } + + // 向容器中缓存单例模式的 bean 对象,以防循环引用 + boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && + isSingletonCurrentlyInCreation(beanName)); + if (earlySingletonExposure) { + if (logger.isDebugEnabled()) { + logger.debug("Eagerly caching bean '" + beanName + + "' to allow for resolving potential circular references"); + } + // 这里是一个 ObjectFactory 的匿名内部类,为了防止循环引用,尽早持有对象的引用 + addSingletonFactory(beanName, new ObjectFactory() { + public Object getObject() throws BeansException { + return getEarlyBeanReference(beanName, mbd, bean); + } + }); + } + + // bean 对象的初始化,依赖注入在此触发 + // 这个 exposedObject 在初始化完成之后,将返回作为依赖注入完成后的 bean + Object exposedObject = bean; + try { + /** + * !!!!!!!!!!!!!!!!!!!!!!!!!!! + * 把生成的 bean对象 的依赖关系设置好,完成整个依赖注入过程 + * !!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + populateBean(beanName, mbd, instanceWrapper); + if (exposedObject != null) { + // 初始化 bean对象 + exposedObject = initializeBean(beanName, exposedObject, mbd); + } + } + catch (Throwable ex) { + if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { + throw (BeanCreationException) ex; + } + else { + throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); + } + } + + if (earlySingletonExposure) { + // 获取指定名称的已注册的 单例bean对象 + Object earlySingletonReference = getSingleton(beanName, false); + if (earlySingletonReference != null) { + // 如果根据名称获取的已注册的 bean 和正在实例化的 bean 是同一个 + if (exposedObject == bean) { + // 当前实例化的 bean 初始化完成 + exposedObject = earlySingletonReference; + } + // 如果当前 bean 依赖其他 bean,并且当发生循环引用时不允许新创建实例对象 + else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { + String[] dependentBeans = getDependentBeans(beanName); + Set actualDependentBeans = new LinkedHashSet(dependentBeans.length); + // 获取当前 bean 所依赖的其他 bean + for (String dependentBean : dependentBeans) { + // 对 依赖bean 进行类型检查 + if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { + actualDependentBeans.add(dependentBean); + } + } + if (!actualDependentBeans.isEmpty()) { + throw new BeanCurrentlyInCreationException(beanName, + "Bean with name '" + beanName + "' has been injected into other beans [" + + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + + "] in its raw version as part of a circular reference, but has eventually been " + + "wrapped. This means that said other beans do not use the final version of the " + + "bean. This is often the result of over-eager type matching - consider using " + + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); + } + } + } + } + + try { + // 注册 成完依赖注入的bean + registerDisposableBeanIfNecessary(beanName, bean, mbd); + } + catch (BeanDefinitionValidationException ex) { + throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); + } + + // 为应用返回所需要的实例对象 + return exposedObject; + } +} ``` -从源码中可以看到 createBeanInstance() 和 populateBean() 这两个方法与依赖注入的实现非常密切,createBeanInstance() 方法中生成了 Bean 所包含的 Java 对象,populateBean() 方法对这些生成的 bean 对象之间的依赖关系进行了处理。下面我们先看一下 createBeanInstance() 方法的实现。 - -## 3、createBeanInstance() 方法的具体实现 +从源码中可以看到 createBeanInstance() 和 populateBean() 这两个方法与依赖注入的实现非常密切,createBeanInstance() 方法中生成了 bean 所包含的 Java 对象,populateBean() 方法对这些生成的 bean 对象之间的依赖关系进行了处理。下面我们先看一下 createBeanInstance() 方法的实现。 ```java - // 创建 Bean 的实例对象 - protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { - - // 检查确认 Bean 是可实例化的 - Class beanClass = resolveBeanClass(mbd, beanName); - if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { - throw new BeanCreationException(mbd.getResourceDescription(), beanName, - "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); - } - - // 使用工厂方法对 Bean 进行实例化 - if (mbd.getFactoryMethodName() != null) { - return instantiateUsingFactoryMethod(beanName, mbd, args); - } - - // 使用容器的自动装配方法进行实例化 - boolean resolved = false; - boolean autowireNecessary = false; - if (args == null) { - synchronized (mbd.constructorArgumentLock) { - if (mbd.resolvedConstructorOrFactoryMethod != null) { - resolved = true; - autowireNecessary = mbd.constructorArgumentsResolved; - } - } - } - if (resolved) { - if (autowireNecessary) { - // 配置了自动装配属性,使用容器的自动装配实例化, - // 即,根据参数类型匹配 Bean 的构造方法 - return autowireConstructor(beanName, mbd, null, null); - } - else { - // 使用默认的无参构造方法进行实例化 - return instantiateBean(beanName, mbd); - } - } - - // 使用 Bean 的构造方法进行实例化 - Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); - if (ctors != null || - mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || - mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { - // 使用容器的自动装配特性,调用匹配的构造方法实例化 - return autowireConstructor(beanName, mbd, ctors, args); - } - - return instantiateBean(beanName, mbd); - } - - // 使用默认的无参构造方法实例化 Bean 对象 - protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { - try { - Object beanInstance; - final BeanFactory parent = this; - // 获取系统的安全管理接口,JDK 标准的安全管理 API - if (System.getSecurityManager() != null) { - // 这里是一个匿名内置类,根据实例化策略创建实例对象 - beanInstance = AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - return getInstantiationStrategy().instantiate(mbd, beanName, parent); - } - }, getAccessControlContext()); - } - else { - - /** - * !!!!!!!!!!!!!! - * 使用初始化策略实例化 Bean 对象 - * !!!!!!!!!!!!!! - */ - beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); - } - BeanWrapper bw = new BeanWrapperImpl(beanInstance); - initBeanWrapper(bw); - return bw; - } - catch (Throwable ex) { - throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); - } - } +/** + * 创建 bean 的实例对象 + */ +protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { + + // 检查确认 bean 是可实例化的 + Class beanClass = resolveBeanClass(mbd, beanName); + if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { + throw new BeanCreationException(mbd.getResourceDescription(), beanName, + "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); + } + + // 使用 RootBeanDefinition对象 中的 factoryMethodName 对 bean 进行实例化 + if (mbd.getFactoryMethodName() != null) { + return instantiateUsingFactoryMethod(beanName, mbd, args); + } + + // 使用容器的自动装配方法进行实例化 + boolean resolved = false; + boolean autowireNecessary = false; + if (args == null) { + synchronized (mbd.constructorArgumentLock) { + if (mbd.resolvedConstructorOrFactoryMethod != null) { + resolved = true; + autowireNecessary = mbd.constructorArgumentsResolved; + } + } + } + if (resolved) { + if (autowireNecessary) { + // 配置了自动装配属性,使用容器的自动装配实例化,即,根据参数类型匹配 bean 的构造方法 + return autowireConstructor(beanName, mbd, null, null); + } + else { + // 使用默认的无参构造方法进行实例化 + return instantiateBean(beanName, mbd); + } + } + + // 使用 bean 的构造方法进行实例化 + Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); + if (ctors != null || + mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || + mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { + // 使用容器的自动装配特性,调用匹配的构造方法实例化 + return autowireConstructor(beanName, mbd, ctors, args); + } + + return instantiateBean(beanName, mbd); +} +// 使用默认的无参构造方法实例化 bean对象 +protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { + try { + Object beanInstance; + final BeanFactory parent = this; + // 获取系统的安全管理接口,JDK 标准的安全管理 API + if (System.getSecurityManager() != null) { + // 这里使用了一个 PrivilegedAction 的匿名内部类,根据实例化策略创建实例对象 + beanInstance = AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return getInstantiationStrategy().instantiate(mbd, beanName, parent); + } + }, getAccessControlContext()); + } + else { + /** + * !!!!!!!!!!!!!! + * 使用初始化策略实例化 bean 对象 + * !!!!!!!!!!!!!! + */ + beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); + } + BeanWrapper bw = new BeanWrapperImpl(beanInstance); + initBeanWrapper(bw); + return bw; + } + catch (Throwable ex) { + throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); + } +} ``` -从源码中我们可以看到其调用了 SimpleInstantiationStrategy 实现类来生成 bean 对象,这个类是 spring 用来生成 bean 对象的默认类,它提供了两种策略来实例化 bean 对象,一种是利用 Java 的反射机制,另一种是直接使用 CGLIB。 -## 4、SimpleInstantiationStrategy 中的 instantiate() 方法实现 +从源码中我们可以看到其调用了 SimpleInstantiationStrategy 实现类来生成 bean 对象,这个类是 Spring 用来生成 bean对象 的默认类,它提供了两种策略来实例化 bean对象,一种是利用 Java 的反射机制,另一种是直接使用 CGLIB。 ```java - // 使用初始化策略实例化 Bean 对象 - public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) { - // 如果 Bean 定义中没有方法覆盖,则使用 Java 的反射机制实例化对象,否则使用 CGLIB - if (beanDefinition.getMethodOverrides().isEmpty()) { - Constructor constructorToUse; - synchronized (beanDefinition.constructorArgumentLock) { - // 获取对象的构造方法或生成对象的工厂方法对 bean 进行实例化 - constructorToUse = (Constructor) beanDefinition.resolvedConstructorOrFactoryMethod; - - // 如果前面没有获取到构造方法,则通过反射获取 - if (constructorToUse == null) { - // 使用 JDK 的反射机制,判断要实例化的 Bean 是否是接口 - final Class clazz = beanDefinition.getBeanClass(); - // 如果 clazz 是一个接口,直接抛出异常 - if (clazz.isInterface()) { - throw new BeanInstantiationException(clazz, "Specified class is an interface"); - } - try { - if (System.getSecurityManager() != null) { - // 这里是一个匿名内置类,使用反射机制获取 Bean 的构造方法 - constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Constructor run() throws Exception { - return clazz.getDeclaredConstructor((Class[]) null); - } - }); - } - else { - constructorToUse = clazz.getDeclaredConstructor((Class[]) null); - } - beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse; - } - catch (Exception ex) { - throw new BeanInstantiationException(clazz, "No default constructor found", ex); - } - } - } - // 使用 BeanUtils 实例化,通过反射机制调用”构造方法.newInstance(arg)”来进行实例化 - return BeanUtils.instantiateClass(constructorToUse); - } - else { - /** - * !!!!!!!!!!!!!! - * 使用 CGLIB 来实例化对象 - * 调用了 CglibSubclassingInstantiationStrategy 中的实现 - * !!!!!!!!!!!!!! - */ - return instantiateWithMethodInjection(beanDefinition, beanName, owner); - } - } - +public class SimpleInstantiationStrategy implements InstantiationStrategy { + + // 使用初始化策略实例化 bean对象 + public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) { + // 如果 配置的bean 中没有方法覆盖,则使用 Java 的反射机制实例化对象,否则使用 CGLIB + if (beanDefinition.getMethodOverrides().isEmpty()) { + Constructor constructorToUse; + synchronized (beanDefinition.constructorArgumentLock) { + // 获取对象的构造方法对 bean 进行实例化 + constructorToUse = (Constructor) beanDefinition.resolvedConstructorOrFactoryMethod; + // 如果前面没有获取到构造方法,则通过反射获取 + if (constructorToUse == null) { + // 使用 JDK 的反射机制,判断要实例化的 bean 是否是接口 + final Class clazz = beanDefinition.getBeanClass(); + // 如果 clazz 是一个接口,直接抛出异常 + if (clazz.isInterface()) { + throw new BeanInstantiationException(clazz, "Specified class is an interface"); + } + try { + if (System.getSecurityManager() != null) { + // 这里使用了一个 PrivilegedExceptionAction 的匿名内部类,使用反射机制获取 bean 的构造方法 + constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Constructor run() throws Exception { + return clazz.getDeclaredConstructor((Class[]) null); + } + }); + } + else { + constructorToUse = clazz.getDeclaredConstructor((Class[]) null); + } + beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse; + } + catch (Exception ex) { + throw new BeanInstantiationException(clazz, "No default constructor found", ex); + } + } + } + // 根据传入的 Constructor,在 BeanUtils 中调用该 Constructor 的 + // newInstance(Object...) 方法,实例化指定对象 + return BeanUtils.instantiateClass(constructorToUse); + } + else { + /** + * !!!!!!!!!!!!!! + * 使用 CGLIB 来实例化对象 + * 调用了 CglibSubclassingInstantiationStrategy 中的实现 + * !!!!!!!!!!!!!! + */ + return instantiateWithMethodInjection(beanDefinition, beanName, owner); + } + } +} ``` 在 SimpleInstantiationStrategy 的子类 CglibSubclassingInstantiationStrategy 中可以看到使用 CGLIB 进行实例化的源码实现。 -## 5、CglibSubclassingInstantiationStrategy 中使用 CGLIB 进行实例化的源码实现 ```java - // 下面两个方法都通过实例化自己的私有静态内部类 CglibSubclassCreator, - // 然后调用该内部类对象的实例化方法 instantiate() 完成实例化 - protected Object instantiateWithMethodInjection( - RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) { - - // 必须生成 cglib 子类 - return new CglibSubclassCreator(beanDefinition, owner).instantiate(null, null); - } - - @Override - protected Object instantiateWithMethodInjection( - RootBeanDefinition beanDefinition, String beanName, BeanFactory owner, - Constructor ctor, Object[] args) { - - return new CglibSubclassCreator(beanDefinition, owner).instantiate(ctor, args); - } - - /** - * 为避免 3.2 之前的 Spring 版本中的外部 cglib 依赖而创建的内部类。 - */ - private static class CglibSubclassCreator { - - private static final Log logger = LogFactory.getLog(CglibSubclassCreator.class); - - private final RootBeanDefinition beanDefinition; - - private final BeanFactory owner; - - public CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) { - this.beanDefinition = beanDefinition; - this.owner = owner; - } - - // 使用 CGLIB 进行 Bean 对象实例化 - public Object instantiate(Constructor ctor, Object[] args) { - // 实例化 Enhancer 对象,并为 Enhancer 对象设置父类,生成 Java 对象的参数,比如:基类、回调方法等 - Enhancer enhancer = new Enhancer(); - // 将 Bean 本身作为其父类 - enhancer.setSuperclass(this.beanDefinition.getBeanClass()); - enhancer.setCallbackFilter(new CallbackFilterImpl()); - enhancer.setCallbacks(new Callback[] { - NoOp.INSTANCE, - new LookupOverrideMethodInterceptor(), - new ReplaceOverrideMethodInterceptor() - }); - - // 使用 CGLIB 的 create 方法生成实例对象 - return (ctor == null) ? enhancer.create() : enhancer.create(ctor.getParameterTypes(), args); - } +public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy { + + /** + * 下面两个方法都通过实例化自己的私有静态内部类 CglibSubclassCreator, + * 然后调用该内部类对象的实例化方法 instantiate() 完成实例化 + */ + protected Object instantiateWithMethodInjection( + RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) { + + return new CglibSubclassCreator(beanDefinition, owner).instantiate(null, null); + } + + @Override + protected Object instantiateWithMethodInjection( + RootBeanDefinition beanDefinition, String beanName, BeanFactory owner, + Constructor ctor, Object[] args) { + + return new CglibSubclassCreator(beanDefinition, owner).instantiate(ctor, args); + } + + /** + * 为避免 3.2 之前的 Spring 版本中的外部 cglib 依赖而创建的内部类。 + */ + private static class CglibSubclassCreator { + + private static final Log logger = LogFactory.getLog(CglibSubclassCreator.class); + + private final RootBeanDefinition beanDefinition; + + private final BeanFactory owner; + + public CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) { + this.beanDefinition = beanDefinition; + this.owner = owner; + } + + // 使用 CGLIB 进行 bean对象 实例化 + public Object instantiate(Constructor ctor, Object[] args) { + // 实例化 Enhancer对象,并为 Enhancer对象 设置父类,生成 Java 对象的参数,比如:基类、回调方法等 + Enhancer enhancer = new Enhancer(); + // 将 bean 本身作为其父类 + enhancer.setSuperclass(this.beanDefinition.getBeanClass()); + enhancer.setCallbackFilter(new CallbackFilterImpl()); + enhancer.setCallbacks(new Callback[] { + NoOp.INSTANCE, + new LookupOverrideMethodInterceptor(), + new ReplaceOverrideMethodInterceptor() + }); + + // 使用 CGLIB 的 create() 方法生成实例对象 + return (ctor == null) ? enhancer.create() : enhancer.create(ctor.getParameterTypes(), args); + } + } } - ``` -至此,完成了 bean 对象的实例化,然后就可以根据解析得到的 BeanDefinition 完成对各个属性的赋值处理,也就是依赖注入。这个实现方法就是前面 AbstractAutowireCapableBeanFactory 类中的 populateBean() 方法。 -## 6、AbstractAutowireCapableBeanFactory 中的 populateBean(),完成依赖注入 +至此,完成了 bean对象 的实例化,然后就可以根据解析得到的 BeanDefinition对象 完成对各个属性的赋值处理,也就是依赖注入。这个实现方法就是前面 AbstractAutowireCapableBeanFactory 类中的 populateBean() 方法。 ```java - // 为属性赋值,完成依赖注入 - protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { - // 获取 BeanDefinition 中设置的 property,这些 property 来自对 BeanDefinition 的解析 - PropertyValues pvs = mbd.getPropertyValues(); - - // 如果实例对象为 null,而要注入的属性值不为空,则抛出下述异常 - if (bw == null) { - if (!pvs.isEmpty()) { - throw new BeanCreationException( - mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); - } - else { - // 实例对象为 null,属性值也为空,不需要设置属性值,直接返回 - return; - } - } - - // 在设置属性之前调用 Bean 的 PostProcessor 后置处理器 - boolean continueWithPropertyPopulation = true; - - if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { - for (BeanPostProcessor bp : getBeanPostProcessors()) { - if (bp instanceof InstantiationAwareBeanPostProcessor) { - InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; - if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { - continueWithPropertyPopulation = false; - break; - } - } - } - } - - if (!continueWithPropertyPopulation) { - return; - } - - // 依赖注入开始,首先处理 autowire 自动装配的注入 - if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || - mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { - MutablePropertyValues newPvs = new MutablePropertyValues(pvs); - - // 对 autowire 自动装配的处理,根据 Bean 名称自动装配注入 - if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { - autowireByName(beanName, mbd, bw, newPvs); - } - - // 根据 Bean 类型自动装配注入 - if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { - autowireByType(beanName, mbd, bw, newPvs); - } - - pvs = newPvs; - } - - // 检查容器是否持有用于处理单例模式 Bean 关闭时的后置处理器 - boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); - // Bean 实例对象没有依赖,即没有继承基类 - boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); - - if (hasInstAwareBpps || needsDepCheck) { - // 从实例对象中提取属性描述符 - PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); - if (hasInstAwareBpps) { - for (BeanPostProcessor bp : getBeanPostProcessors()) { - if (bp instanceof InstantiationAwareBeanPostProcessor) { - InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; - // 使用 BeanPostProcessor 处理器处理属性值 - pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); - if (pvs == null) { - return; - } - } - } - } - if (needsDepCheck) { - // 为要设置的属性进行依赖检查 - checkDependencies(beanName, mbd, filteredPds, pvs); - } - } - /** - * !!!!!!!!!!! - * 对属性进行依赖注入 - * !!!!!!!!!!! - */ - applyPropertyValues(beanName, mbd, bw, pvs); - } +public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory + implements AutowireCapableBeanFactory { - // 解析并注入依赖属性的过程 - protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { - if (pvs == null || pvs.isEmpty()) { - return; - } - - // 封装属性值 - MutablePropertyValues mpvs = null; - List original; - - if (System.getSecurityManager()!= null) { - if (bw instanceof BeanWrapperImpl) { - // 设置安全上下文,JDK 安全机制 - ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); - } - } - - if (pvs instanceof MutablePropertyValues) { - mpvs = (MutablePropertyValues) pvs; - // 如果属性值已经转换 - if (mpvs.isConverted()) { - try { - // 为实例化对象设置属性值 - bw.setPropertyValues(mpvs); - return; - } - catch (BeansException ex) { - throw new BeanCreationException( - mbd.getResourceDescription(), beanName, "Error setting property values", ex); - } - } - // 获取属性值对象的原始类型值 - original = mpvs.getPropertyValueList(); - } - else { - original = Arrays.asList(pvs.getPropertyValues()); - } - - // 获取用户自定义的类型转换 - TypeConverter converter = getCustomTypeConverter(); - if (converter == null) { - converter = bw; - } - // 创建一个 BeanDefinition 属性值解析器,将 Bean 定义中的属性值解析为 Bean 实例对象的实际值 - BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter); - - // 为属性的解析值创建一个副本,最后将属性值注入到实例对象中 - List deepCopy = new ArrayList(original.size()); - boolean resolveNecessary = false; - for (PropertyValue pv : original) { - // 如果属性值已经转换,直接添加到 deepCopy 列表中 - if (pv.isConverted()) { - deepCopy.add(pv); - } - // 如果属性值需要转换 - else { - String propertyName = pv.getName(); - // 原始的属性值,即转换之前的属性值 - Object originalValue = pv.getValue(); - /** - * !!!!!!!!!!!!!!!!!!! - * 解析属性值,对注入类型进行转换 - * !!!!!!!!!!!!!!!!!!! - */ - Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); - // 转换之后的属性值 - Object convertedValue = resolvedValue; - // 属性值是否可以转换 - boolean convertible = bw.isWritableProperty(propertyName) && - !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); - if (convertible) { - // 使用用户自定义的类型转换器转换属性值 - convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter); - } - // 存储转换后的属性值,避免每次属性注入时的转换工作 - if (resolvedValue == originalValue) { - if (convertible) { - // 设置属性转换之后的值 - pv.setConvertedValue(convertedValue); - } - deepCopy.add(pv); - } - // 如果:属性是可转换的,且属性原始值是字符串类型,且属性的原始类型值不是 - // 动态生成的字符串,且属性的原始值不是集合或者数组类型 - else if (convertible && originalValue instanceof TypedStringValue && - !((TypedStringValue) originalValue).isDynamic() && - !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) { - pv.setConvertedValue(convertedValue); - deepCopy.add(pv); - } - else { - resolveNecessary = true; - // 重新封装属性的值 - deepCopy.add(new PropertyValue(pv, convertedValue)); - } - } - } - if (mpvs != null && !resolveNecessary) { - // 标记属性值已经转换过 - mpvs.setConverted(); - } - - // 进行属性依赖注入 - try { - /** - * !!!!!!!!!!!!!!!!!!!!! - * 完成 bean 的属性值注入的入口 - * 走 AbstractPropertyAccessor 中的实现方法 - * !!!!!!!!!!!!!!!!!!!!! - */ - bw.setPropertyValues(new MutablePropertyValues(deepCopy)); - } - catch (BeansException ex) { - throw new BeanCreationException( - mbd.getResourceDescription(), beanName, "Error setting property values", ex); - } - } - + /** + * 为属性赋值,完成依赖注入 + */ + protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { + // 获取 RootBeanDefinition 中设置的 属性值PropertyValues,这些属性值来自对 + // .xml 文件中 bean元素 的解析 + PropertyValues pvs = mbd.getPropertyValues(); + + // 如果 BeanWrapper对象 为 null,而要注入的属性值不为空,则抛出下述异常 + if (bw == null) { + if (!pvs.isEmpty()) { + throw new BeanCreationException( + mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); + } + else { + // BeanWrapper对象 为 null,属性值也为空,不需要设置属性值,直接返回 + return; + } + } + + // 在设置属性之前调用 bean 的 PostProcessor 后置处理器 + boolean continueWithPropertyPopulation = true; + + if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { + for (BeanPostProcessor bp : getBeanPostProcessors()) { + if (bp instanceof InstantiationAwareBeanPostProcessor) { + InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; + if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { + continueWithPropertyPopulation = false; + break; + } + } + } + } + + if (!continueWithPropertyPopulation) { + return; + } + + // 依赖注入开始,首先处理 autowire 自动装配的注入 + if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || + mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { + MutablePropertyValues newPvs = new MutablePropertyValues(pvs); + + // 对 autowire 自动装配的处理,根据 bean 名称自动装配注入 + if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { + autowireByName(beanName, mbd, bw, newPvs); + } + + // 根据 bean 类型自动装配注入 + if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { + autowireByType(beanName, mbd, bw, newPvs); + } + + pvs = newPvs; + } + + // 检查容器是否持有用于处理单例模式 bean 关闭时的后置处理器 + boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); + // bean实例对象 没有依赖,即没有继承基类 + boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); + + if (hasInstAwareBpps || needsDepCheck) { + // 从实例对象中提取属性描述符 + PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); + if (hasInstAwareBpps) { + for (BeanPostProcessor bp : getBeanPostProcessors()) { + if (bp instanceof InstantiationAwareBeanPostProcessor) { + InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; + // 使用 BeanPostProcessor 处理器处理属性值 + pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); + if (pvs == null) { + return; + } + } + } + } + if (needsDepCheck) { + // 为要设置的属性进行依赖检查 + checkDependencies(beanName, mbd, filteredPds, pvs); + } + } + /** + * !!!!!!!!!!! + * 对属性进行依赖注入 + * !!!!!!!!!!! + */ + applyPropertyValues(beanName, mbd, bw, pvs); + } + + /** + * 解析并注入依赖属性的过程 + */ + protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { + if (pvs == null || pvs.isEmpty()) { + return; + } + + // 封装属性值 + MutablePropertyValues mpvs = null; + List original; + + if (System.getSecurityManager()!= null) { + if (bw instanceof BeanWrapperImpl) { + // 设置安全上下文,JDK 安全机制 + ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); + } + } + + if (pvs instanceof MutablePropertyValues) { + mpvs = (MutablePropertyValues) pvs; + // 如果属性值已经转换 + if (mpvs.isConverted()) { + try { + // 为实例化对象设置属性值 + bw.setPropertyValues(mpvs); + return; + } + catch (BeansException ex) { + throw new BeanCreationException( + mbd.getResourceDescription(), beanName, "Error setting property values", ex); + } + } + // 获取属性值对象的原始类型值 + original = mpvs.getPropertyValueList(); + } + else { + original = Arrays.asList(pvs.getPropertyValues()); + } + + // 获取用户自定义的类型转换 + TypeConverter converter = getCustomTypeConverter(); + if (converter == null) { + converter = bw; + } + // 创建一个 BeanDefinition 属性值解析器,将 BeanDefinition 中的属性值解析为 bean 实例对象的实际值 + BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter); + + // 为属性的解析值创建一个副本,最后将属性值注入到实例对象中 + List deepCopy = new ArrayList(original.size()); + boolean resolveNecessary = false; + for (PropertyValue pv : original) { + // 如果属性值已经转换,直接添加到 deepCopy 列表中 + if (pv.isConverted()) { + deepCopy.add(pv); + } + // 如果属性值需要转换 + else { + String propertyName = pv.getName(); + // 原始的属性值,即转换之前的属性值 + Object originalValue = pv.getValue(); + /** + * !!!!!!!!!!!!!!!!!!! + * 解析属性值,对注入类型进行转换 + * !!!!!!!!!!!!!!!!!!! + */ + Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); + // 转换之后的属性值 + Object convertedValue = resolvedValue; + // 属性值是否可以转换 + boolean convertible = bw.isWritableProperty(propertyName) && + !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); + if (convertible) { + // 使用用户自定义的类型转换器转换属性值 + convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter); + } + // 存储转换后的属性值,避免每次属性注入时的转换工作 + if (resolvedValue == originalValue) { + if (convertible) { + // 设置属性转换之后的值 + pv.setConvertedValue(convertedValue); + } + deepCopy.add(pv); + } + // 如果:属性是可转换的,且属性原始值是字符串类型,且属性的原始类型值不是 + // 动态生成的字符串,且属性的原始值不是集合或者数组类型 + else if (convertible && originalValue instanceof TypedStringValue && + !((TypedStringValue) originalValue).isDynamic() && + !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) { + pv.setConvertedValue(convertedValue); + deepCopy.add(pv); + } + else { + resolveNecessary = true; + // 重新封装属性的值 + deepCopy.add(new PropertyValue(pv, convertedValue)); + } + } + } + if (mpvs != null && !resolveNecessary) { + // 标记属性值已经转换过 + mpvs.setConverted(); + } + + // 进行属性依赖注入 + try { + /** + * !!!!!!!!!!!!!!!!!!!!! + * 完成 bean 的属性值注入的入口 + * 走 AbstractPropertyAccessor 中的实现方法 + * !!!!!!!!!!!!!!!!!!!!! + */ + bw.setPropertyValues(new MutablePropertyValues(deepCopy)); + } + catch (BeansException ex) { + throw new BeanCreationException( + mbd.getResourceDescription(), beanName, "Error setting property values", ex); + } + } +} ``` - -## 7、BeanDefinitionValueResolver 中解析属性值,对注入类型进行转换的具体实现 +BeanDefinitionValueResolver 中解析属性值,对注入类型进行转换的具体实现。 ```java - // 解析属性值,对注入类型进行转换 - public Object resolveValueIfNecessary(Object argName, Object value) { - // 对引用类型的属性进行解析,RuntimeBeanReference 是在对 - // BeanDefinition 进行解析时生成的数据对象 - if (value instanceof RuntimeBeanReference) { - RuntimeBeanReference ref = (RuntimeBeanReference) value; - /** - * !!!!!!!!!!!!!!!! - * 解析引用类型的属性值 - * !!!!!!!!!!!!!!!! - */ - return resolveReference(argName, ref); - } - - // 对属性值是引用容器中另一个 Bean 名称的解析 - else if (value instanceof RuntimeBeanNameReference) { - String refName = ((RuntimeBeanNameReference) value).getBeanName(); - refName = String.valueOf(evaluate(refName)); - if (!this.beanFactory.containsBean(refName)) { - throw new BeanDefinitionStoreException( - "Invalid bean name '" + refName + "' in bean reference for " + argName); - } - return refName; - } - // 对 BeanDefinitionHolder 类型属性的解析,主要是 Bean 中的内部类 - else if (value instanceof BeanDefinitionHolder) { - BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value; - return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition()); - } - else if (value instanceof BeanDefinition) { - BeanDefinition bd = (BeanDefinition) value; - return resolveInnerBean(argName, "(inner bean)", bd); - } - // 对集合数组类型的属性解析 - else if (value instanceof ManagedArray) { - ManagedArray array = (ManagedArray) value; - // 获取数组的类型 - Class elementType = array.resolvedElementType; - if (elementType == null) { - // 获取数组元素的类型 - String elementTypeName = array.getElementTypeName(); - if (StringUtils.hasText(elementTypeName)) { - try { - // 使用反射机制创建指定类型的对象 - elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader()); - array.resolvedElementType = elementType; - } - catch (Throwable ex) { - throw new BeanCreationException( - this.beanDefinition.getResourceDescription(), this.beanName, - "Error resolving array type for " + argName, ex); - } - } - // 没有获取到数组的类型,也没有获取到数组元素的类型 - // 则直接设置数组的类型为 Object - else { - elementType = Object.class; - } - } - // 创建指定类型的数组 - return resolveManagedArray(argName, (List) value, elementType); - } - // 解析 list 类型的属性值 - else if (value instanceof ManagedList) { - // May need to resolve contained runtime references. - return resolveManagedList(argName, (List) value); - } - // 解析 set 类型的属性值 - else if (value instanceof ManagedSet) { - // May need to resolve contained runtime references. - return resolveManagedSet(argName, (Set) value); - } - // 解析 map 类型的属性值 - else if (value instanceof ManagedMap) { - // May need to resolve contained runtime references. - return resolveManagedMap(argName, (Map) value); - } - // 解析 Properties 类型的属性值,Properties 其实就是 key 和 value 均为字符串的 map - else if (value instanceof ManagedProperties) { - Properties original = (Properties) value; - // 创建一个拷贝,用于作为解析后的返回值 - Properties copy = new Properties(); - for (Map.Entry propEntry : original.entrySet()) { - Object propKey = propEntry.getKey(); - Object propValue = propEntry.getValue(); - if (propKey instanceof TypedStringValue) { - propKey = evaluate((TypedStringValue) propKey); - } - if (propValue instanceof TypedStringValue) { - propValue = evaluate((TypedStringValue) propValue); - } - copy.put(propKey, propValue); - } - return copy; - } - // 解析字符串类型的属性值 - else if (value instanceof TypedStringValue) { - TypedStringValue typedStringValue = (TypedStringValue) value; - Object valueObject = evaluate(typedStringValue); - try { - // 获取属性的目标类型 - Class resolvedTargetType = resolveTargetType(typedStringValue); - if (resolvedTargetType != null) { - // 对目标类型的属性进行解析,递归调用 - return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType); - } - // 没有获取到属性的目标对象,则按 Object 类型返回 - else { - return valueObject; - } - } - catch (Throwable ex) { - throw new BeanCreationException( - this.beanDefinition.getResourceDescription(), this.beanName, - "Error converting typed String value for " + argName, ex); - } - } - else { - return evaluate(value); - } - } - - // 解析引用类型的属性值 - private Object resolveReference(Object argName, RuntimeBeanReference ref) { - try { - // 获取引用的 BeanName - String refName = ref.getBeanName(); - refName = String.valueOf(evaluate(refName)); - // 如果引用的对象在父容器中,则从父容器中获取指定的引用对象 - if (ref.isToParent()) { - if (this.beanFactory.getParentBeanFactory() == null) { - throw new BeanCreationException( - this.beanDefinition.getResourceDescription(), this.beanName, - "Can't resolve reference to bean '" + refName + - "' in parent factory: no parent factory available"); - } - return this.beanFactory.getParentBeanFactory().getBean(refName); - } - // 从当前的容器中获取指定的引用 Bean 对象,如果指定的 Bean 没有被实例化 - // 则会递归触发引用 Bean 的初始化和依赖注入 - else { - Object bean = this.beanFactory.getBean(refName); - // 为 refName 对应的 BeanDefinition 注入依赖的 Bean - this.beanFactory.registerDependentBean(refName, this.beanName); - return bean; - } - } - catch (BeansException ex) { - throw new BeanCreationException( - this.beanDefinition.getResourceDescription(), this.beanName, - "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex); - } - } - - // 解析 array 类型的属性 - private Object resolveManagedArray(Object argName, List ml, Class elementType) { - // 创建一个指定类型的数组,用于存放和返回解析后的数组 - Object resolved = Array.newInstance(elementType, ml.size()); - for (int i = 0; i < ml.size(); i++) { - // 递归解析 array 的每一个元素,并将解析后的值设置到 resolved 数组中,索引为 i - Array.set(resolved, i, - resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i))); - } - return resolved; - } - - // 解析 list 类型的属性 - private List resolveManagedList(Object argName, List ml) { - List resolved = new ArrayList(ml.size()); - for (int i = 0; i < ml.size(); i++) { - // 递归解析 list 的每一个元素 - resolved.add( - resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i))); - } - return resolved; - } - - // 解析 set 类型的属性 - private Set resolveManagedSet(Object argName, Set ms) { - Set resolved = new LinkedHashSet(ms.size()); - int i = 0; - // 递归解析 set 的每一个元素 - for (Object m : ms) { - resolved.add(resolveValueIfNecessary(new KeyedArgName(argName, i), m)); - i++; - } - return resolved; - } - - // 解析 map 类型的属性 - private Map resolveManagedMap(Object argName, Map mm) { - Map resolved = new LinkedHashMap(mm.size()); - // 递归解析 map 中每一个元素的 key 和 value - for (Map.Entry entry : mm.entrySet()) { - Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey()); - Object resolvedValue = resolveValueIfNecessary( - new KeyedArgName(argName, entry.getKey()), entry.getValue()); - resolved.put(resolvedKey, resolvedValue); - } - return resolved; - } - +class BeanDefinitionValueResolver { + + /** + * 解析属性值,对注入类型进行转换 + */ + public Object resolveValueIfNecessary(Object argName, Object value) { + // 对引用类型的属性进行解析,RuntimeBeanReference 是在对 BeanDefinition 进行解析时生成的数据对象 + if (value instanceof RuntimeBeanReference) { + RuntimeBeanReference ref = (RuntimeBeanReference) value; + /** + * !!!!!!!!!!!!!!!! + * 解析引用类型的属性值 + * !!!!!!!!!!!!!!!! + */ + return resolveReference(argName, ref); + } + + // 对属性值是引用容器中另一个 bean 名称的解析 + else if (value instanceof RuntimeBeanNameReference) { + String refName = ((RuntimeBeanNameReference) value).getBeanName(); + refName = String.valueOf(evaluate(refName)); + if (!this.beanFactory.containsBean(refName)) { + throw new BeanDefinitionStoreException( + "Invalid bean name '" + refName + "' in bean reference for " + argName); + } + return refName; + } + // 对 BeanDefinitionHolder 类型属性的解析,主要是 bean 中的内部类 + else if (value instanceof BeanDefinitionHolder) { + BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value; + return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition()); + } + else if (value instanceof BeanDefinition) { + BeanDefinition bd = (BeanDefinition) value; + return resolveInnerBean(argName, "(inner bean)", bd); + } + // 对集合数组类型的属性解析 + else if (value instanceof ManagedArray) { + ManagedArray array = (ManagedArray) value; + // 获取数组的类型 + Class elementType = array.resolvedElementType; + if (elementType == null) { + // 获取数组元素的类型 + String elementTypeName = array.getElementTypeName(); + if (StringUtils.hasText(elementTypeName)) { + try { + // 使用反射机制创建指定类型的对象 + elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader()); + array.resolvedElementType = elementType; + } + catch (Throwable ex) { + throw new BeanCreationException( + this.beanDefinition.getResourceDescription(), this.beanName, + "Error resolving array type for " + argName, ex); + } + } + // 没有获取到数组的类型,也没有获取到数组元素的类型 + // 则直接设置数组的类型为 Object + else { + elementType = Object.class; + } + } + // 创建指定类型的数组 + return resolveManagedArray(argName, (List) value, elementType); + } + // 解析 list 类型的属性值 + else if (value instanceof ManagedList) { + // May need to resolve contained runtime references. + return resolveManagedList(argName, (List) value); + } + // 解析 set 类型的属性值 + else if (value instanceof ManagedSet) { + // May need to resolve contained runtime references. + return resolveManagedSet(argName, (Set) value); + } + // 解析 map 类型的属性值 + else if (value instanceof ManagedMap) { + // May need to resolve contained runtime references. + return resolveManagedMap(argName, (Map) value); + } + // 解析 Properties 类型的属性值,Properties 其实就是 key 和 value 均为字符串的 map + else if (value instanceof ManagedProperties) { + Properties original = (Properties) value; + // 创建一个拷贝,用于作为解析后的返回值 + Properties copy = new Properties(); + for (Map.Entry propEntry : original.entrySet()) { + Object propKey = propEntry.getKey(); + Object propValue = propEntry.getValue(); + if (propKey instanceof TypedStringValue) { + propKey = evaluate((TypedStringValue) propKey); + } + if (propValue instanceof TypedStringValue) { + propValue = evaluate((TypedStringValue) propValue); + } + copy.put(propKey, propValue); + } + return copy; + } + // 解析字符串类型的属性值 + else if (value instanceof TypedStringValue) { + TypedStringValue typedStringValue = (TypedStringValue) value; + Object valueObject = evaluate(typedStringValue); + try { + // 获取属性的目标类型 + Class resolvedTargetType = resolveTargetType(typedStringValue); + if (resolvedTargetType != null) { + // 对目标类型的属性进行解析,递归调用 + return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType); + } + // 没有获取到属性的目标对象,则按 Object 类型返回 + else { + return valueObject; + } + } + catch (Throwable ex) { + throw new BeanCreationException( + this.beanDefinition.getResourceDescription(), this.beanName, + "Error converting typed String value for " + argName, ex); + } + } + else { + return evaluate(value); + } + } + + /** + * 解析引用类型的属性值 + */ + private Object resolveReference(Object argName, RuntimeBeanReference ref) { + try { + // 获取 所引用bean 的 beanName + String refName = ref.getBeanName(); + refName = String.valueOf(evaluate(refName)); + // 如果引用的对象在父容器中,则从父容器中获取指定的引用对象 + if (ref.isToParent()) { + if (this.beanFactory.getParentBeanFactory() == null) { + throw new BeanCreationException( + this.beanDefinition.getResourceDescription(), this.beanName, + "Can't resolve reference to bean '" + refName + + "' in parent factory: no parent factory available"); + } + return this.beanFactory.getParentBeanFactory().getBean(refName); + } + // 从当前的容器中获取指定的引用 bean对象,如果指定的 bean 没有被实例化 + // 则会递归触发引用 bean 的初始化和依赖注入 + else { + Object bean = this.beanFactory.getBean(refName); + // 为 refName对应的bean 注入 它所依赖的bean + this.beanFactory.registerDependentBean(refName, this.beanName); + return bean; + } + } + catch (BeansException ex) { + throw new BeanCreationException( + this.beanDefinition.getResourceDescription(), this.beanName, + "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex); + } + } + + /** + * 解析 array 类型的属性 + */ + private Object resolveManagedArray(Object argName, List ml, Class elementType) { + // 创建一个指定类型的数组,用于存放和返回解析后的数组 + Object resolved = Array.newInstance(elementType, ml.size()); + for (int i = 0; i < ml.size(); i++) { + // 递归解析 array 的每一个元素,并将解析后的值设置到 resolved 数组中,索引为 i + Array.set(resolved, i, + resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i))); + } + return resolved; + } + + /** + * 解析 list 类型的属性 + */ + private List resolveManagedList(Object argName, List ml) { + List resolved = new ArrayList(ml.size()); + for (int i = 0; i < ml.size(); i++) { + // 递归解析 list 的每一个元素 + resolved.add( + resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i))); + } + return resolved; + } + + /** + * 解析 set 类型的属性 + */ + private Set resolveManagedSet(Object argName, Set ms) { + Set resolved = new LinkedHashSet(ms.size()); + int i = 0; + // 递归解析 set 的每一个元素 + for (Object m : ms) { + resolved.add(resolveValueIfNecessary(new KeyedArgName(argName, i), m)); + i++; + } + return resolved; + } + + /** + * 解析 map 类型的属性 + */ + private Map resolveManagedMap(Object argName, Map mm) { + Map resolved = new LinkedHashMap(mm.size()); + // 递归解析 map 中每一个元素的 key 和 value + for (Map.Entry entry : mm.entrySet()) { + Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey()); + Object resolvedValue = resolveValueIfNecessary( + new KeyedArgName(argName, entry.getKey()), entry.getValue()); + resolved.put(resolvedKey, resolvedValue); + } + return resolved; + } +} ``` -至此,已经为依赖注入做好了准备,下面就该将 bean 对象设置到它所依赖的另一个 bean 的属性中去。AbstractPropertyAccessor 和其子类 BeanWrapperImpl 完成了依赖注入的详细过程。 -## 8、AbstractPropertyAccessor 中的实现 +至此,已经为依赖注入做好了准备,下面就该将 bean对象 设置到它所依赖的另一个 bean 的属性中去。AbstractPropertyAccessor 和其子类 BeanWrapperImpl 完成了依赖注入的详细过程。先看一下 AbstractPropertyAccessor 中的实现。 ```java - public void setPropertyValues(PropertyValues pvs) throws BeansException { - setPropertyValues(pvs, false, false); - } - - public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid) - throws BeansException { - - List propertyAccessExceptions = null; - List propertyValues = (pvs instanceof MutablePropertyValues ? - ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues())); - for (PropertyValue pv : propertyValues) { - try { - /** - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * 走 BeanWrapperImpl 中的实现,也是 bean 属性值注入具体实现的入口 - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - */ - setPropertyValue(pv); - } - catch (NotWritablePropertyException ex) { - if (!ignoreUnknown) { - throw ex; - } - } - catch (NullValueInNestedPathException ex) { - if (!ignoreInvalid) { - throw ex; - } - } - catch (PropertyAccessException ex) { - if (propertyAccessExceptions == null) { - propertyAccessExceptions = new LinkedList(); - } - propertyAccessExceptions.add(ex); - } - } - - // 如果遇到个别异常,则抛出复合异常 - if (propertyAccessExceptions != null) { - PropertyAccessException[] paeArray = - propertyAccessExceptions.toArray(new PropertyAccessException[propertyAccessExceptions.size()]); - throw new PropertyBatchUpdateException(paeArray); - } - } - +public abstract class AbstractPropertyAccessor extends TypeConverterSupport implements ConfigurablePropertyAccessor { + + /** + * setPropertyValues() 方法有多种重载,但最终都走的是 + * setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)重载方法 + */ + public void setPropertyValues(Map map) throws BeansException { + setPropertyValues(new MutablePropertyValues(map)); + } + + public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown) throws BeansException { + setPropertyValues(pvs, ignoreUnknown, false); + } + + public void setPropertyValues(PropertyValues pvs) throws BeansException { + setPropertyValues(pvs, false, false); + } + + public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid) + throws BeansException { + + List propertyAccessExceptions = null; + List propertyValues = (pvs instanceof MutablePropertyValues ? + ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues())); + for (PropertyValue pv : propertyValues) { + try { + /** + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * 该方法走 BeanWrapperImpl 中的实现,这是 bean属性值注入 具体实现的入口 + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + setPropertyValue(pv); + } + catch (NotWritablePropertyException ex) { + if (!ignoreUnknown) { + throw ex; + } + } + catch (NullValueInNestedPathException ex) { + if (!ignoreInvalid) { + throw ex; + } + } + catch (PropertyAccessException ex) { + if (propertyAccessExceptions == null) { + propertyAccessExceptions = new LinkedList(); + } + propertyAccessExceptions.add(ex); + } + } + + // 如果出现 PropertyAccessException 异常,则将这些异常积累起来放到一个集合中,然后一次性抛出!!! + // 这种抛异常的方式 在实际的开发中也时常使用,可以好好看一下,对比一下 + if (propertyAccessExceptions != null) { + PropertyAccessException[] paeArray = + propertyAccessExceptions.toArray(new PropertyAccessException[propertyAccessExceptions.size()]); + throw new PropertyBatchUpdateException(paeArray); + } + } +} ``` - -## 9、BeanWrapperImpl 中的实现 +最后看一下 BeanWrapperImpl 中的实现。 ```java - @Override - public void setPropertyValue(PropertyValue pv) throws BeansException { - // PropertyTokenHolder 是一个用于内部使用的内部类 - PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens; - if (tokens == null) { - String propertyName = pv.getName(); - BeanWrapperImpl nestedBw; - try { - nestedBw = getBeanWrapperForPropertyPath(propertyName); - } - catch (NotReadablePropertyException ex) { - throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, - "Nested property in path '" + propertyName + "' does not exist", ex); - } - tokens = getPropertyNameTokens(getFinalPath(nestedBw, propertyName)); - if (nestedBw == this) { - pv.getOriginalPropertyValue().resolvedTokens = tokens; - } - - /** - * !!!!!!!!!!!!!!! - * 进入 bean 属性值注入的具体实现 - * !!!!!!!!!!!!!!! - */ - nestedBw.setPropertyValue(tokens, pv); - } - else { - setPropertyValue(tokens, pv); - } - } - - /** - * !!!!!!!!!!!!!!!! - * 实现属性值依赖注入的具体实现 - * !!!!!!!!!!!!!!!! - */ - @SuppressWarnings("unchecked") - private void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException { - // PropertyTokenHolder 主要保存属性的名称、路径、以及集合的 size 等信息 - String propertyName = tokens.canonicalName; - String actualName = tokens.actualName; - - // 对集合类型的属性注入 - // keys 是用来保存集合类型属性的 size - if (tokens.keys != null) { - // 将属性信息从 tokens 拷贝到 getterTokens - PropertyTokenHolder getterTokens = new PropertyTokenHolder(); - getterTokens.canonicalName = tokens.canonicalName; - getterTokens.actualName = tokens.actualName; - getterTokens.keys = new String[tokens.keys.length - 1]; - System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1); - Object propValue; - try { - // 通过反射机制,调用属性的 getter 方法获取属性值 - propValue = getPropertyValue(getterTokens); - } - catch (NotReadablePropertyException ex) { - throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, - "Cannot access indexed value in property referenced " + - "in indexed property path '" + propertyName + "'", ex); - } - // 获取集合类型属性的长度 - String key = tokens.keys[tokens.keys.length - 1]; - if (propValue == null) { - if (this.autoGrowNestedPaths) { - int lastKeyIndex = tokens.canonicalName.lastIndexOf('['); - getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex); - propValue = setDefaultValue(getterTokens); - } - else { - throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName, - "Cannot access indexed value in property referenced " + - "in indexed property path '" + propertyName + "': returned null"); - } - } - // 如果属性值是 Array 数组类型的,则注入 array 类型的属性值 - if (propValue.getClass().isArray()) { - // 获取属性的描述符 - PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); - // 获取数组的类型 - Class requiredType = propValue.getClass().getComponentType(); - // 获取数组的长度 - int arrayIndex = Integer.parseInt(key); - Object oldValue = null; - try { - // 获取数组以前初始化的值 - if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) { - oldValue = Array.get(propValue, arrayIndex); - } - // 将属性的值赋值给数组中的元素 - Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), - requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length)); - Array.set(propValue, arrayIndex, convertedValue); - } - catch (IndexOutOfBoundsException ex) { - throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, - "Invalid array index in property path '" + propertyName + "'", ex); - } - } - // 如果属性值是 List 类型的,则注入 list 类型的属性值 - else if (propValue instanceof List) { - PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); - // 获取 list 集合中元素的类型 - Class requiredType = GenericCollectionTypeResolver.getCollectionReturnType( - pd.getReadMethod(), tokens.keys.length); - List list = (List) propValue; - - int index = Integer.parseInt(key); - Object oldValue = null; - if (isExtractOldValueForEditor() && index < list.size()) { - oldValue = list.get(index); - } - // 获取 list 解析后的属性值 - Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), - requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length)); - // 获取 list 集合的 size - int size = list.size(); - // 如果 list 的长度大于属性值的长度,则多余的元素赋值为 null - if (index >= size && index < this.autoGrowCollectionLimit) { - for (int i = size; i < index; i++) { - try { - list.add(null); - } - catch (NullPointerException ex) { - throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, - "Cannot set element with index " + index + " in List of size " + - size + ", accessed using property path '" + propertyName + - "': List does not support filling up gaps with null elements"); - } - } - list.add(convertedValue); - } - else { - try { - // 为 list 属性赋值 - list.set(index, convertedValue); - } - catch (IndexOutOfBoundsException ex) { - throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, - "Invalid list index in property path '" + propertyName + "'", ex); - } - } - } - // 如果属性值是 Map 类型的,则注入 Map 类型的属性值 - else if (propValue instanceof Map) { - PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); - // 获取 map 集合 key 的类型 - Class mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType( - pd.getReadMethod(), tokens.keys.length); - // 获取 map 集合 value 的类型 - Class mapValueType = GenericCollectionTypeResolver.getMapValueReturnType( - pd.getReadMethod(), tokens.keys.length); - Map map = (Map) propValue; - TypeDescriptor typeDescriptor = (mapKeyType != null ? - TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class)); - // 解析 map 类型属性 key 值 - Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor); - Object oldValue = null; - if (isExtractOldValueForEditor()) { - oldValue = map.get(convertedMapKey); - } - // 解析 map 类型属性 value 值 - Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), - mapValueType, TypeDescriptor.nested(property(pd), tokens.keys.length)); - // 将解析后的 key 和 value 值赋值给 map 集合属性 - map.put(convertedMapKey, convertedMapValue); - } - else { - throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, - "Property referenced in indexed property path '" + propertyName + - "' is neither an array nor a List nor a Map; returned value was [" + pv.getValue() + "]"); - } - } - // 对非集合类型的属性注入 - else { - PropertyDescriptor pd = pv.resolvedDescriptor; - if (pd == null || !pd.getWriteMethod().getDeclaringClass().isInstance(this.object)) { - pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); - // 如果无法获取到属性名或者属性没有提供 setter 赋值方法 - if (pd == null || pd.getWriteMethod() == null) { - // 如果属性值是可选的,即不是必须的,则忽略该属性值 - if (pv.isOptional()) { - logger.debug("Ignoring optional value for property '" + actualName + - "' - property not found on bean class [" + getRootClass().getName() + "]"); - return; - } - // 如果属性值是必须的,则抛出无法给属性赋值,因为没提供 setter 方法的异常 - else { - PropertyMatches matches = PropertyMatches.forProperty(propertyName, getRootClass()); - throw new NotWritablePropertyException( - getRootClass(), this.nestedPath + propertyName, - matches.buildErrorMessage(), matches.getPossibleMatches()); - } - } - pv.getOriginalPropertyValue().resolvedDescriptor = pd; - } - - Object oldValue = null; - try { - Object originalValue = pv.getValue(); - Object valueToApply = originalValue; - if (!Boolean.FALSE.equals(pv.conversionNecessary)) { - if (pv.isConverted()) { - valueToApply = pv.getConvertedValue(); - } - else { - if (isExtractOldValueForEditor() && pd.getReadMethod() != null) { - // 获取属性的 getter 方法 - final Method readMethod = pd.getReadMethod(); - // 如果属性的 getter 方法无法访问,则使用 Java 的反射机制强行访问 (暴力读取属性值) - if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()) && - !readMethod.isAccessible()) { - if (System.getSecurityManager()!= null) { - // 匿名内部类,根据权限修改属性的读取控制限制 - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - readMethod.setAccessible(true); - return null; - } - }); - } - else { - readMethod.setAccessible(true); - } - } - try { - // 属性没有提供 getter 方法时,调用潜在的读取属性值的方法,获取属性值 - if (System.getSecurityManager() != null) { - oldValue = AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - return readMethod.invoke(object); - } - }, acc); - } - else { - oldValue = readMethod.invoke(object); - } - } - catch (Exception ex) { - if (ex instanceof PrivilegedActionException) { - ex = ((PrivilegedActionException) ex).getException(); - } - if (logger.isDebugEnabled()) { - logger.debug("Could not read previous value of property '" + - this.nestedPath + propertyName + "'", ex); - } - } - } - // 设置属性的注入值 - valueToApply = convertForProperty(propertyName, oldValue, originalValue, pd); - } - pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue); - } - // 根据 Java 的内省机制,获取属性的 setter(写方法) 方法 - final Method writeMethod = (pd instanceof GenericTypeAwarePropertyDescriptor ? - ((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodForActualAccess() : - pd.getWriteMethod()); - // 如果属性的 setter 方法无法访问,则强行设置 setter 方法可访问 (暴力为属性赋值) - if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) { - if (System.getSecurityManager()!= null) { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - writeMethod.setAccessible(true); - return null; - } - }); - } - else { - writeMethod.setAccessible(true); - } - } - final Object value = valueToApply; - // 如果使用了 Java 的安全机制,则需要权限验证 - if (System.getSecurityManager() != null) { - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - // 将属性值设置到属性上去 - writeMethod.invoke(object, value); - return null; - } - }, acc); - } - catch (PrivilegedActionException ex) { - throw ex.getException(); - } - } - else { - // 将属性值设置到属性上去 - writeMethod.invoke(this.object, value); - } - } - catch (TypeMismatchException ex) { - throw ex; - } - catch (InvocationTargetException ex) { - PropertyChangeEvent propertyChangeEvent = - new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue()); - if (ex.getTargetException() instanceof ClassCastException) { - throw new TypeMismatchException(propertyChangeEvent, pd.getPropertyType(), ex.getTargetException()); - } - else { - throw new MethodInvocationException(propertyChangeEvent, ex.getTargetException()); - } - } - catch (Exception ex) { - PropertyChangeEvent pce = - new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue()); - throw new MethodInvocationException(pce, ex); - } - } - } - +public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWrapper { + + @Override + public void setPropertyValue(PropertyValue pv) throws BeansException { + // PropertyTokenHolder 是一个用于内部使用的内部类 + PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens; + if (tokens == null) { + String propertyName = pv.getName(); + BeanWrapperImpl nestedBw; + try { + nestedBw = getBeanWrapperForPropertyPath(propertyName); + } + catch (NotReadablePropertyException ex) { + throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, + "Nested property in path '" + propertyName + "' does not exist", ex); + } + tokens = getPropertyNameTokens(getFinalPath(nestedBw, propertyName)); + if (nestedBw == this) { + pv.getOriginalPropertyValue().resolvedTokens = tokens; + } + + /** + * !!!!!!!!!!!!!!! + * 进入 bean 属性值注入的具体实现 + * !!!!!!!!!!!!!!! + */ + nestedBw.setPropertyValue(tokens, pv); + } + else { + setPropertyValue(tokens, pv); + } + } + + /** + * !!!!!!!!!!!!!!!! + * 依赖注入(将某个bean所依赖的值 注入到这个bean中) 的具体实现 + * !!!!!!!!!!!!!!!! + */ + @SuppressWarnings("unchecked") + private void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException { + // PropertyTokenHolder 是定义在 BeanWrapperImpl 中的内部类,主要保存属性的名称、路径、 + // 以及集合的 size 等信息 + String propertyName = tokens.canonicalName; + String actualName = tokens.actualName; + + // 对集合类型的属性注入,PropertyTokenHolder 的 keys 是用来保存集合类型属性的 size + if (tokens.keys != null) { + // 将属性信息从 tokens 拷贝到 getterTokens + PropertyTokenHolder getterTokens = new PropertyTokenHolder(); + getterTokens.canonicalName = tokens.canonicalName; + getterTokens.actualName = tokens.actualName; + getterTokens.keys = new String[tokens.keys.length - 1]; + System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1); + Object propValue; + try { + // 通过反射机制,调用属性的 getter 方法获取属性值 + propValue = getPropertyValue(getterTokens); + } + catch (NotReadablePropertyException ex) { + throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, + "Cannot access indexed value in property referenced " + + "in indexed property path '" + propertyName + "'", ex); + } + // 获取集合类型属性的长度 + String key = tokens.keys[tokens.keys.length - 1]; + if (propValue == null) { + if (this.autoGrowNestedPaths) { + int lastKeyIndex = tokens.canonicalName.lastIndexOf('['); + getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex); + propValue = setDefaultValue(getterTokens); + } + else { + throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName, + "Cannot access indexed value in property referenced " + + "in indexed property path '" + propertyName + "': returned null"); + } + } + // 如果属性值是 Array 数组类型的,则注入 array 类型的属性值 + if (propValue.getClass().isArray()) { + // 获取属性的描述符 + PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); + // 获取数组的类型 + Class requiredType = propValue.getClass().getComponentType(); + // 获取数组的长度 + int arrayIndex = Integer.parseInt(key); + Object oldValue = null; + try { + // 获取数组以前初始化的值 + if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) { + oldValue = Array.get(propValue, arrayIndex); + } + // 将属性的值赋值给数组中的元素 + Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), + requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length)); + Array.set(propValue, arrayIndex, convertedValue); + } + catch (IndexOutOfBoundsException ex) { + throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, + "Invalid array index in property path '" + propertyName + "'", ex); + } + } + // 如果属性值是 List 类型的,则注入 list 类型的属性值 + else if (propValue instanceof List) { + PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); + // 获取 list 集合中元素的类型 + Class requiredType = GenericCollectionTypeResolver.getCollectionReturnType( + pd.getReadMethod(), tokens.keys.length); + List list = (List) propValue; + + int index = Integer.parseInt(key); + Object oldValue = null; + if (isExtractOldValueForEditor() && index < list.size()) { + oldValue = list.get(index); + } + // 获取 list 解析后的属性值 + Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), + requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length)); + // 获取 list 集合的 size + int size = list.size(); + // 如果 list 的长度大于属性值的长度,则多余的元素赋值为 null + if (index >= size && index < this.autoGrowCollectionLimit) { + for (int i = size; i < index; i++) { + try { + list.add(null); + } + catch (NullPointerException ex) { + throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, + "Cannot set element with index " + index + " in List of size " + + size + ", accessed using property path '" + propertyName + + "': List does not support filling up gaps with null elements"); + } + } + list.add(convertedValue); + } + else { + try { + // 为 list 属性赋值 + list.set(index, convertedValue); + } + catch (IndexOutOfBoundsException ex) { + throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, + "Invalid list index in property path '" + propertyName + "'", ex); + } + } + } + // 如果属性值是 Map 类型的,则注入 Map 类型的属性值 + else if (propValue instanceof Map) { + PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); + // 获取 map 集合 key 的类型 + Class mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType( + pd.getReadMethod(), tokens.keys.length); + // 获取 map 集合 value 的类型 + Class mapValueType = GenericCollectionTypeResolver.getMapValueReturnType( + pd.getReadMethod(), tokens.keys.length); + Map map = (Map) propValue; + TypeDescriptor typeDescriptor = (mapKeyType != null ? + TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class)); + // 解析 map 类型属性 key 值 + Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor); + Object oldValue = null; + if (isExtractOldValueForEditor()) { + oldValue = map.get(convertedMapKey); + } + // 解析 map 类型属性 value 值 + Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), + mapValueType, TypeDescriptor.nested(property(pd), tokens.keys.length)); + // 将解析后的 key 和 value 值赋值给 map 集合属性 + map.put(convertedMapKey, convertedMapValue); + } + else { + throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName, + "Property referenced in indexed property path '" + propertyName + + "' is neither an array nor a List nor a Map; returned value was [" + pv.getValue() + "]"); + } + } + // 对非集合类型的属性注入 + else { + PropertyDescriptor pd = pv.resolvedDescriptor; + if (pd == null || !pd.getWriteMethod().getDeclaringClass().isInstance(this.object)) { + pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName); + // 如果无法获取到属性名或者属性没有提供 setter 赋值方法 + if (pd == null || pd.getWriteMethod() == null) { + // 如果属性值是可选的,即不是必须的,则忽略该属性值 + if (pv.isOptional()) { + logger.debug("Ignoring optional value for property '" + actualName + + "' - property not found on bean class [" + getRootClass().getName() + "]"); + return; + } + // 如果属性值是必须的,则抛出无法给属性赋值,因为没提供 setter 方法的异常 + else { + PropertyMatches matches = PropertyMatches.forProperty(propertyName, getRootClass()); + throw new NotWritablePropertyException( + getRootClass(), this.nestedPath + propertyName, + matches.buildErrorMessage(), matches.getPossibleMatches()); + } + } + pv.getOriginalPropertyValue().resolvedDescriptor = pd; + } + + Object oldValue = null; + try { + Object originalValue = pv.getValue(); + Object valueToApply = originalValue; + if (!Boolean.FALSE.equals(pv.conversionNecessary)) { + if (pv.isConverted()) { + valueToApply = pv.getConvertedValue(); + } + else { + if (isExtractOldValueForEditor() && pd.getReadMethod() != null) { + // 获取属性的 getter 方法 + final Method readMethod = pd.getReadMethod(); + // 如果属性的 getter 方法无法访问,则使用 Java 的反射机制强行访问 (暴力读取属性值) + if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()) && + !readMethod.isAccessible()) { + if (System.getSecurityManager()!= null) { + // 匿名内部类,根据权限修改属性的读取控制限制 + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + readMethod.setAccessible(true); + return null; + } + }); + } + else { + readMethod.setAccessible(true); + } + } + try { + // 属性没有提供 getter 方法时,调用潜在的读取属性值的方法,获取属性值 + if (System.getSecurityManager() != null) { + oldValue = AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws Exception { + return readMethod.invoke(object); + } + }, acc); + } + else { + oldValue = readMethod.invoke(object); + } + } + catch (Exception ex) { + if (ex instanceof PrivilegedActionException) { + ex = ((PrivilegedActionException) ex).getException(); + } + if (logger.isDebugEnabled()) { + logger.debug("Could not read previous value of property '" + + this.nestedPath + propertyName + "'", ex); + } + } + } + // 设置属性的注入值 + valueToApply = convertForProperty(propertyName, oldValue, originalValue, pd); + } + pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue); + } + // 根据 Java 的内省机制,获取属性的 setter方法 + final Method writeMethod = (pd instanceof GenericTypeAwarePropertyDescriptor ? + ((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodForActualAccess() : + pd.getWriteMethod()); + // 如果属性的 setter方法 无法访问,则强行设置 setter方法 可访问 (暴力为属性赋值) + if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) { + if (System.getSecurityManager()!= null) { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + writeMethod.setAccessible(true); + return null; + } + }); + } + else { + writeMethod.setAccessible(true); + } + } + final Object value = valueToApply; + // 如果使用了 Java 的安全机制,则需要权限验证 + if (System.getSecurityManager() != null) { + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws Exception { + // 将属性值设置到属性上去 + writeMethod.invoke(object, value); + return null; + } + }, acc); + } + catch (PrivilegedActionException ex) { + throw ex.getException(); + } + } + else { + // 将属性值设置到属性上去 + writeMethod.invoke(this.object, value); + } + } + catch (TypeMismatchException ex) { + throw ex; + } + catch (InvocationTargetException ex) { + PropertyChangeEvent propertyChangeEvent = + new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue()); + if (ex.getTargetException() instanceof ClassCastException) { + throw new TypeMismatchException(propertyChangeEvent, pd.getPropertyType(), ex.getTargetException()); + } + else { + throw new MethodInvocationException(propertyChangeEvent, ex.getTargetException()); + } + } + catch (Exception ex) { + PropertyChangeEvent pce = + new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue()); + throw new MethodInvocationException(pce, ex); + } + } + } +} ``` -终于完成了对 bean 的各种属性的依赖注入,在 bean 的实例化和依赖注入的过程中,需要依据 BeanDefinition 中的信息来递归地完成依赖注入。另外,在此过程中存在许多递归调用,一个递归是在上下文体系中查找需要的 bean 和创建 bean 的递归调用;另一个是在依赖注入时,通过递归调用容器的 getBean 方法,得到当前 bean 的依赖 bean,同时也触发对依赖 bean 的创建和注入;在对 bean 的属性进行依赖注入时,解析的过程也是递归的。这样,根据依赖关系,一层一层地完成 bean 的创建和注入,直到最后完成当前 bean 的创建。 +至此,完成了对 bean 的各种属性的依赖注入,在 bean 的实例化和依赖注入的过程中,需要依据 BeanDefinition 中的信息来递归地完成依赖注入。另外,在此过程中存在许多递归调用,一个递归是在上下文体系中查找 当前bean依赖的bean 和创建 当前bean依赖的bean 的递归调用;另一个是在依赖注入时,通过递归调用容器的 getBean() 方法,得到当前 bean 的依赖 bean,同时也触发对依赖 bean 的创建和注入;在对 bean 的属性进行依赖注入时,解析的过程也是递归的。这样,根据依赖关系,从最末层的依赖bean开始,一层一层地完成 bean 的创建和注入,直到最后完成当前 bean 的创建。 -## 最后补充一下通过 lazy-init 属性触发的依赖注入 -lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 BeanDefinition 的定位、载入、解析和注册之后。虽然会影响 IoC 容器初始化的性能,但确能有效提高应用第一次获取该 bean 的效率。 +## lazy-init 属性触发的依赖注入 +最后看一下 lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 BeanDefinition 的定位、载入、解析和注册之后。通过牺牲 IoC 容器初始化的性能,来有效提升应用第一次获取该 bean 的效率。 lazy-init 实现的入口方法在我们前面解读过的 AbstractApplicationContext 的 refresh() 中,它是 IoC 容器正式启动的标志。 ```java - /** - * 容器初始化的过程:BeanDefinition 的 Resource 定位、BeanDefinition 的载入、BeanDefinition 的注册。 - * BeanDefinition 的载入和 bean 的依赖注入是两个独立的过程,依赖注入一般发生在 应用第一次通过 getBean() 方法从容器获取 bean 时。 - * - * 另外需要注意的是,IoC 容器有一个预实例化的配置(即,将 AbstractBeanDefinition 中的 lazyInit 属性设为 true),使用户可以对容器的初始化 - * 过程做一个微小的调控,lazyInit 设为 true 的 bean 将在容器初始化时进行依赖注入,而不会等到 getBean() 方法调用时才进行 - */ - public void refresh() throws BeansException, IllegalStateException { - synchronized (this.startupShutdownMonitor) { - // 调用容器准备刷新的方法,获取容器的当前时间,同时给容器设置同步标识 - prepareRefresh(); - - // 告诉子类启动 refreshBeanFactory() 方法,Bean 定义资源文件的载入从子类的 refreshBeanFactory() 方法启动开始 - ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); - - // 为 BeanFactory 配置容器特性,例如类加载器、事件处理器等 - prepareBeanFactory(beanFactory); - - try { - // 为容器的某些子类指定特殊的 BeanPost 事件处理器 - postProcessBeanFactory(beanFactory); - - // 调用所有注册的 BeanFactoryPostProcessor 的 Bean - invokeBeanFactoryPostProcessors(beanFactory); - - // 为 BeanFactory 注册 BeanPost 事件处理器. - // BeanPostProcessor 是 Bean 后置处理器,用于监听容器触发的事件 - registerBeanPostProcessors(beanFactory); - - // 初始化信息源,和国际化相关. - initMessageSource(); - - // 初始化容器事件传播器 - initApplicationEventMulticaster(); - - // 调用子类的某些特殊 Bean 初始化方法 - onRefresh(); - - // 为事件传播器注册事件监听器. - registerListeners(); - - /** - * !!!!!!!!!!!!!!!!!!!!! - * 初始化 Bean,并对 lazy-init 属性进行处理 - * !!!!!!!!!!!!!!!!!!!!! - */ - finishBeanFactoryInitialization(beanFactory); - - // 初始化容器的生命周期事件处理器,并发布容器的生命周期事件 - finishRefresh(); - } - - catch (BeansException ex) { - // 销毁以创建的单态 Bean - destroyBeans(); - - // 取消 refresh 操作,重置容器的同步标识. - cancelRefresh(ex); - - throw ex; - } - } - } - - // 对配置了 lazy-init 属性的 Bean 进行预实例化处理 - protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { - // 这是 Spring3 以后新加的代码,为容器指定一个转换服务 (ConversionService) - // 在对某些 Bean 属性进行转换时使用 - if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && - beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { - beanFactory.setConversionService( - /** - * !!!!!!!!!!!!!!!!!!!! - * 在这里调用了 getBean() 方法,触发依赖注入 - * !!!!!!!!!!!!!!!!!!!! - */ - beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); - } - - String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); - for (String weaverAwareName : weaverAwareNames) { - getBean(weaverAwareName); - } - - // 为了类型匹配,停止使用临时的类加载器 - beanFactory.setTempClassLoader(null); - - // 缓存容器中所有注册的 BeanDefinition 元数据,以防被修改 - beanFactory.freezeConfiguration(); - - // 对配置了 lazy-init 属性的单态模式 Bean 进行预实例化处理 - beanFactory.preInstantiateSingletons(); - } - +public abstract class AbstractApplicationContext extends DefaultResourceLoader + implements ConfigurableApplicationContext, DisposableBean { + + /** + * 容器初始化的过程: + * 1、根据指定规则扫描指定目录,获取所有 用于配置bean的配置文件; + * 2、根据 Spring定义的规则,解析配置文件中的各个元素,将其封装成 IoC容器 可以装载的 BeanDefinition对象; + * 3、将封装好的 BeanDefinition 注册进 IoC容器。 + * + * IoC容器的初始化 和 bean的依赖注入 是两个独立的过程,依赖注入一般发生在应用第一次通过 getBean()方法 + * 从容器获取 bean 时。 + * 另外需要注意的是,IoC容器 有一个预实例化的配置(即,将 元素 的 lazyInit属性 设为 false), + * 使该 元素对应的 bean可以提前实例化,而不用等到调用 getBean()方法 时才开始实例化。 + */ + public void refresh() throws BeansException, IllegalStateException { + synchronized (this.startupShutdownMonitor) { + // 调用容器准备刷新的方法,获取容器的当前时间,同时给容器设置同步标识 + prepareRefresh(); + + // 告诉子类启动 refreshBeanFactory() 方法,BeanDefinition 资源文件的载入从子类的 + // refreshBeanFactory() 方法启动开始 + ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); + + // 为 BeanFactory 配置容器特性,例如类加载器、事件处理器等 + prepareBeanFactory(beanFactory); + + try { + // 为容器的某些子类指定特殊的 BeanPost 事件处理器 + postProcessBeanFactory(beanFactory); + + // 调用所有注册的 BeanFactoryPostProcessor + invokeBeanFactoryPostProcessors(beanFactory); + + // 为 BeanFactory 注册 BeanPost 事件处理器. + // BeanPostProcessor 是 Bean 后置处理器,用于监听容器触发的事件 + registerBeanPostProcessors(beanFactory); + + // 初始化信息源,和国际化相关. + initMessageSource(); + + // 初始化容器事件传播器 + initApplicationEventMulticaster(); + + // 调用子类的某些特殊 Bean 初始化方法 + onRefresh(); + + // 为事件传播器注册事件监听器. + registerListeners(); + + /** + * !!!!!!!!!!!!!!!!!!!!! + * 对配置了 lazy-init属性为true的bean 进行预实例化 + * !!!!!!!!!!!!!!!!!!!!! + */ + finishBeanFactoryInitialization(beanFactory); + + // 初始化容器的生命周期事件处理器,并发布容器的生命周期事件 + finishRefresh(); + } + + catch (BeansException ex) { + // 销毁以创建的单态 Bean + destroyBeans(); + + // 取消 refresh 操作,重置容器的同步标识. + cancelRefresh(ex); + + throw ex; + } + } + } + + /** + * 对配置了 lazy-init属性为true的bean 进行预实例化 + */ + protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { + // 这是 Spring3 以后新加的代码,为容器指定一个转换服务 (ConversionService) + // 在对某些 bean 属性进行转换时使用 + if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && + beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { + beanFactory.setConversionService( + /** + * !!!!!!!!!!!!!!!!!!!! + * 在这里 通过调用 getBean()方法,触发依赖注入 + * !!!!!!!!!!!!!!!!!!!! + */ + beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); + } + + String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); + for (String weaverAwareName : weaverAwareNames) { + getBean(weaverAwareName); + } + + // 为了类型匹配,停止使用临时的类加载器 + beanFactory.setTempClassLoader(null); + + // 缓存容器中所有注册的 BeanDefinition 元数据,以防被修改 + beanFactory.freezeConfiguration(); + + // 对配置了 lazy-init属性 的 单例bean 进行预实例化处理 + beanFactory.preInstantiateSingletons(); + } +} ``` diff --git a/docs/Spring/SpringMVC/IoC容器在Web环境中的启动.md b/docs/Spring/SpringMVC/IoC容器在Web环境中的启动.md index afc89e4..79d1294 100644 --- a/docs/Spring/SpringMVC/IoC容器在Web环境中的启动.md +++ b/docs/Spring/SpringMVC/IoC容器在Web环境中的启动.md @@ -1,9 +1,9 @@ ## 1 Web环境中的SpringMVC -在Web环境中,SpringMVC是建立在IoC容器基础上的。了解SpringMVC,首先要了解Spring的IoC容器是如何在Web环境中被载人并起作用的。 +在 Web环境 中,SpringMVC 是建立在 IoC容器 基础上的。了解 SpringMVC,首先要了解 Spring 的 IoC容器 是如何在 Web环境 中被载入并起作用的。 -Spring的IoC是一个独立模块,它并不直接在Web容器中发挥作用,如果要在Web环境中使用IoC容器,需要Spring为IoC设计一个启动过程,把IoC容器导入,并在Web容器中建立起来。具体说来,这个启动过程是和Web容器的启动过程集成在一起的。在这个过程中,一方面处理Web容器的启动,另一方面通过设计特定的Web容器拦截器,将IoC容器载人到Web环境中来,并将其初始化。在这个过程建立完成以后,IoC容器才能正常工作,而SpringMVC是建立在IoC容器的基础上的,这样才能建立起MVC框架的运行机制,从而响应从Web容器传递的HTTP请求。 +Spring 的 IoC 是一个独立模块,它并不直接在 Web容器 中发挥作用,如果要在 Web环境 中使用 IoC容器,需要 Spring 为 IoC 设计一个启动过程,把 IoC容器 导入,并在 Web容器 中建立起来。具体说来,这个启动过程是和 Web容器 的启动过程集成在一起的。在这个过程中,一方面处理 Web容器 的启动,另一方面通过设计特定的 Web容器拦截器,将 IoC容器 载人到 Web环境 中来,并将其初始化。在这个过程建立完成以后,IoC容器 才能正常工作,而 SpringMVC 是建立在 IoC容器 的基础上的,这样才能建立起 MVC框架 的运行机制,从而响应从 Web容器 传递的 HTTP请求。 -下面以Tomcat作为Web容器的例子进行分析。在Tomcat中,web.xml是应用的部署描述文件。在web.xml中常常经常能看到与Spring相关的部署描述。 +下面以 Tomcat 作为 Web容器 的例子进行分析。在 Tomcat 中,web.xml 是应用的部署描述文件。在 web.xml 中常常经常能看到与 Spring 相关的部署描述。 ```xml sample @@ -22,320 +22,318 @@ Spring的IoC是一个独立模块,它并不直接在Web容器中发挥作用 org.springframework.web.context.ContextLoaderListener ``` -web.xml是SpringMVC与Tomcat的接口部分。这个部署描述文件中,首先定义了一个Servlet对象,它是SpringMVC的DispatcherServlet。这个DispatcherServlet是MVC中很重要的一个类,起着分发请求的作用。 +web.xml 是 SpringMVC 与 Tomcat 的接口部分。这个部署描述文件中,首先定义了一个 Servlet对象,它是 SpringMVC 的 DispatcherServlet。这个 DispatcherServlet 是 MVC 中很重要的一个类,起着分发请求的作用。 -同时,在部署描述中,还为这个DispatcherServlet定义了对应的URL映射,以指定这个Servlet需要处理的HTTP请求范围。context-param参数用来指定IoC容器读取Bean的XML文件的路径,在这里,这个配置文件被定义为WEB-INF/applicationContext.xml。其中可以看到Spring应用的Bean配置。 +同时,在部署描述中,还为这个 DispatcherServlet 定义了对应的 URL映射,以指定这个 Servlet 需要处理的 HTTP请求范围。context-param参数 用来指定 IoC容器 读取 Bean 的 XML文件 的路径,在这里,这个配置文件被定义为 WEB-INF/applicationContext.xml。其中可以看到 Spring应用 的 Bean配置。 -最后,作为Spring MVC的启动类,ContextLoaderListener被定义为一个监听器,这个监听器是与Web服务器的生命周期相关联的,由ContextLoaderListener监听器负责完成 IoC容器在Web环境中的启动工作。 +最后,作为 Spring MVC 的启动类,ContextLoaderListener 被定义为一个监听器,这个监听器是与 Web服务器 的生命周期相关联的,由 ContextLoaderListener监听器 负责完成 IoC容器 在 Web环境 中的启动工作。 -DispatchServlet和ContextLoaderListener提供了在Web容器中对Spring的接口,也就是说,这些接口与Web容器耦合是通过ServletContext来实现的(ServletContext是容器和应用沟通的桥梁,从一定程度上讲ServletContext就是servlet规范的体现)。这个ServletContext为Spring的IoC容器提供了一个宿主环境,在宿主环境中,Spring MVC建立起一个IoC容器的体系。这个IoC容器体系是通过ContextLoaderListener的初始化来建立的,在建立IoC容器体系后,把DispatchServlet作为Spring MVC处理Web请求的转发器建立起来,从而完成响应HTTP请求的准备。有了这些基本配置,建立在IoC容器基础上的SpringMVC就可以正常地发挥作用了。下面我们看一下loC容器在Web容器中的启动代码实现。 +DispatchServlet 和 ContextLoaderListener 提供了在 Web容器 中对 Spring 的接口,也就是说,这些接口与 Web容器 耦合是通过 ServletContext 来实现的(ServletContext 是容器和应用沟通的桥梁,从一定程度上讲 ServletContext 就是 servlet规范 的体现)。这个 ServletContext 为 Spring 的 IoC容器 提供了一个宿主环境,在宿主环境中,Spring MVC 建立起一个 IoC容器 的体系。这个 IoC容器体系 是通过 ContextLoaderListener 的初始化来建立的,在建立 IoC容器体系 后,把 DispatchServlet 作为 Spring MVC 处理 Web请求 的转发器建立起来,从而完成响应 HTTP请求 的准备。有了这些基本配置,建立在 IoC容器 基础上的 SpringMVC 就可以正常地发挥作用了。下面我们看一下 IoC容器 在 Web容器 中的启动代码实现。 ## 2 IoC容器启动的基本过程 -IoC容器的启动过程就是建立上下文的过程,该上下文是与ServletContext相伴而生的,同时也是IoC容器在Web应用环境中的具体表现之一。由ContextLoaderListener启动的上下文为根上下文。在根上下文的基础上,还有一个与Web MVC相关的上下文用来保存控制器(DispatcherServlet)需要的MVC对象,作为根上下文的子上下文,构成一个层次化的上下文体系。在Web容器中启动Spring应用程序时,首先建立根上下文,然后建立这个上下文体系,这个上下文体系的建立是由ContextLoder来完成的,其UML时序图如下图所示。 +IoC容器 的启动过程就是建立上下文的过程,该上下文是与 ServletContext 相伴而生的,同时也是 IoC容器 在 Web应用环境 中的具体表现之一。由 ContextLoaderListener 启动的上下文为根上下文。在根上下文的基础上,还有一个与 Web MVC 相关的上下文用来保存控制器(DispatcherServlet)需要的 MVC对象,作为根上下文的子上下文,构成一个层次化的上下文体系。在 Web容器 中启动 Spring应用程序 时,首先建立根上下文,然后建立这个上下文体系,这个上下文体系的建立是由 ContextLoder 来完成的,其 UML时序图 如下图所示。 ![avatar](/images/springMVC/Web容器启动spring应用程序过程图.png) -在web.xml中,已经配置了ContextLoaderListener,它是Spring提供的类,是为在Web容器中建立IoC容器服务的,它实现了ServletContextListener接口,这个接口是在Servlet API中定义的,提供了与Servlet生命周期结合的回调,比如上下文初始化contextInitialized()方法和上下文销毁contextDestroyed()方法。而在Web容器中,建立WebApplicationContext的过程,是在contextInitialized()方法中完成的。另外,ContextLoaderListener还继承了ContextLoader,具体的载入IoC容器的过程是由ContextLoader来完成的。 +在 web.xml 中,已经配置了 ContextLoaderListener,它是 Spring 提供的类,是为在 Web容器 中建立 IoC容器 服务的,它实现了 ServletContextListener接口,这个接口是在 Servlet API 中定义的,提供了与 Servlet生命周期 结合的回调,比如上下文初始化 contextInitialized()方法 和 上下文销毁 contextDestroyed()方法。而在 Web容器 中,建立 WebApplicationContext 的过程,是在 contextInitialized()方法 中完成的。另外,ContextLoaderListener 还继承了 ContextLoader,具体的载入 IoC容器 的过程是由 ContextLoader 来完成的。 -在ContextLoader中,完成了两个IoC容器建立的基本过程,一个是在Web容器中建立起双亲IoC容器,另一个是生成相应的WebApplicationContext并将其初始化。 +在 ContextLoader 中,完成了两个 IoC容器 建立的基本过程,一个是在 Web容器 中建立起 双亲IoC容器,另一个是生成相应的 WebApplicationContext 并将其初始化。 ## 3 Web容器中的上下文设计 -先从Web容器中的上下文入手,看看Web环境中的上下文设置有哪些特别之处,然后再 -到ContextLoaderListener中去了解整个容器启动的过程。为了方便在Web环境中使用IoC容器, -Spring为Web应用提供了上下文的扩展接口WebApplicationContext来满足启动过程的需要,其继承关系如下图所示。 +先从 Web容器 中的上下文入手,看看 Web环境 中的上下文设置有哪些特别之处,然后再到 ContextLoaderListener 中去了解整个容器启动的过程。为了方便在 Web环境 中使用 IoC容器, +Spring 为 Web应用 提供了上下文的扩展接口 WebApplicationContext 来满足启动过程的需要,其继承关系如下图所示。 ![avatar](/images/springMVC/WebApplicationContext接口的类继承关系.png) -在这个类继承关系中,可以从熟悉的XmlWebApplicationContext入手来了解它的接口实现。在接口设计中,最后是通过ApplicationContex接口与BeanFactory接口对接的,而对于具体的功能实现,很多都是封装在其基类AbstractRefreshableWebApplicationContext中完成的。 +在这个类继承关系中,可以从熟悉的 XmlWebApplicationContext 入手来了解它的接口实现。在接口设计中,最后是通过 ApplicationContex接口 与 BeanFactory接口 对接的,而对于具体的功能实现,很多都是封装在其基类 AbstractRefreshableWebApplicationContext 中完成的。 -同样,在源代码中,也可以分析出类似的继承关系,在WebApplicationContext中可以看到相关的常量设计,比如ROOT_ WEB_ APPLICATION_CONTEXT_ATTRIBUTE等,这个常量是用来索引在ServletContext中存储的根上下文的。这个接口类定义的接口方法比较简单,在这个接口中,定义了一 -个getServletContext方法,通过这个方法可以得到当前Web容器的Servlet上下文环境,通过 -这个方法,相当于提供了一个Web容器级别的全局环境。 +同样,在源代码中,也可以分析出类似的继承关系,在 WebApplicationContext 中可以看到相关的常量设计,比如 ROOT_ WEB_ APPLICATION_CONTEXT_ATTRIBUTE 等,这个常量是用来索引在 ServletContext 中存储的根上下文的。这个接口类定义的接口方法比较简单,在这个接口中,定义了一 +个 getServletContext()方法,通过这个方法可以得到当前 Web容器 的 Servlet上下文环境,通过 +这个方法,相当于提供了一个 Web容器级别的 全局环境。 ```java public interface WebApplicationContext extends ApplicationContext { - /** - * 该常量用于在ServletContext中存取根上下文 - */ - String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"; - - /** - * 对于WebApplicationContext来说,需要得到Web容器的ServletContext - */ - ServletContext getServletContext(); + /** + * 该常量用于在 ServletContext 中存取根上下文 + */ + String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"; + + /** + * 对于 WebApplicationContext 来说,需要得到 Web容器 的 ServletContext + */ + ServletContext getServletContext(); } ``` -在启动过程中,Spring会使用一个默认的WebApplicationContext实现作为IoC容器,这个默认使用的IoC容器就是XmlWebApplicationContext,它继承了ApplicationContext,在ApplicationContext的基础上,增加了对Web环境和XML配置定义的处理。在XmlWebApplicationContext的初始化过程中,Web容器中的IoC容器被建立起来,从而在Web容器中建立起整个Spring应用。与前面博文中分析的IoC容器的初始化一样,这个过程也有loadBeanDefinition对BeanDefinition的载入。在Web环境中,对定位BeanDefinition的Resource有特别的要求,这个要求的处理体现在对getDefaultConfigLocations方法的处理中。这里使用了默认的BeanDefinition的配置路径,这个路径在XmlWebApplicationContext中作为一个常量定义好了,即/WEB-INF/applicationContext.xml。 +在启动过程中,Spring 会使用一个默认的 WebApplicationContext 实现作为 IoC容器,这个默认使用的 IoC容器 就是 XmlWebApplicationContext,它继承了 ApplicationContext,在 ApplicationContext 的基础上,增加了对 Web环境 和 XML配置定义 的处理。在 XmlWebApplicationContext 的初始化过程中,Web容器 中的 IoC容器 被建立起来,从而在 Web容器 中建立起整个 Spring应用。与前面博文中分析的 IoC容器 的初始化一样,这个过程也有 loadBeanDefinition()方法 对 BeanDefinition 的载入。在 Web环境 中,对定位 BeanDefinition 的 Resource 有特别的要求,这个要求的处理体现在对 getDefaultConfigLocations()方法 的处理中。这里使用了默认的 BeanDefinition 的配置路径,这个路径在 XmlWebApplicationContext 中作为一个常量定义好了,即 /WEB-INF/applicationContext.xml。 ```java public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext { - /** 若不指定其它文件,spring默认从"/WEB-INF/applicationContext.xml"目录文件 初始化IoC容器 */ - public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; - - /** 默认的配置文件在 /WEB-INF/ 目录下 */ - public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; - - /** 默认的配置文件后缀名为.xml */ - public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; - - /** - * 此加载过程在 容器refresh()时启动 - */ - @Override - protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { - // 使用XmlBeanDefinitionReader对指定的BeanFactory进行解析 - XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); - - // 初始化beanDefinitionReader的属性,其中,设置ResourceLoader是因为 - // XmlBeanDefinitionReader是DefaultResource的子类,所有这里同样会使用 - // DefaultResourceLoader来定位BeanDefinition - beanDefinitionReader.setEnvironment(this.getEnvironment()); - beanDefinitionReader.setResourceLoader(this); - beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); - - // 该方法是一个空实现 - initBeanDefinitionReader(beanDefinitionReader); - // 使用初始化完成的beanDefinitionReader来加载BeanDefinitions - loadBeanDefinitions(beanDefinitionReader); - } - - protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { - } - - /** - * 获取所有的配置文件,然后一个一个载入BeanDefinition - */ - protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException { - String[] configLocations = getConfigLocations(); - if (configLocations != null) { - for (String configLocation : configLocations) { - reader.loadBeanDefinitions(configLocation); - } - } - } - - /** - * 获取默认路径"/WEB-INF/***.xml"下的配置文件, - * 或者获取"/WEB-INF/applicationContext.xml"配置文件 - */ - @Override - protected String[] getDefaultConfigLocations() { - if (getNamespace() != null) { - return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX}; - } - else { - return new String[] {DEFAULT_CONFIG_LOCATION}; - } - } + /** 若不指定其它文件,Spring 默认从 "/WEB-INF/applicationContext.xml" 目录文件 初始化 IoC容器 */ + public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; + + /** 默认的配置文件在 /WEB-INF/ 目录下 */ + public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; + + /** 默认的配置文件后缀名为 .xml */ + public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml"; + + /** + * 此加载过程在容器 refresh() 时启动 + */ + @Override + protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { + // 使用 XmlBeanDefinitionReader 对指定的 BeanFactory 进行解析 + XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); + + // 初始化 beanDefinitionReader 的属性,其中,设置 ResourceLoader 是因为 XmlBeanDefinitionReader + // 是 DefaultResource 的子类,所有这里同样会使用 DefaultResourceLoader 来定位 BeanDefinition + beanDefinitionReader.setEnvironment(this.getEnvironment()); + beanDefinitionReader.setResourceLoader(this); + beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); + + // 该方法是一个空实现 + initBeanDefinitionReader(beanDefinitionReader); + // 使用初始化完成的 beanDefinitionReader 来加载 BeanDefinitions + loadBeanDefinitions(beanDefinitionReader); + } + + protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { + } + + /** + * 获取所有的配置文件,然后一个一个载入 BeanDefinition + */ + protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException { + String[] configLocations = getConfigLocations(); + if (configLocations != null) { + for (String configLocation : configLocations) { + reader.loadBeanDefinitions(configLocation); + } + } + } + + /** + * 获取默认路径 "/WEB-INF/***.xml" 下的配置文件, + * 或者获取 "/WEB-INF/applicationContext.xml" 配置文件 + */ + @Override + protected String[] getDefaultConfigLocations() { + if (getNamespace() != null) { + return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX}; + } + else { + return new String[] {DEFAULT_CONFIG_LOCATION}; + } + } } ``` -从上面的代码中可以看到,在XmlWebApplicationContext中,基本的上下文功能都已经通过类的继承获得,这里需要处理的是,如何获取Bean定义信息,在这里,就转化为如何在Web容器环境中获得Bean定义信息。在获得Bean定义信息之后,后面的过程基本上就和前面分析的XmlFileSystemBeanFactory一样,是通过XmlBeanDefinitionReader来载人Bean定义信息的,最终完成整个上下文的初始化过程。 +从上面的代码中可以看到,在 XmlWebApplicationContext 中,基本的上下文功能都已经通过类的继承获得,这里需要处理的是,如何获取 BeanDefinition信息,在这里,就转化为如何在 Web容器环境 中获得 BeanDefinition信息。在获得 BeanDefinition信息 之后,后面的过程基本上就和前面分析的 XmlFileSystemBeanFactory 一样,是通过 XmlBeanDefinitionReader 来载入 BeanDefinition信息 的,最终完成整个上下文的初始化过程。 ## 4 ContextLoader的设计与实现 -对于Spring承载的Web应用而言,可以指定在Web应用程序启动时载入IoC容器(或者称为WebApplicationContext)。这个功能是由ContextLoaderListener来完成的,它是在Web容器中配置的监听器,会监听Web容器的启动,然后载入IoC容器。这个ContextLoaderListener通过使用ContextLoader来完成实际的WebApplicationContext,也就是IoC容器的初始化工作。这个ContextLoader就像Spring应用程序在Web容器中的启动器。这个启动过程是在Web容器中发生的,所以需要根据Web容器部署的要求来定义ContextLoader,相关的配置在概述中已经看到了,这里就不重复了。 +对于 Spring 承载的 Web应用 而言,可以指定在 Web应用程序 启动时载入 IoC容器(或者称为WebApplicationContext)。这个功能是由 ContextLoaderListener 来完成的,它是在 Web容器 中配置的监听器,会监听 Web容器 的启动,然后载入 IoC容器。这个 ContextLoaderListener 通过使用 ContextLoader 来完成实际的 WebApplicationContext,也就是 IoC容器 的初始化工作。这个 ContextLoader 就像 Spring应用程序 在 Web容器 中的启动器。这个启动过程是在 Web容器 中发生的,所以需要根据 Web容器 部署的要求来定义 ContextLoader,相关的配置在概述中已经看到了,这里就不重复了。 -为了了解IoC容器在Web容器中的启动原理,这里对启动器ContextLoaderListener的实现进行分析。**这个监听器是启动根IoC容器并把它载入到Web容器的主要功能模块,也是整个Spring Web应用加载IoC的第一个地方**。从加载过程可以看到,首先从Servlet事件中得到ServletContext,然后可以读取配置在web.xml中的各个相关的属性值,接着ContextLoader会实例化WebApplicationContext,并完成其载人和初始化过程。这个被初始化的第一个上下文,作为根上下文而存在,这个根上下文载入后,被绑定到Web应用程序的ServletContext上。任何需要访问根上下文的应用程序代码都可以从WebApplicationContextUtils类的静态方法中得到。 +为了了解 IoC容器 在 Web容器 中的启动原理,这里对 启动器ContextLoaderListener 的实现进行分析。**这个监听器是启动 根IoC容器 并把它载入到 Web容器 的主要功能模块,也是整个 Spring Web应用 加载 IoC 的第一个地方**。从加载过程可以看到,首先从 Servlet事件 中得到 ServletContext,然后可以读取配置在 web.xml 中的各个相关的属性值,接着 ContextLoader 会实例化 WebApplicationContext,并完成其载人和初始化过程。这个被初始化的第一个上下文,作为根上下文而存在,这个根上下文载入后,被绑定到 Web应用程序 的 ServletContext 上。任何需要访问根上下文的应用程序代码都可以从 WebApplicationContextUtils类 的静态方法中得到。 -下面分析具体的根上下文的载人过程。在ContextLoaderListener中,实现的是**ServletContextListener接口,这个接口里的函数会结合Web容器的生命周期被调用**。因为ServletContextListener是ServletContext的监听者,如果ServletContext发生变化,会触发出相应的事件,而监听器一直在对这些事件进行监听,如果接收到了监听的事件,就会做出预先设计好的响应动作。由于ServletContext的变化而触发的监听器的响应具体包括:在服务器启动时,ServletContext被创建的时候,服务器关闭时,ServletContext将被销毁的时候等。对应这些事件及Web容器状态的变化,在监听器中定义了对应的事件响应的回调方法。比如,在服务器启动时,ServletContextListener的contextInitialized()方法被调用,服务器将要关闭时,ServletContextListener的contextDestroyed()方法被调用。了解了Web容器中监听器的工作原理,下面看看服务器启动时 ContextLoaderListener的调用完成了什么。在这个初始化回调中,创建了ContextLoader,同时会利用创建出来的ContextLoader来完成IoC容器的初始化。 +下面分析具体的根上下文的载人过程。在 ContextLoaderListener 中,实现的是 **ServletContextListener接口,这个接口里的函数会结合 Web容器 的生命周期被调用**。因为 ServletContextListener 是 ServletContext 的监听者,如果 ServletContext 发生变化,会触发出相应的事件,而监听器一直在对这些事件进行监听,如果接收到了监听的事件,就会做出预先设计好的响应动作。由于 ServletContext 的变化而触发的监听器的响应具体包括:在服务器启动时,ServletContext 被创建的时候,服务器关闭时,ServletContext 将被销毁的时候等。对应这些事件及 Web容器状态 的变化,在监听器中定义了对应的事件响应的回调方法。比如,在服务器启动时,ServletContextListener 的 contextInitialized()方法 被调用,服务器将要关闭时,ServletContextListener 的 contextDestroyed()方法 被调用。了解了 Web容器 中监听器的工作原理,下面看看服务器启动时 ContextLoaderListener 的调用完成了什么。在这个初始化回调中,创建了 ContextLoader,同时会利用创建出来的 ContextLoader 来完成 IoC容器 的初始化。 ```java public class ContextLoaderListener extends ContextLoader implements ServletContextListener { - private ContextLoader contextLoader; - - /** - * 启动web应用的 根上下文 - */ - public void contextInitialized(ServletContextEvent event) { - // 由于本类直接继承了ContextLoader,所以能直接使用ContextLoader来初始化IoC容器 - this.contextLoader = createContextLoader(); - if (this.contextLoader == null) { - this.contextLoader = this; - } - // 具体的初始化工作交给ContextLoader完成 - this.contextLoader.initWebApplicationContext(event.getServletContext()); - } + private ContextLoader contextLoader; + + /** + * 启动 web应用 的根上下文 + */ + public void contextInitialized(ServletContextEvent event) { + // 由于本类直接继承了 ContextLoader,所以能直接使用 ContextLoader 来初始化 IoC容器 + this.contextLoader = createContextLoader(); + if (this.contextLoader == null) { + this.contextLoader = this; + } + // 具体的初始化工作交给 ContextLoader 完成 + this.contextLoader.initWebApplicationContext(event.getServletContext()); + } } public class ContextLoader { - public static final String CONTEXT_CLASS_PARAM = "contextClass"; - - public static final String CONTEXT_ID_PARAM = "contextId"; - - public static final String CONTEXT_INITIALIZER_CLASSES_PARAM = "contextInitializerClasses"; - - public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation"; - - public static final String LOCATOR_FACTORY_SELECTOR_PARAM = "locatorFactorySelector"; - - public static final String LOCATOR_FACTORY_KEY_PARAM = "parentContextKey"; - - private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties"; - - private static final Properties defaultStrategies; - - static { - // Load default strategy implementations from properties file. - // This is currently strictly internal and not meant to be customized - // by application developers. - try { - ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class); - defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); - } - catch (IOException ex) { - throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage()); - } - } - - /** - * 由ContextLoader完成根上下文在Web容器中的创建。这个根上下文是作为Web容器中唯一的实例而存在的, - * 根上下文创建成功后 会被存到Web容器的ServletContext中,供需要时使用。存取这个根上下文的路径是由 - * Spring预先设置好的,在WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE中进行了定义 - */ - public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { - // 如果ServletContext中已经包含了根上下文,则抛出异常 - if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { - throw new IllegalStateException( - "Cannot initialize context because there is already a root application context present - " + - "check whether you have multiple ContextLoader* definitions in your web.xml!"); - } - Log logger = LogFactory.getLog(ContextLoader.class); - servletContext.log("Initializing Spring root WebApplicationContext"); - if (logger.isInfoEnabled()) { - logger.info("Root WebApplicationContext: initialization started"); - } - long startTime = System.currentTimeMillis(); - - try { - if (this.context == null) { - // 这里创建在ServletContext中存储的根上下文 - this.context = createWebApplicationContext(servletContext); - } - if (this.context instanceof ConfigurableWebApplicationContext) { - ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; - if (!cwac.isActive()) { - if (cwac.getParent() == null) { - // 载入根上下文的 双亲上下文 - ApplicationContext parent = loadParentContext(servletContext); - cwac.setParent(parent); - } - // 配置 并且初始化IoC容器,看到Refresh应该能想到AbstractApplicationContext - // 中的refresh()方法,猜到它是前面介绍的IoC容器的初始化入口 - configureAndRefreshWebApplicationContext(cwac, servletContext); - } - } - // 将上面创建的WebApplicationContext实例 存到ServletContext中,注意同时被存入的常量 - // ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,以后的应用都会根据这个属性获取根上下文 - servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); - - ClassLoader ccl = Thread.currentThread().getContextClassLoader(); - if (ccl == ContextLoader.class.getClassLoader()) { - currentContext = this.context; - } - else if (ccl != null) { - currentContextPerThread.put(ccl, this.context); - } - - if (logger.isDebugEnabled()) { - logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + - WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); - } - if (logger.isInfoEnabled()) { - long elapsedTime = System.currentTimeMillis() - startTime; - logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); - } - - return this.context; - } - catch (RuntimeException ex) { - logger.error("Context initialization failed", ex); - servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); - throw ex; - } - catch (Error err) { - logger.error("Context initialization failed", err); - servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); - throw err; - } - } - - /** - * 创建WebApplicationContext的实例化对象 - */ - protected WebApplicationContext createWebApplicationContext(ServletContext sc) { - // 判断使用什么样的类在Web容器中作为IoC容器 - Class contextClass = determineContextClass(sc); - if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { - throw new ApplicationContextException("Custom context class [" + contextClass.getName() + - "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); - } - // 直接实例化需要产生的IoC容器 - return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); - } - - /** - * 在确定使用何种IoC容器的过程中可以看到,应用可以在部署描述符中指定使用什么样的IoC容器, - * 这个指定操作是通过CONTEXT_ CLASS_ PARAM参数的设置完成的。如果没有指定特定的IoC容器, - * 将使用默认的IoC容器,也就是XmlWebApplicationContext对象作为在Web环境中使用的IoC容器。 - */ - protected Class determineContextClass(ServletContext servletContext) { - // 获取servletContext中对CONTEXT_CLASS_PARAM(contextClass)参数的配置 - String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); - if (contextClassName != null) { - try { - // 获取配置的contextClassName对应的clazz对象 - return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader()); - } - catch (ClassNotFoundException ex) { - throw new ApplicationContextException( - "Failed to load custom context class [" + contextClassName + "]", ex); - } - } - else { - // 如果没有配置CONTEXT_CLASS_PARAM,则使用默认的ContextClass - contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); - try { - return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); - } - catch (ClassNotFoundException ex) { - throw new ApplicationContextException( - "Failed to load default context class [" + contextClassName + "]", ex); - } - } - } - - protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { - if (ObjectUtils.identityToString(wac).equals(wac.getId())) { - // The application context id is still set to its original default value - // -> assign a more useful id based on available information - String idParam = sc.getInitParameter(CONTEXT_ID_PARAM); - if (idParam != null) { - wac.setId(idParam); - } - else { - // Generate default id... - if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) { - // Servlet <= 2.4: resort to name specified in web.xml, if any. - wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + - ObjectUtils.getDisplayString(sc.getServletContextName())); - } - else { - wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + - ObjectUtils.getDisplayString(sc.getContextPath())); - } - } - } - - // 设置ServletContext 及配置文件的位置参数 - wac.setServletContext(sc); - String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM); - if (initParameter != null) { - wac.setConfigLocation(initParameter); - } - customizeContext(sc, wac); - // IoC容器初始化的入口,想不起来的把前面IoC容器初始化的博文再读10遍 - wac.refresh(); - } + public static final String CONTEXT_CLASS_PARAM = "contextClass"; + + public static final String CONTEXT_ID_PARAM = "contextId"; + + public static final String CONTEXT_INITIALIZER_CLASSES_PARAM = "contextInitializerClasses"; + + public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation"; + + public static final String LOCATOR_FACTORY_SELECTOR_PARAM = "locatorFactorySelector"; + + public static final String LOCATOR_FACTORY_KEY_PARAM = "parentContextKey"; + + private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties"; + + private static final Properties defaultStrategies; + + static { + // Load default strategy implementations from properties file. + // This is currently strictly internal and not meant to be customized + // by application developers. + try { + ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class); + defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); + } + catch (IOException ex) { + throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage()); + } + } + + /** + * 由 ContextLoader 完成根上下文在 Web容器 中的创建。这个根上下文是作为 Web容器 中唯一的实例而存在的, + * 根上下文创建成功后会被存到 Web容器 的 ServletContext 中,供需要时使用。存取这个根上下文的路径是由 + * Spring 预先设置好的,在 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 中进行了定义 + */ + public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { + // 如果 ServletContext 中已经包含了根上下文,则抛出异常 + if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { + throw new IllegalStateException( + "Cannot initialize context because there is already a root application context present - " + + "check whether you have multiple ContextLoader* definitions in your web.xml!"); + } + Log logger = LogFactory.getLog(ContextLoader.class); + servletContext.log("Initializing Spring root WebApplicationContext"); + if (logger.isInfoEnabled()) { + logger.info("Root WebApplicationContext: initialization started"); + } + long startTime = System.currentTimeMillis(); + + try { + if (this.context == null) { + // 这里创建在 ServletContext 中存储的根上下文 + this.context = createWebApplicationContext(servletContext); + } + if (this.context instanceof ConfigurableWebApplicationContext) { + ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; + if (!cwac.isActive()) { + if (cwac.getParent() == null) { + // 载入根上下文的 双亲上下文 + ApplicationContext parent = loadParentContext(servletContext); + cwac.setParent(parent); + } + // 配置并初始化 IoC容器,看到下面方法中的 Refresh单词 应该能想到 + // AbstractApplicationContext 中的 refresh()方法,猜到它是前面介绍的 IoC容器 的初始化入口 + configureAndRefreshWebApplicationContext(cwac, servletContext); + } + } + // 将上面创建的 WebApplicationContext实例 存到 ServletContext 中,注意同时被存入的常量 + // ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,以后的应用都会根据这个属性获取根上下文 + servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); + + ClassLoader ccl = Thread.currentThread().getContextClassLoader(); + if (ccl == ContextLoader.class.getClassLoader()) { + currentContext = this.context; + } + else if (ccl != null) { + currentContextPerThread.put(ccl, this.context); + } + + if (logger.isDebugEnabled()) { + logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); + } + if (logger.isInfoEnabled()) { + long elapsedTime = System.currentTimeMillis() - startTime; + logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); + } + + return this.context; + } + catch (RuntimeException ex) { + logger.error("Context initialization failed", ex); + servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); + throw ex; + } + catch (Error err) { + logger.error("Context initialization failed", err); + servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); + throw err; + } + } + + /** + * 创建 WebApplicationContext 的实例化对象 + */ + protected WebApplicationContext createWebApplicationContext(ServletContext sc) { + // 判断使用什么样的类在 Web容器 中作为 IoC容器 + Class contextClass = determineContextClass(sc); + if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { + throw new ApplicationContextException("Custom context class [" + contextClass.getName() + + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); + } + // 直接实例化需要产生的 IoC容器 + return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); + } + + /** + * 在确定使用何种 IoC容器 的过程中可以看到,应用可以在部署描述符中指定使用什么样的 IoC容器, + * 这个指定操作是通过 CONTEXT_ CLASS_ PARAM参数 的设置完成的。如果没有指定特定的 IoC容器, + * 将使用默认的 IoC容器,也就是 XmlWebApplicationContext对象 作为在 Web环境 中使用的 IoC容器。 + */ + protected Class determineContextClass(ServletContext servletContext) { + // 获取 servletContext 中对 CONTEXT_CLASS_PARAM(contextClass)参数 的配置 + String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); + if (contextClassName != null) { + try { + // 获取配置的 contextClassName 对应的 clazz对象 + return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader()); + } + catch (ClassNotFoundException ex) { + throw new ApplicationContextException( + "Failed to load custom context class [" + contextClassName + "]", ex); + } + } + else { + // 如果没有配置 CONTEXT_CLASS_PARAM,则使用默认的 ContextClass + contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); + try { + return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); + } + catch (ClassNotFoundException ex) { + throw new ApplicationContextException( + "Failed to load default context class [" + contextClassName + "]", ex); + } + } + } + + protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { + if (ObjectUtils.identityToString(wac).equals(wac.getId())) { + // The application context id is still set to its original default value + // -> assign a more useful id based on available information + String idParam = sc.getInitParameter(CONTEXT_ID_PARAM); + if (idParam != null) { + wac.setId(idParam); + } + else { + // Generate default id... + if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) { + // Servlet <= 2.4: resort to name specified in web.xml, if any. + wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + + ObjectUtils.getDisplayString(sc.getServletContextName())); + } + else { + wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + + ObjectUtils.getDisplayString(sc.getContextPath())); + } + } + } + + // 设置 ServletContext 及配置文件的位置参数 + wac.setServletContext(sc); + String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM); + if (initParameter != null) { + wac.setConfigLocation(initParameter); + } + customizeContext(sc, wac); + // IoC容器 初始化的入口,想不起来的把前面 IoC容器 初始化的博文再读10遍 + wac.refresh(); + } } ``` -这就是IoC容器在Web容器中的启动过程,与 应用中启动IoC容器的方式相类似,所不同的是这里需要考虑Web容器的环境特点,比如各种参数的设置,IoC容器与Web容器ServletContext的结合等。在初始化这个上下文以后,该上下文会被存储到SevletContext中,这样就建立了一个全局的关于整个应用的上下文。同时,在启动Spring MVC时,我们还会看到这个上下文被以后的DispatcherServlet在进行自己持有的上下文的初始化时,设置为DispatcherServlet自带的上下文的双亲上下文。 \ No newline at end of file +这就是 IoC容器 在 Web容器 中的启动过程,与应用中启动 IoC容器 的方式相类似,所不同的是这里需要考虑 Web容器 的环境特点,比如各种参数的设置,IoC容器 与 Web容器 ServletContext 的结合等。在初始化这个上下文以后,该上下文会被存储到 SevletContext 中,这样就建立了一个全局的关于整个应用的上下文。同时,在启动 SpringMVC 时,我们还会看到这个上下文被以后的 DispatcherServlet 在进行自己持有的上下文的初始化时,设置为 DispatcherServlet 自带的上下文的双亲上下文。 \ No newline at end of file diff --git a/docs/Spring/SpringMVC/SpringMVC的设计与实现.md b/docs/Spring/SpringMVC/SpringMVC的设计与实现.md index c976464..cf27340 100644 --- a/docs/Spring/SpringMVC/SpringMVC的设计与实现.md +++ b/docs/Spring/SpringMVC/SpringMVC的设计与实现.md @@ -1,35 +1,36 @@ ## 1 SpringMVC应用场景 -在使用SpringMVC时,除了要在web.xml中配置ContextLoaderListener外,还要对DispatcherServlet进行配置。作为一个Servlet,这个DispatcherServlet实现的是Sun的J2EE核心模式中的前端控制器模式(Front Controller), 作为一个前端控制器,所有的Web请求都需要通过它来处理,进行转发、匹配、数据处理后,并转由页面进行展现,因此这个DispatcerServlet可以看成是Spring MVC实现中最为核心的部分。 +在使用 SpringMVC 时,除了要在 web.xml 中配置 ContextLoaderListener 外,还要对 DispatcherServlet 进行配置。作为一个 Servlet,这个 DispatcherServlet 实现的是 Sun 的 J2EE核心模式 中的 前端控制器模式(Front Controller), 作为一个前端控制器,所有的 Web请求 都需要通过它来进行转发、匹配、数据处理,然后转由页面进行展现,因此这个 DispatcerServlet 可以看成是 SpringMVC实现 中最为核心的部分。 -在Spring MVC中,对于不同的Web请求的映射需求,Spring MVC提供了不同的HandlerMapping的实现,可以让应用开发选取不同的映射策略。DispatcherSevlet默认了BeanNameUrlHandlerMapping作为映射策略实现。除了映射策略可以定制外,Spring MVC提供了各种Controller的实现来供应用扩展和使用,以应对不同的控制器使用场景,这些Controller控制器需要实现handleRequest接口方法,并返回ModelAndView对象。Spring MVC还提供了各种视图实现,比如常用的JSP视图。除此之外,Spring MVC还提供了拦截器供应用使用,允许应用对Web请求进行拦截,以及前置处理和后置处理。 +在 SpringMVC 中,对于不同的 Web请求 的映射需求,SpringMVC 提供了不同的 HandlerMapping 的实现,可以让应用开发选取不同的映射策略。DispatcherSevlet 默认了 BeanNameUrlHandlerMapping 作为映射策略实现。除了映射策略可以定制外,SpringMVC 还提供了各种 Controller 的实现来供应用扩展和使用,以应对不同的控制器使用场景,这些 Controller控制器 需要实现 handleRequest()接口方法,并返回 ModelAndView对象。SpringMVC 还提供了各种视图实现,比如常用的 JSP视图。除此之外,SpringMVC 还提供了拦截器供应用使用,允许应用对 Web请求 进行拦截,以及前置处理和后置处理。 ## 2 SpringMVC设计概览 -在完成对ContextLoaderListener的初始化以后,Web容器开始初始化DispatcherServlet,这个初始化的启动与在web.xml中对载入次序的定义有关。DispatcherServlet会建立自己的上下文来持有Spring MVC的Bean对象,在建立这个自己持有的IoC容器时,会**从ServletContext中得到根上下文**作为DispatcherServlet持有上下文的双亲上下文。有了这个根上下文,再对自己持有的上下文进行初始化,最后把自己持有的这个上下文保存到ServletContext中,供以后检索和使用。 +在完成对 ContextLoaderListener 的初始化以后,Web容器 开始初始化 DispatcherServlet,这个初始化的启动与在 web.xml 中对载入次序的定义有关。DispatcherServlet 会建立自己的上下文来持有SpringMVC 的 Bean对象,在建立这个自己持有的 IoC容器 时,会**从 ServletContext 中得到根上下文**作为 DispatcherServlet 持有上下文的双亲上下文。有了这个根上下文,再对自己持有的上下文进行初始化,最后把自己持有的这个上下文保存到 ServletContext 中,供以后检索和使用。 -为了解这个过程,可以从DispatcherServlet的父类FrameworkServlet的代码入手,去探寻DispatcherServlet的启动过程,它同时也是SpringMVC的启动过程。ApplicationContext的创建过程和ContextLoader创建根上下文的过程有许多类似的地方。下面来看一下这个DispatcherServlet类的继承关系。 +为了解这个过程,可以从 DispatcherServlet 的父类 FrameworkServlet 的代码入手,去探寻 DispatcherServlet 的启动过程,它同时也是 SpringMVC 的启动过程。ApplicationContext 的创建过程和 ContextLoader 创建根上下文的过程有许多类似的地方。下面来看一下这个 DispatcherServlet类 的继承关系。 ![avatar](/images/springMVC/DispatcherServlet的继承关系.png) -DispatcherServlet通过继承FrameworkServlet和HttpServletBean而继承了HttpServlet,通过使用Servlet API来对HTTP请求进行响应,成为Spring MVC的前端处理器,同时成为MVC模块与Web容器集成的处理前端。 +DispatcherServlet 通过继承 FrameworkServlet 和 HttpServletBean 而继承了 HttpServlet,通过使用Servlet API 来对 HTTP请求 进行响应,成为 SpringMVC 的前端处理器,同时成为 MVC模块 与 Web容器 集成的处理前端。 -DispatcherServlet的工作大致可以分为两个部分:一个是初始化部分,由initServletBean()启动,通过initWebApplicationContext()方法最终调用DispatcherServlet的initStrategies()方法,在这个方法里,DispatcherServlet对MVC模块的其他部分进行了初始化,比如handlerMapping、ViewResolver等;另一个是对HTTP请求进行响应,作为一个Servlet,Web容器会调用Servlet的doGet()和doPost()方法,在经过FrameworkServlet的processRequest()简单处理后,会调用DispatcherServlet的doService()方法,在这个方法调用中封装了doDispatch(),这个doDispatch()是Dispatcher实现MVC模式的主要部分,下图为DispatcherServlet的处理过程时序图。 +DispatcherServlet 的工作大致可以分为两个部分:一个是初始化部分,由 initServletBean()方法 启动,通过 initWebApplicationContext()方法 最终调用 DispatcherServlet 的 initStrategies()方法,在这个方法里,DispatcherServlet 对 MVC模块 的其他部分进行了初始化,比如 handlerMapping、ViewResolver 等;另一个是对 HTTP请求 进行响应,作为一个 Servlet,Web容器 会调用 Servlet 的doGet() 和 doPost()方法,在经过 FrameworkServlet 的 processRequest() 简单处理后,会调用 DispatcherServlet 的 doService()方法,在这个方法调用中封装了 doDispatch(),这个 doDispatch() 是 Dispatcher 实现 MVC模式 的主要部分,下图为 DispatcherServlet 的处理过程时序图。 ![avatar](/images/springMVC/DispatcherServlet的处理过程.png) ## 3 DispatcherServlet的启动和初始化 -前面大致描述了Spring MVC的工作流程,下面看一下DispatcherServlet的启动和初始化的代码设计及实现。 +前面大致描述了 SpringMVC 的工作流程,下面看一下 DispatcherServlet 的启动和初始化的代码设计及实现。 -作为Servlet,DispatcherServlet的启动与Servlet的启动过程是相联系的。在Servlet的初始化过程中,Servlet的init()方法会被调用,以进行初始化,DispatcherServlet的基类HttpServletBean实现了该方法。在初始化开始时,需要读取配置在ServletContext中的Bean属性参数,这些属性参数设置在web.xml的Web容器初始化参数中。使用编程式的方式来设置这些Bean属性,在这里可以看到对PropertyValues和BeanWrapper的使用。对于这些和依赖注人相关的类的使用,在分析IoC容器的初始化时,尤其是在依赖注入实现分析时,有过“亲密接触”。只是这里的依赖注人是与Web容器初始化相关的。 +作为 Servlet,DispatcherServlet 的启动与 Servlet 的启动过程是相联系的。在 Servlet 的初始化过程中,Servlet 的 init()方法 会被调用,以进行初始化,DispatcherServlet 的基类 HttpServletBean 实现了该方法。在初始化开始时,需要读取配置在 ServletContext 中的 Bean属性参数,这些属性参数设置在 web.xml 的 Web容器初始化参数 中。使用编程式的方式来设置这些 Bean属性,在这里可以看到对 PropertyValues 和 BeanWrapper 的使用。对于这些和依赖注人相关的类的使用,在分析 IoC容器 的初始化时,尤其是在依赖注入实现分析时,有过“亲密接触”。只是这里的依赖注人是与 Web容器 初始化相关的。 -接着会执行DispatcherServlet持有的IoC容器的初始化过程,在这个初始化过程中,一个新的上下文被建立起来,这个DispatcherServlet持有的上下文被设置为根上下文的子上下文。一个Web应用中可以容纳多个Servlet存在;与此相对应,对于应用在Web容器中的上下体系,一个根上下文可以作为许多Servlet上下文的双亲上下文。了解IoC工作原理的读者知道,在向IoC容器getBean()时,IoC容器会首先向其双亲上下文去getBean(),也就是说,在根上下文中定义的Bean是可以被各个Servlet持有的上下文得到和共享的。DispatcherServlet持有的 上下文被建立起来以后,也需要和其他IoC容器一样完成初始化,这个初始化也是通过refresh()方法来完成的。最后,DispatcherServlet给这个自己持有的上下文命名,并把它设置到Web容器的上下文中,这个名称和在web.xml中设置的DispatcherServlet的Servlet名称有关,从而保证了这个上下文在Web环境上下文体系中的唯一性。 +接着会执行 DispatcherServlet 持有的 IoC容器 的初始化过程,在这个初始化过程中,一个新的上下文被建立起来,这个 DispatcherServlet 持有的上下文被设置为根上下文的子上下文。一个 Web应用 中可以容纳多个 Servlet 存在;与此相对应,对于应用在 Web容器 中的上下体系,一个根上下文可以作为许多 Servlet上下文 的双亲上下文。了解 IoC 工作原理的读者知道,在向 IoC容器 getBean() 时,IoC容器 会首先向其双亲上下文去 getBean(),也就是说,在根上下文中定义的 Bean 是可以被各个 Servlet 持有的上下文得到和共享的。DispatcherServlet 持有的 上下文被建立起来以后,也需要和其他 IoC容器 一样完成初始化,这个初始化也是通过 refresh()方法 来完成的。最后,DispatcherServlet 给这个自己持有的上下文命名,并把它设置到 Web容器 的上下文中,这个名称和在 web.xml 中设置的 DispatcherServlet 的 Servlet名称 有关,从而保证了这个上下文在 Web环境上下文体系 中的唯一性。 ```java public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware { + public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); } - // 获取Servlet的初始化参数,对bean属性进行配置 + // 获取 Servlet 的初始化参数,对 bean属性 进行配置 try { PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); @@ -54,10 +55,11 @@ public abstract class HttpServletBean extends HttpServlet implements Environment public abstract class FrameworkServlet extends HttpServletBean { - /** 此servlet的WebApplicationContext */ + + /** 此 servlet 的 WebApplicationContext */ private WebApplicationContext webApplicationContext; - /** 我们是否应该将当前Servlet的上下文webApplicationContext设为ServletContext的属性 */ + /** 我们是否应该将当前 Servlet 的上下文 webApplicationContext 设为 ServletContext 的属性 */ private boolean publishContext = true; public FrameworkServlet() { @@ -68,7 +70,7 @@ public abstract class FrameworkServlet extends HttpServletBean { } /** - * 覆盖了父类HttpServletBean的空实现 + * 覆盖了父类 HttpServletBean 的空实现 */ @Override protected final void initServletBean() throws ServletException { @@ -100,16 +102,16 @@ public abstract class FrameworkServlet extends HttpServletBean { } /** - * 为这个Servlet初始化一个公共的WebApplicationContext实例 + * 为这个 Servlet 初始化一个公共的 WebApplicationContext实例 */ protected WebApplicationContext initWebApplicationContext() { - // 获取 根上下文 作为当前MVC上下文的双亲上下文,这个根上下文保存在ServletContext中 + // 获取根上下文作为当前 MVC上下文 的双亲上下文,这个根上下文保存在 ServletContext 中 WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; if (this.webApplicationContext != null) { - // 可以在本对象被构造时注入一个webApplicationContext实例 + // 可以在本对象被构造时注入一个 webApplicationContext实例 wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; @@ -126,24 +128,24 @@ public abstract class FrameworkServlet extends HttpServletBean { } if (wac == null) { // 在本对象被构造时没有注入上下文实例 -> - // 查看是否已在servlet上下文中注册了上下文实例。 + // 查看是否已在 servlet上下文 中注册了上下文实例。 // 如果存在一个,则假定父上下文(如果有的话)已经被设置, // 并且用户已经执行了任何初始化,例如设置上下文ID wac = findWebApplicationContext(); } if (wac == null) { - // 没有为此servlet定义上下文实例 -> 创建本地实例 + // 没有为此 servlet 定义上下文实例 -> 创建本地实例 wac = createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { - // 上下文 不是支持刷新的ConfigurableApplicationContext,或者 - // 在构造时注入的上下文已经完成刷新 -> 在此处手动触发onRefresh()方法 + // 上下文不是支持刷新的 ConfigurableApplicationContext,或者 + // 在构造时注入的上下文已经完成刷新 -> 在此处手动触发 onRefresh()方法 onRefresh(wac); } if (this.publishContext) { - // 把当前建立的上下文保存到ServletContext中,使用的属性名是和当前servlet名相关的 + // 把当前建立的上下文保存到 ServletContext 中,使用的属性名是和 当前servlet名 相关的 String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { @@ -156,7 +158,7 @@ public abstract class FrameworkServlet extends HttpServletBean { } } ``` -至此,这个MVC的上下文就建立起来了,具体取得根上下文的过程在WebApplicationContextUtils中实现。这个根上下文是ContextLoader设置到ServletContext中去的,使用的属性是ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,ContextLoader还对这个IoC容器的Bean配置文件进行了设置,默认的位置是在/WEB-INF/applicationContext.xml文件中。由于这个根上下文是DispatcherServlet建立的上下文的 双亲上下文,所以根上下文中管理的Bean也可以被DispatcherServlet的上下文使用。通过getBean()向IoC容器获取Bean时,容器会先到它的双亲IoC容器中获取。 +至此,这个 MVC 的上下文就建立起来了,具体取得根上下文的过程在 WebApplicationContextUtils 中实现。这个根上下文是 ContextLoader 设置到 ServletContext 中去的,使用的属性是 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,ContextLoader 还对这个 IoC容器 的 Bean 配置文件进行了设置,默认的位置是在 /WEB-INF/applicationContext.xml文件 中。由于这个根上下文是 DispatcherServlet 建立的上下文的 双亲上下文,所以根上下文中管理的 Bean 也可以被 DispatcherServlet 的上下文使用。通过 getBean() 向 IoC容器 获取 Bean 时,容器会先到它的 双亲IoC容器 中获取。 ```java /** * 这是一个封装了很多静态方法的抽象工具类,所以只能调用其静态方法, @@ -164,8 +166,8 @@ public abstract class FrameworkServlet extends HttpServletBean { */ public abstract class WebApplicationContextUtils { /** - * 使用了WebApplicationContext的ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE属性,获取 - * ServletContext中的根上下文,这个属性代表的根上下文在ContextLoaderListener初始化的 + * 使用了 WebApplicationContext 的 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE属性,获取 + * ServletContext 中的根上下文,这个属性代表的根上下文在 ContextLoaderListener 初始化的 * 过程中被建立 */ public static WebApplicationContext getWebApplicationContext(ServletContext sc) { @@ -173,7 +175,7 @@ public abstract class WebApplicationContextUtils { } /** - * 查找此web应用程序的自定义WebApplicationContext + * 查找此 web应用程序 的自定义 WebApplicationContext */ public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) { Assert.notNull(sc, "ServletContext must not be null"); @@ -197,20 +199,20 @@ public abstract class WebApplicationContextUtils { } ) ``` -回到FrameworkServlet的实现中来看一下,DispatcherServlet的上下文是怎样建立的,这个建立过程与前面建立根上下文的过程非常类似。建立DispatcherServlet的上下文,需要把根上下文作为参数传递给它。然后使用反射技术来实例化上下文对象,并为它设置参数。根据默认的配置,这个上下文对象也是XmlWebApplicationContext对象,这个类型是在DEFAULT_CONTEXT_CLASS参数中设置好并允许BeanUtilis使用的。在实例化结束后,需要为这个上下文对象设置好一些基本的配置,这些配置包括它的双亲上下文、Bean配置文件的位置等。完成这些配置以后,最后通过调用IoC容器的refresh()方法来完成IoC容器的最终初始化,这和前面我们对IoC容器实现原理的分析中所看到的IoC容器初始化的过程是一致的。 +回到 FrameworkServlet 的实现中来看一下,DispatcherServlet 的上下文是怎样建立的,这个建立过程与前面建立根上下文的过程非常类似。建立 DispatcherServlet 的上下文,需要把根上下文作为参数传递给它。然后使用反射技术来实例化上下文对象,并为它设置参数。根据默认的配置,这个上下文对象也是 XmlWebApplicationContext对象,这个类型是在 DEFAULT_CONTEXT_CLASS参数 中设置好并允许 BeanUtilis 使用的。在实例化结束后,需要为这个上下文对象设置好一些基本的配置,这些配置包括它的双亲上下文、Bean配置文件 的位置等。完成这些配置以后,最后通过调用 IoC容器 的 refresh()方法 来完成 IoC容器 的最终初始化,这和前面我们对 IoC容器实现原理 的分析中所看到的 IoC容器初始化 的过程是一致的。 ```java public abstract class FrameworkServlet extends HttpServletBean { /** - * 为此servlet实例化一个WebApplicationContext,可以是默认的XmlWebApplicationContext, - * 也可以是用户设置的自定义Context上下文 + * 为此 servlet 实例化一个 WebApplicationContext,可以是默认的 XmlWebApplicationContext, + * 也可以是用户设置的自定义 Context上下文 */ protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { return createWebApplicationContext((ApplicationContext) parent); } protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) { - // 默认为XmlWebApplicationContext.class + // 默认为 XmlWebApplicationContext.class Class contextClass = getContextClass(); if (this.logger.isDebugEnabled()) { this.logger.debug("Servlet with name '" + getServletName() + @@ -228,11 +230,11 @@ public abstract class FrameworkServlet extends HttpServletBean { (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); - // 这里设置的 双亲上下文,就是在ContextLoader中建立的根上下文 + // 这里设置的 双亲上下文,就是在 ContextLoader 中建立的根上下文 wac.setParent(parent); wac.setConfigLocation(getContextConfigLocation()); - // 配置并且刷新wac + // 配置并且刷新 WebApplicationContext对象 configureAndRefreshWebApplicationContext(wac); return wac; @@ -240,15 +242,15 @@ public abstract class FrameworkServlet extends HttpServletBean { protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) { - // 应用程序上下文id仍设置为其原始默认值,如果该id不为空的话 + // 应用程序上下文id 仍设置为其原始默认值,如果该 id 不为空的话 if (this.contextId != null) { wac.setId(this.contextId); } else { - // 生成默认的id + // 生成默认的 id ServletContext sc = getServletContext(); if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) { - // 当Servlet<=2.4:如果有,请使用web.xml中指定的名称。 + // 当 Servlet <= 2.4:如果有,请使用 web.xml 中指定的名称。 String servletContextName = sc.getServletContextName(); if (servletContextName != null) { wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + servletContextName + @@ -259,7 +261,7 @@ public abstract class FrameworkServlet extends HttpServletBean { } } else { - // Servlet 2.5的getContextPath可用! + // Servlet 2.5 的 getContextPath 可用! wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()) + "/" + getServletName()); } @@ -272,8 +274,8 @@ public abstract class FrameworkServlet extends HttpServletBean { wac.setNamespace(getNamespace()); wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); - // 在刷新上下文的任何情况下,都将会调用wac环境的initPropertySources()方法。 - // 在此处执行此方法,以确保在刷新上下文之前,servlet属性源已准备就绪 + // 在刷新上下文的任何情况下,都将会调用 此wac 的 env的 initPropertySources()方法。 + // 在此处执行此方法,以确保在刷新上下文之前,servlet属性源 已准备就绪 ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment)env).initPropertySources(getServletContext(), getServletConfig()); @@ -283,20 +285,20 @@ public abstract class FrameworkServlet extends HttpServletBean { applyInitializers(wac); - // IoC容器都是通过该方法完成 容器初始化的 + // IoC容器 都是通过该方法完成 容器初始化的 wac.refresh(); } } ``` -这时候DispatcherServlet中的IoC容器已经建立起来了,这个IoC容器是 根上下文 的子容器。如果要查找一个由DispatcherServlet所持有的IoC容器来管理的Bean,系统会首先到 根上下文 中去查找。如果查找不到,才会到DispatcherServlet所管理的IoC容器去进行查找,这是由IoC容器getBean()的实现来决定的。通过一系列在Web容器中执行的动作,在这个上下文体系建立和初始化完毕的基础上,Spring MVC就可以发挥其作用了。下面来分析一下Spring MVC的具体实现。 +这时候 DispatcherServlet 中的 IoC容器 已经建立起来了,这个 IoC容器 是 根上下文 的子容器。如果要查找一个由 DispatcherServlet 所持有的 IoC容器 来管理的 Bean,系统会首先到 根上下文 中去查找。如果查找不到,才会到 DispatcherServlet 所管理的 IoC容器 去进行查找,这是由 IoC容器 的 getBean() 的实现来决定的。通过一系列在 Web容器 中执行的动作,在这个上下文体系建立和初始化完毕的基础上,SpringMVC 就可以发挥其作用了。下面来分析一下 SpringMVC 的具体实现。 -在前面分析DispatchServlet的初始化过程中可以看到,DispatchServlet持有一个以自己的Servlet名称命名的IoC容器。这个IoC容器是一个WebApplicationContext对象,这个IoC容器建立起来以后,意味着DispatcherServlet拥有自己的Bean定义空间,这为使用各个独立的XML文件来配置MVC中各个Bean创造了条件。由于在初始化结束以后,与Web容器相关的加载过程实际上已经完成了,SpringMVC的具体实现和普通的Spring应用程序的实现并没有太大的差别。 +在前面分析 DispatchServlet 的初始化过程中可以看到,DispatchServlet 持有一个以自己的 Servlet名称 命名的 IoC容器。这个 IoC容器 是一个 WebApplicationContext对象,这个 IoC容器 建立起来以后,意味着 DispatcherServlet 拥有自己的 Bean定义空间,这为使用各个独立的 XML文件 来配置 MVC 中各个 Bean 创造了条件。由于在初始化结束以后,与 Web容器 相关的加载过程实际上已经完成了,SpringMVC 的具体实现和普通的 Spring应用程序 的实现并没有太大的差别。 -在DispatcherServlet的初始化过程中,以对HandlerMapping的初始化调用作为触发点,了解SpringMVC模块初始化的方法调用关系。这个调用关系最初是由HttpServletBean的init()方法触发的,这个HttpServletBean是HttpServlet的子类。接着会在HttpServletBean的子类FrameworkServlet中对IoC容器完成初始化,在这个初始化方法中,会调用DispatcherServlet的initStrategies()方法,该方法包括对各种MVC框架的实现元素,比如支持国际化的LocalResolver、支持request映射的HandlerMappings,以及视图生成的ViewResolver等。由该方法启动整个Spring MVC框架的初始化。 +在 DispatcherServlet 的初始化过程中,以对 HandlerMapping 的初始化调用作为触发点,了解 SpringMVC模块 初始化的方法调用关系。这个调用关系最初是由 HttpServletBean 的 init()方法 触发的,这个 HttpServletBean 是 HttpServlet 的子类。接着会在 HttpServletBean 的子类 FrameworkServlet 中对 IoC容器 完成初始化,在这个初始化方法中,会调用 DispatcherServlet 的 initStrategies()方法,该方法包括对各种 MVC框架 的实现元素,比如支持国际化的 LocalResolver、支持 request 映射的 HandlerMappings,以及视图生成的 ViewResolver 等。由该方法启动整个 SpringMVC框架 的初始化。 ```java public class DispatcherServlet extends FrameworkServlet { /** - * 初始化此servlet使用的策略对象。 + * 初始化此 servlet 使用的策略对象。 * 可以在子类中重写,以便初始化进一步的策略对象(U8C) */ protected void initStrategies(ApplicationContext context) { @@ -306,7 +308,7 @@ public class DispatcherServlet extends FrameworkServlet { initLocaleResolver(context); // 主题view层 initThemeResolver(context); - // 解析url和Method的对应关系 + // 解析 url 和 Method 的对应关系 initHandlerMappings(context); // 适配器匹配 initHandlerAdapters(context); @@ -321,42 +323,42 @@ public class DispatcherServlet extends FrameworkServlet { } } ``` -对于具体的初始化过程,根据上面的方法名称,很容易理解。以HandlerMapping为例来说明这个initHandlerMappings()过程。这里的Mapping关系的作用是,为HTTP请求找到相应的Controller控制器,从而利用这些控制器Controller去完成设计好的数据处理工作。 +对于具体的初始化过程,根据上面的方法名称,很容易理解。以 HandlerMapping 为例来说明这个 initHandlerMappings()过程。这里的 Mapping关系 的作用是,为 HTTP请求 找到相应的 Controller控制器,从而利用这些 控制器Controller 去完成设计好的数据处理工作。 -HandlerMappings完成对MVC中Controller的定义和配置,只不过在Web这个特定的应用环境中,这些控制器是与具体的HTTP请求相对应的。在HandlerMapping初始化的过程中,把在Bean配置文件中配置好的HandlerMapping从IoC容器中取得。 +HandlerMappings 完成对 MVC 中 Controller 的定义和配置,只不过在 Web 这个特定的应用环境中,这些控制器是与具体的 HTTP请求 相对应的。在 HandlerMapping初始化 的过程中,把在 Bean配置文件 中配置好的 HandlerMapping 从 IoC容器 中取得。 ```java /** - * 初始化此类使用的HandlerMappings。 - * 如果在BeanFactory中没有为此命名空间定义的HandlerMapping bean,则默认为BeanNameUrlHandlerMapping + * 初始化此类使用的 HandlerMappings。 + * 如果在 BeanFactory 中没有为此命名空间定义的 HandlerMapping bean,则默认为 BeanNameUrlHandlerMapping */ private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; - // 这个detectAllHandlerMappings默认为true,表示从所有的IoC容器中获取所有的HandlerMappings + // 这个 detectAllHandlerMappings 默认为 true,表示从所有的 IoC容器 中获取所有的HandlerMappings if (this.detectAllHandlerMappings) { - // 查找所有的HandlerMapping,从应用上下文context及其双亲上下文中 + // 查找所有的 HandlerMapping,从 应用上下文context 及其双亲上下文中 Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList( matchingBeans.values()); - // 保持HandlerMappings的有序性 + // 保持 HandlerMappings 的有序性 OrderComparator.sort(this.handlerMappings); } } else { try { - // 根据名称从当前的IoC容器中通过getBean()获取HandlerMapping + // 根据名称从当前的 IoC容器 中通过 getBean() 获 取HandlerMapping HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { - // 忽略,稍后将添加默认的HandlerMapping + // 忽略,稍后将添加默认的 HandlerMapping } } - // 如果找不到其他映射,请通过注册默认的HandlerMapping确保至少有一个HandlerMapping + // 如果找不到其他映射,请通过注册默认的 HandlerMapping 确保至少有一个 HandlerMapping if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isDebugEnabled()) { @@ -366,20 +368,18 @@ HandlerMappings完成对MVC中Controller的定义和配置,只不过在Web这 } } ``` -经过以上读取过程,handlerMappings变量就已经获取了在Bean中配置好的映射关系。其他的初始化过程和handlerMappings比较类似,都是直接从IoC容器中读入配置,所以这里的MVC初始化过程是建立在IoC容器已经初始化完成的基础上的。 +经过以上读取过程,handlerMappings变量 就已经获取了在 Bean 中配置好的映射关系。其他的初始化过程和 handlerMappings 比较类似,都是直接从 IoC容器 中读入配置,所以这里的 MVC初始化过程 是建立在 IoC容器 已经初始化完成的基础上的。 ## 4 SpringMVC处理分发HTTP请求 ### 4.1 HandlerMapping的配置和设计原理 -前面分析了DispatcherServlet对Spring MVC框架的初始化过程,在此基础上,我们再进一步分析HandlerMapping的实现原理,看看这个MVC框架中比较关键的控制部分是如何实现的。 +前面分析了 DispatcherServlet 对 SpringMVC框架 的初始化过程,在此基础上,我们再进一步分析 HandlerMapping 的实现原理,看看这个 MVC框架 中比较关键的控制部分是如何实现的。 -在初始化完成时,在上下文环境中已定义的所有HandlerMapping都已经被加载了,这些加载的handlerMappings被放在一个List中并被排序,存储着HTTP请求对应的映射数据。这个List中的每一个元素都对应着一个具体handlerMapping的配置,一般每一个handlerMapping -可以持有一系列从URL请求到Controller的映射,而Spring MVC提供了一系列的HandlerMapping实现。 +在初始化完成时,在上下文环境中已定义的所有 HandlerMapping 都已经被加载了,这些加载的 handlerMappings 被放在一个 List 中并被排序,存储着 HTTP请求 对应的映射数据。这个 List 中的每一个元素都对应着一个具体 handlerMapping 的配置,一般每一个 handlerMapping 可以持有一系列从 URL请求 到 Controller 的映射,而 SpringMVC 提供了一系列的 HandlerMapping 实现。 ![avatar](/images/springMVC/HandlerMapping组件.png) -以SimpleUrlHandlerMapping这个handlerMapping为例来分析HandlerMapping的设计与实现。在SimpleUrlHandlerMapping中,定义了一个map来 持有 一系列的映射关系。通过这些在HandlerMapping中定义的映射关系,即这些URL请求和控制器的对应关系,使Spring MVC -应用可以根据HTTP请求确定一个对应的Controller。具体来说,这些映射关系是通过接口HandlerMapping来封装的,在HandlerMapping接 口中定义了一个getHandler方法,通过这个方法,可以获得与HTTP请求对应的HandlerExecutionChain,在这个HandlerExecutionChain -中,封装了具体的Controller对象。 +以 SimpleUrlHandlerMapping 为例来分析 HandlerMapping 的设计与实现。在 SimpleUrlHandlerMapping 中,定义了一个 Map 来持有一系列的映射关系。通过这些在 HandlerMapping 中定义的映射关系,即这些 URL请求 和控制器的对应关系,使 SpringMVC +应用 可以根据 HTTP请求 确定一个对应的 Controller。具体来说,这些映射关系是通过 HandlerMapping接口 来封装的,在 HandlerMapping接口 中定义了一个 getHandler()方法,通过这个方法,可以获得与 HTTP请求 对应的 HandlerExecutionChain,在这个 HandlerExecutionChain 中,封装了具体的 Controller对象。 ```java public interface HandlerMapping { @@ -396,15 +396,13 @@ public interface HandlerMapping { String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes"; /** - * 返回的这个HandlerExecutionChain不但持有handler本身,还包括了处理这个HTTP请求的拦截器 + * 返回的这个 HandlerExecutionChain 不但持有 handler本身,还包括了处理这个 HTTP请求 的拦截器链 */ HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; } ``` -这个HandlerExecutionChain的实现看起来比较简洁,它持有一个Interceptor链和一个handler对象,这个handler对象实际上就是HTTP请求对应的Controller,在持有这个handler对象的同时,还在HandlerExecutionChain中设置了一个拦截器链,通过这个拦截器链中的拦截器, -可以为handler对象提供功能的增强。要完成这些工作,需要对拦截器链和handler都进行配置,这些配置都是在HandlerExecutionChain的初始化函数中完成的。为了维护这个拦截器链和handler,HandlerExecutionChain还提供了一系列与拦截器链维护相关的操作,比如,为拦 -截器链增加拦截器的addInterceptor()方法。 +这个 HandlerExecutionChain 的实现看起来比较简洁,它持有一个 拦截器链(HandlerInterceptor对象列表) 和一个 handler对象,这个 handler对象 实际上就是 HTTP请求 对应的 Controller,在持有这个 handler对象 的同时,还在 HandlerExecutionChain 中设置了一个拦截器链,通过这个拦截器链中的拦截器,可以为 handler对象 提供功能的增强。要完成这些工作,需要对拦截器链和 handler 都进行配置,这些配置都是在 HandlerExecutionChain 的初始化函数中完成的。为了维护这个拦截器链和 handler,HandlerExecutionChain 还提供了一系列与拦截器链维护相关的操作,比如,为拦截器链增加拦截器的 addInterceptor()方法。 ```java public class HandlerExecutionChain { @@ -460,7 +458,7 @@ public class HandlerExecutionChain { } /** - * 延迟初始化interceptorList和interceptors集合 + * 延迟初始化 interceptorList 和 interceptors集合 */ private void initInterceptorList() { if (this.interceptorList == null) { @@ -496,12 +494,13 @@ public class HandlerExecutionChain { } } ``` -HandlerExecutionChain中定义的Handler和Interceptor需要在定义HandlerMapping时配置好,例如对具体的SimpleURLHandlerMapping,要做的就是根据URL映射的方式,注册Handler和Interceptor,从而维护一个反映这种映射关系的handlerMap。当需要匹配HTTP请求时,需要查询这个handlerMap中的信息来得到对应的HandlerExecutionChain。这些信息是什么时候配置好的呢?这里有一个注册过程,这个注册过程在容器对Bean进行依赖注入时发生,它实际上是通过一个Bean的postProcessor()来完成的。以SimpleHandlerMapping为例,需要注意的是,这里用到了对容器的回调,只有SimpleHandlerMapping是ApplicationContextAware的子类才能启动这个注册过程。这个注册过程完成的是反映URL和Controller之间映射关系的handlerMap的建立。 +HandlerExecutionChain 中定义的 Handler 和 HandlerInterceptor[]属性 需要在定义 HandlerMapping 时配置好,例如对具体的 SimpleURLHandlerMapping,要做的就是根据 URL映射 的方式,注册 Handler 和 HandlerInterceptor[],从而维护一个反映这种映射关系的 handlerMap。当需要匹配 HTTP请求 时,需要查询这个 handlerMap 中的信息来得到对应的 HandlerExecutionChain。这些信息是什么时候配置好的呢?这里有一个注册过程,这个注册过程在容器对 Bean 进行依赖注入时发生,它实际上是通过一个 Bean 的 postProcessor() 来完成的。以 SimpleHandlerMapping 为例,需要注意的是,这里用到了对容器的回调,只有 SimpleHandlerMapping 是 ApplicationContextAware 的子类才能启动这个注册过程。这个注册过程完成的是反映 URL 和 Controller 之间映射关系的 handlerMap 的建立。 ![avatar](/images/springMVC/SimpleUrlHandlerMapping的继承关系.png) ```java public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping { + @Override public void initApplicationContext() throws BeansException { super.initApplicationContext(); @@ -509,18 +508,18 @@ public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping { } /** - * 为相应的路径注册URL映射中指定的所有handlers处理程序 + * 为相应的路径注册 URL映射 中指定的所有 handlers处理程序 */ protected void registerHandlers(Map urlMap) throws BeansException { if (urlMap.isEmpty()) { logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping"); } else { - // 这里对bean的配置进行解析,然后调用父类的registerHandler()方法进行解析 + // 这里对 bean 的配置进行解析,然后调用父类的 registerHandler()方法 进行解析 for (Map.Entry entry : urlMap.entrySet()) { String url = entry.getKey(); Object handler = entry.getValue(); - // 如果url没有斜线,就在前面加上斜线 + // 如果 url 没有斜线,就在前面加上斜线 if (!url.startsWith("/")) { url = "/" + url; } @@ -535,12 +534,12 @@ public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping { } } ``` -这个SimpleUrlHandlerMapping注册过程的完成,很大一部分需要它的基类来配合,这个基类就是AbstractUrlHandlerMapping。在AbstractUrlHandlerMapping的处理过程中,如果使用Bean的名称作为映射,那么直接从容器中获取这个HTTP映射对应的Bean,然后还要对不同的URL配置进行解析处理,比如在HTTP请求中配置成“/”和通配符“/*” 的URL,以及正常的URL请求,完成这个解析处理过程以后,会 -把URL和handler作为键值对放到一个handlerMap中去。 +这个 SimpleUrlHandlerMapping 注册过程的完成,很大一部分需要它的基类来配合,这个基类就是 AbstractUrlHandlerMapping。在 AbstractUrlHandlerMapping 的处理过程中,如果使用 Bean 的名称作为映射,那么直接从容器中获取这个 HTTP映射 对应的 Bean,然后还要对不同的 URL配置 进行解析处理,比如在 HTTP请求 中配置成 “/” 和 通配符“/*” 的 URL,以及正常的 URL请求,完成这个解析处理过程以后,会把 URL 和 handler 作为键值对放到一个 handlerMap 中去。 ```java public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered { + /** - * 为给定的URL路径注册指定的handler处理程序 + * 为给定的 URL路径 注册指定的 handler处理程序 */ protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException { Assert.notNull(urlPaths, "URL path array must not be null"); @@ -550,14 +549,14 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport } /** - * 为给定的URL路径注册指定的handler处理程序 + * 为给定的 URL路径 注册指定的 handler处理程序 */ protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { Assert.notNull(urlPath, "URL path must not be null"); Assert.notNull(handler, "Handler object must not be null"); Object resolvedHandler = handler; - // 如果使用bean名称进行映射,就直接从IoC容器中获取该bean名称对应的handler + // 如果使用 bean名称 进行映射,就直接从 IoC容器 中获取该 bean名称 对应的 handler if (!this.lazyInitHandlers && handler instanceof String) { String handlerName = (String) handler; if (getApplicationContext().isSingleton(handlerName)) { @@ -574,21 +573,21 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport } } else { - // 处理URL是"/"的映射,把这个"/"映射的controller设置到rootHandler中 + // 处理 URL 是 "/" 的映射,把这个 "/" 映射的 controller 设置到 rootHandler 中 if (urlPath.equals("/")) { if (logger.isInfoEnabled()) { logger.info("Root mapping to " + getHandlerDescription(handler)); } setRootHandler(resolvedHandler); } - // 处理URL是"/"的映射,把这个"/"映射的controller设置到defaultHandler中 + // 处理 URL 是 "/" 的映射,把这个 "/" 映射的 controller 设置到 defaultHandler 中 else if (urlPath.equals("/*")) { if (logger.isInfoEnabled()) { logger.info("Default mapping to " + getHandlerDescription(handler)); } setDefaultHandler(resolvedHandler); } - // 处理正常的URL映射,此handlerMap的key和value分别代表URL和映射的Controller + // 处理正常的 URL映射,此 handlerMap 的 key 和 value 分别代表 URL 和 映射的Controller else { this.handlerMap.put(urlPath, resolvedHandler); if (logger.isInfoEnabled()) { @@ -599,7 +598,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport } /** - * 为此handler映射设置根handler,即要为根路径("/")注册的handler + * 为此 handler映射 设置 根handler,即要为根路径("/")注册的 handler *

Default is {@code null}, indicating no root handler. */ public void setRootHandler(Object rootHandler) { @@ -611,7 +610,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport } /** - * 设置此handler映射的默认handler。如果未找到特定映射,则将返回此handler + * 设置 此handler映射 的默认 handler。如果未找到特定映射,则将返回 此handler */ public void setDefaultHandler(Object defaultHandler) { this.defaultHandler = defaultHandler; @@ -622,50 +621,50 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport } } ``` -这里的handlerMap是一个HashMap,其中保存了URL请求和Controller的映射关系,这个handlerMap是在AbstractUrlHandlerMapping中定义的( Map handlerMap = new LinkedHashMap() ),这个配置好URL请求和handler映射数据的handlerMap,为Spring MVC响应HTTP请求准备好了基本的映射数据,根据这个handlerMap以及设置于其中的映射数据,可以方便地由 -URL请求得到它所对应的handler。有了这些准备工作,Spring MVC就可以等待HTTP请求的到来了。 +这里的 handlerMap 是一个 HashMap,其中保存了 “URL请求” --> “Controller对象” 的映射关系,这个 handlerMap 是在 AbstractUrlHandlerMapping 中定义的( Map handlerMap = new LinkedHashMap() ),这个配置好 URL请求 和 handler映射数据 的 handlerMap,为 SpringMVC 响应 HTTP请求 准备好了基本的映射数据,根据这个 handlerMap 以及设置于其中的映射数据,可以方便地由 URL请求 得到它所对应的 handler。有了这些准备工作,SpringMVC 就可以等待 HTTP请求 的到来了。 ### 4.2 使用HandlerMapping完成请求的映射处理 -继续通过SimpleUrlHandlerMapping的实现来分析HandlerMapping的接口方法getHandler(),该方法会根据初始化时得到的映射关系来生成DispatcherServlet需要的HandlerExecutionChain,也就是说,这个getHandler()方法是实际使用HandlerMapping完成请求的映射处理的地方。在前面的HandlerExecutionChain的执行过程中,首先在AbstractHandlerMapping中启动getHandler的调用。 +继续通过 SimpleUrlHandlerMapping的实现 来分析 HandlerMapping 的 接口方法getHandler(),该方法会根据初始化时得到的映射关系来生成 DispatcherServlet 需要的 HandlerExecutionChain,也就是说,这个 getHandler()方法 是实际使用 HandlerMapping 完成请求的映射处理的地方。在前面的 HandlerExecutionChain 的执行过程中,首先在 AbstractHandlerMapping 中启动 getHandler() 的调用。 ```java public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered { /** - * 查找给定请求的handler,如果找不到特定的handler,则返回到defaultHandler + * 查找给定请求的 handler,如果找不到特定的 handler,则返回到 defaultHandler */ public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { - // 模板方法模式 + // 这里用到了模板方法模式,getHandler() 是一个模板方法,定义了流程,getHandlerInternal() 则是 + // 一个抽象方法,交由子类实现 Object handler = getHandlerInternal(request); - // 如果找不到特定的handler,则取defaultHandler + // 如果找不到特定的 handler,则取 defaultHandler if (handler == null) { handler = getDefaultHandler(); } - // defaultHandler也没有则返回null + // defaultHandler 也没有则返回 null if (handler == null) { return null; } - // 如果该handler是String类型的,说明它是一个beanname - // 根据该beanname从IoC容器中获取真正的handler对象 + // 如果该 handler 是 String类型的,说明它是一个 beanName + // 根据该 beanName 从 IoC容器 中获取真正的 handler对象 if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } - // 这里把handler添加到到HandlerExecutionChain中 + // 这里把 handler 添加到到 HandlerExecutionChain 中 return getHandlerExecutionChain(handler, request); } } ``` -取得handler的具体过程在getHandlerInternal()方法中实现,这个方法接受HTTP请求作为参数,它的实现在AbstractHandlerMapping的子类AbstractUrlHandlerMapping中,这个实现过程包括从HTTP请求中得到URL,并根据URL到urlMapping中获得handler。 +取得 handler 的具体过程在 getHandlerInternal()方法 中实现,这个方法接受 HTTP请求 作为参数,它的实现在 AbstractHandlerMapping 的子类 AbstractUrlHandlerMapping 中,这个实现过程包括从 HTTP请求 中得到 URL,并根据 URL 到 urlMapping 中获得 handler。 ```java public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { /** - * 查找给定请求的URL路径 对应的handler + * 查找 给定请求的URL 对应的 handler */ @Override protected Object getHandlerInternal(HttpServletRequest request) throws Exception { - // 从request中获取请求的URL路径 + // 从 request 中获取请求的 URL路径 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); - // 将得到的URL路径与handler进行匹配,得到对应的handler,如果没有对应的handler - // 则返回null,这样默认的handler会被使用 + // 将得到的 URL路径 与 handler 进行匹配,得到对应的 handler,如果没有对应的 handler + // 则返回 null,这样 默认的handler 会被使用 Object handler = lookupHandler(lookupPath, request); if (handler == null) { // We need to care for the default handler directly, since we need to @@ -674,7 +673,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { if ("/".equals(lookupPath)) { rawHandler = getRootHandler(); } - // 使用默认的handler + // 使用 默认的handler if (rawHandler == null) { rawHandler = getDefaultHandler(); } @@ -698,7 +697,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { } /** - * 查找给定URL路径的handler实例 + * 查找给定 URL路径 的 handler实例 */ protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // 直接匹配 @@ -758,28 +757,28 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { } } ``` -经过这一系列对HTTP请求进行解析和匹配handler的过程,得到了与请求对应的handler处理器。在返回的handler中,已经完成了在HandlerExecutionChain中进行封装的工作,为handler对HTTP请求的响应做好了准备。 +经过这一系列对 HTTP请求 进行解析和匹配 handler 的过程,得到了与请求对应的 handler处理器。在返回的 handler 中,已经完成了在 HandlerExecutionChain 中进行封装的工作,为 handler 对 HTTP请求 的响应做好了准备。 ### 4.3 DispatcherServlet对HTTP请求的分发处理 -DispatcherServlet是Spring MVC框架中非常重要的一个类,不但建立了自己持有的IoC容器,还肩负着请求分发处理的重任,对HTTP请求的处理是在doService()方法中完成的。DispatcherServlet是HttpServlet的子类 ,与其他HttpServlet一样,可以通过doService()来响应HTTP的请求。然而,依照Spring MVC的使用,业务逻辑的调用入口是在handler的handler()方法中实现的,这是连接Spring MVC和应用业务逻辑实现的地方。 +DispatcherServlet 是 SpringMVC框架 中非常重要的一个类,不但建立了自己持有的 IoC容器,还肩负着请求分发处理的重任,对 HTTP请求 的处理是在 doService()方法 中完成的。DispatcherServlet 是 HttpServlet 的子类 ,与其他 HttpServlet 一样,可以通过 doService() 来响应 HTTP的请求。然而,依照 SpringMVC 的使用,业务逻辑的调用入口是在 handler 的 handler()方法 中实现的,这是连接 SpringMVC 和应用业务逻辑实现的地方。 ```java public class DispatcherServlet extends FrameworkServlet { - /** 此servlet使用的HandlerMappings列表 */ + /** 此 DispatcherServlet 使用的 HandlerMapping对象列表 */ private List handlerMappings; - /** 此servlet使用的HandlerAdapter列表 */ + /** 此 DispatcherServlet 使用的 HandlerAdapter对象列表 */ private List handlerAdapters; /** - * 公开DispatcherServlet特定的请求属性,并将其委托给doDispatch()方法进行实际的分发 + * 公开 DispatcherServlet 特定的请求属性,并将其委托给 doDispatch()方法 进行实际的分发 */ @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { - // 得到请求的URI + // 得到 请求的URI String requestUri = urlPathHelper.getRequestUri(request); String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : ""; @@ -836,8 +835,8 @@ public class DispatcherServlet extends FrameworkServlet { /** * 中央控制器,控制请求的转发 - * 对请求的处理实际上是由doDispatch()来完成的,它是DispatcherServlet完成HTTP请求分发处理的主要方法, - * 包括准备ModelAndView,调用getHandler()方法来响应HTTP请求,然后通过执行Handler的处理来获取请求的 + * 对请求的处理实际上是由 doDispatch() 来完成的,它是 DispatcherServlet 完成 HTTP请求 分发处理的主要方法, + * 包括准备 ModelAndView,调用 getHandler()方法 来响应 HTTP请求,然后通过执行 Handler的处理 来获取请求的 * 处理结果,最后把结果返回出去 */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) @@ -849,7 +848,7 @@ public class DispatcherServlet extends FrameworkServlet { WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { - // 为视图准备好一个ModelAndView,这个ModelAndView持有handler处理请求的结果 + // 为视图准备好一个 ModelAndView,这个 ModelAndView 持有 handler处理请求的结果 ModelAndView mv = null; Exception dispatchException = null; @@ -858,20 +857,20 @@ public class DispatcherServlet extends FrameworkServlet { processedRequest = checkMultipart(request); multipartRequestParsed = processedRequest != request; - // 2.取得处理当前请求的controller,这里也称为hanlder处理器,这里并不是 - // 直接返回controller,而是返回的HandlerExecutionChain请求处理器链对象, - // 该对象封装了handler和interceptors + // 2.取得处理当前请求的 Controller对象,这里也称为 hanlder处理器,这里并不是 + // 直接返回 controller对象,而是返回的 HandlerExecutionChain请求处理器链对象, + // 该对象封装了 handler 和 interceptors mappedHandler = getHandler(processedRequest, false); - // 如果handler为空,则返回404 + // 如果 handler 为空,则返回 404 if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } - // 3. 获取处理request的处理器适配器handler adapter + // 3. 获取处理 request 的处理器适配器 HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); - // 获取请求方式,如:GET, POST, PUT + // 获取 请求方式,如:GET, POST, PUT String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { @@ -939,7 +938,7 @@ public class DispatcherServlet extends FrameworkServlet { } /** - * 返回此请求的HandlerExecutionChain,按顺序尝试所有的HandlerMapping + * 返回此请求的 HandlerExecutionChain,按顺序尝试所有的 HandlerMapping */ @Deprecated protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) @@ -948,17 +947,17 @@ public class DispatcherServlet extends FrameworkServlet { } /** - * 返回此请求的HandlerExecutionChain + * 返回此请求的 HandlerExecutionChain */ protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { - // 遍历 此servlet使用的HandlerMapping列表 + // 遍历 此servlet 使用的 HandlerMapping列表 for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'"); } - // 查找给定请求的handler + // 查找给定请求的 handler HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; @@ -968,10 +967,10 @@ public class DispatcherServlet extends FrameworkServlet { } /** - * 返回此处理程序对象handler的HandlerAdapter + * 返回 此处理程序对象handler 的 HandlerAdapter */ protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { - // 对所有持有的HandlerAdapter进行匹配 + // 对所有持有的 HandlerAdapter 进行匹配 for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); @@ -985,11 +984,11 @@ public class DispatcherServlet extends FrameworkServlet { } } ``` -通过判断,可以知道这个handler是不是Controller接口的实现,比如可以通过具体HandlerAdapter的实现来了解这个适配过程。以SimpleControllerHandlerAdapter的实现为例来了解这个判断是怎样起作用的。 +通过判断,可以知道这个 handler 是不是 Controller接口 的实现,比如可以通过具体 HandlerAdapter 的实现来了解这个适配过程。以 SimpleControllerHandlerAdapter的实现 为例来了解这个判断是怎样起作用的。 ```java public class SimpleControllerHandlerAdapter implements HandlerAdapter { - // 判断要执行的handler是不是Controller类型的 + // 判断要执行的 handler 是不是 Controller类型的 public boolean supports(Object handler) { return (handler instanceof Controller); } @@ -1009,8 +1008,4 @@ public class SimpleControllerHandlerAdapter implements HandlerAdapter { } ``` -经过上面一系列的处理,得到了handler对象,接着就可以开始调用handler对象中的HTTP响应动作了。在handler中封装了应用业务逻辑,由这些逻辑对HTTP请求进行相应的处理,生成需要的数据,并把这些数据封装到ModelAndView对象中去,这个ModelAndView的数据封装是Spring MVC框架的要求。对handler来说, 这些都是通过调用handler()方法中的handleRequest()方法来触发完成的。在得到ModelAndView对象以后,这个ModelAndView对象会被交给MVC模式中的视图类,由视图类对ModelAndView对象中的数据进行呈现。 - - - - +经过上面一系列的处理,得到了 handler对象,接着就可以开始调用 handler对象 中的 HTTP响应动作了。在 handler 中封装了应用业务逻辑,由这些逻辑对 HTTP请求 进行相应的处理,生成需要的数据,并把这些数据封装到 ModelAndView对象 中去,这个 ModelAndView 的数据封装是 SpringMVC框架 的要求。对 handler 来说, 这些都是通过调用 handler()方法 中的 handleRequest()方法 来触发完成的。在得到 ModelAndView对象 以后,这个 ModelAndView对象 会被交给 MVC模式 中的视图类,由视图类对 ModelAndView对象 中的数据进行呈现。