修缮之前的博文

pull/28/head
AmyliaY 6 years ago
parent bf5bf3603e
commit 289fa63ab4

@ -1,17 +1,16 @@
理论性的文字,我觉得就没必要再扯一遍咯,大道理讲这么多,越听越迷糊。不如直接看源码+注解来的明白痛快。所以话不多说,直接上源码。
理论性的文字,我觉得就没必要再扯一遍咯,大道理讲这么多,越听越迷糊。不如直接看源码加注释来的明白痛快。所以话不多说,直接上源码。
## 1主要的接口
### 1.1Advice 通知
定义了切面的增强方式,如:前置增强 BeforeAdvice后置增强 AfterAdvice异常增强 ThrowsAdvice 等。下面看两个主要的子接口的源码。
## 1 主要的接口
### 1.1 Advice 通知
本接口定义了切面的增强方式,如:前置增强 BeforeAdvice后置增强 AfterAdvice异常增强 ThrowsAdvice 等。下面看两个主要的子接口的源码。
```java
public interface MethodBeforeAdvice extends BeforeAdvice {
/**
* 目标方法 method 要开始执行时AOP 会回调此方法
* 目标方法 method 开始执行前AOP 会回调此方法
*/
void before(Method method, Object[] args, Object target) throws Throwable;
}
public interface AfterReturningAdvice extends AfterAdvice {
@ -20,11 +19,10 @@ public interface AfterReturningAdvice extends AfterAdvice {
* 目标方法 method 执行后AOP 会回调此方法,注意,它还传入了 method 的返回值
*/
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
}
```
### 1.2Pointcut 方法的横切面
用来定义需要增强的目标方法的集合一般使用正则表达式去匹配筛选指定范围内的所有满足条件的目标方法。Pointcut 接口有很多实现,我们主要看一下 JdkRegexpMethodPointcut 和 NameMatchMethodPointcut 的实现原理,前者主要通过正则表达式对方法名进行匹配,后者则通过匹配方法名进行匹配。
### 1.2 Pointcut 方法的横切面
本接口用来定义需要增强的目标方法的集合一般使用正则表达式去匹配筛选指定范围内的所有满足条件的目标方法。Pointcut 接口有很多实现,我们主要看一下 JdkRegexpMethodPointcut 和 NameMatchMethodPointcut 的实现原理,前者主要通过正则表达式对方法名进行匹配,后者则通过匹配方法名进行匹配。
```java
// JdkRegexpMethodPointcut 的实现源码
@ -47,7 +45,7 @@ public interface AfterReturningAdvice extends AfterAdvice {
return false;
}
```
### 1.3Advisor 通知器
### 1.3 Advisor 通知器
将 Pointcut 和 Advice 有效地结合在一起。它定义了在哪些方法Pointcut上执行哪些动作Advice。下面看一下 DefaultPointcutAdvisor 的源码实现,它通过持有 Pointcut 和 Advice 属性来将两者有效地结合在一起。
```java
@ -63,7 +61,7 @@ public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor imple
}
/**
* 自己定义了 PointcutAdvice 则使用父类中的定义
* 自己定义了 Pointcut属性而 Advice属性 则使用父类中的定义
*/
public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
this.pointcut = pointcut;
@ -88,16 +86,13 @@ public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdv
public String toString() {
return getClass().getName() + ": advice [" + getAdvice() + "]";
}
}
```
## 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。
## 2 Spring AOP 的设计与实现
AOP 的实现代码中,主要使用了 JDK 动态代理,在特定场景下(被代理对象没有 implements 的接口)也用到了 CGLIB 生成代理对象。通过 AOP 的源码设计可以看到,其先为目标对象建立了代理对象,这个代理对象的生成可以使用 JDK 动态代理或 CGLIB 完成。然后启动为代理对象配置的拦截器,对横切面(目标方法集合)进行相应的增强,将 AOP 的横切面设计和 Proxy 模式有机地结合起来,实现了在 AOP 中定义好的各种织入方式。
先看一下 ProxyFactoryBean 的配置和使用。
### 2.1 ProxyFactoryBean
这里我们主要以 ProxyFactoryBean 的实现为例,对 AOP 的实现原理进行分析。ProxyFactoryBean 主要持有目标对象 target 的代理对象 aopProxy和 Advisor 通知器,而 Advisor 持有 Advice 和 Pointcut这样就可以判断 aopProxy 中的方法 是否是某个指定的切面 Pointcut然后根据其配置的织入方向前置增强/后置增强),通过反射为其织入相应的增强行为 Advice。先看一下 ProxyFactoryBean 的配置和使用。
```xml
<!-- 定义自己的 Advisor 实现,其中包含了 Pointcut 和 Advice -->
@ -116,7 +111,7 @@ AOP 的实现代码中,主要使用了 JDK 动态代理,在特定场景下
</property>
</bean>
```
### 2.2、ProxyFactoryBean 为配置的 target 生成 AopProxy 代理对象
### 2.2 为配置的 target 生成 AopProxy 代理对象
ProxyFactoryBean 的 getObject() 方法先对通知器链进行了初始化,然后根据被代理对象类型的不同,生成代理对象。
```java
@ -140,7 +135,7 @@ ProxyFactoryBean 的 getObject() 方法先对通知器链进行了初始化,
}
}
```
### 2.3、initializeAdvisorChain() 初始化 Advisor 链
### 2.3 初始化 Advisor 链
```java
/**
@ -171,7 +166,6 @@ ProxyFactoryBean 的 getObject() 方法先对通知器链进行了初始化,
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
@ -180,7 +174,6 @@ ProxyFactoryBean 的 getObject() 方法先对通知器链进行了初始化,
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
else {
// 对当前的 factoryBean 进行类型判断,是属于单例 bean 还是原型 bean
Object advice;
@ -197,16 +190,15 @@ ProxyFactoryBean 的 getObject() 方法先对通知器链进行了初始化,
}
}
}
this.advisorChainInitialized = true;
}
```
生成 singleton 的代理对象在 getSingletonInstance 方法中完成,这是 ProxyFactoryBean 生成 AopProxy 代理对象的调用入口。代理对象会封装对 target 对象的调用,针对 target 对象的方法调用会被这里生成的代理对象所拦截。
### 2.4、getSingletonInstance() 生成单例代理对象
### 2.4 生成单例代理对象
```java
/**
* 返回此类代理对象的单例实例,如果尚未创建该实例,则使用单例模式的懒汉式 创建它
* 返回此类代理对象的单例实例,如果尚未创建该实例,则单例地创建它
*/
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
@ -263,11 +255,10 @@ public class ProxyCreatorSupport extends AdvisedSupport {
public AopProxyFactory getAopProxyFactory() {
return this.aopProxyFactory;
}
}
```
下面看一下 AopProxyFactory 接口的实现类 DefaultAopProxyFactory 的代码
下面看一下 AopProxyFactory 接口的实现类 DefaultAopProxyFactory 的 createAopProxy(AdvisedSupport config)方法
```java
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
@ -299,10 +290,17 @@ public class ProxyCreatorSupport extends AdvisedSupport {
可以看到其根据目标对象是否实现了接口,而决定是使用 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 {
/** AdvisedSupport 持有一个 List<Advisor>属性 */
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) {
@ -326,16 +324,21 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//通过 Proxy 生成代理对象并返回
// 通过 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
final class CglibAopProxy implements AopProxy, Serializable {
/** AdvisedSupport 持有一个 List<Advisor>属性 */
protected final AdvisedSupport advised;
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
@ -410,14 +413,16 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
}
}
```
为目标对象 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.1JdkDynamicAopProxy 的 invoke() 拦截
### 3.1 JdkDynamicAopProxy 的 invoke() 拦截
前面已经通过两种不同的方式生成了 AopProxy 代理对象,下面我们先看一下 JdkDynamicAopProxy 中的 invoke()回调方法 中对拦截器调用的实现。
```java
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
@ -429,7 +434,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
Object target = null;
try {
//如果目标对象调用的是 Obejct 类中的基本方法equals、hashCode 则进行相应的处理
// 如果目标对象调用的是 Obejct类 中的基本方法equals()、hashCode() 则进行相应的处理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// 如果目标对象没有重写 Object类 的基本方法equals(Object other)
return equals(args[0]);
@ -458,10 +463,10 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
targetClass = target.getClass();
}
//获取定义好的拦截器链
// 获取定义好的拦截器链,即 Advisor列表
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
//如果没有配置拦截器,就直接调用目标对象 target 的 method 方法,并获取返回值
// 如果没有配置拦截器,就直接通过反射调用目标对象 target 的 method对象,并获取返回值
if (chain.isEmpty()) {
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
@ -478,7 +483,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 特殊提醒它返回“this”方法的返回类型与类型兼容。
//注意,如果 target 在另一个返回的对象中设置了对自身的引用spring 将无法处理
// 注意,如果 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);
@ -496,11 +501,14 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
}
}
}
}
```
### 3.2CglibAopProxy 的 intercept() 拦截
### 3.2 CglibAopProxy 的 intercept() 拦截
CglibAopProxy 的 intercept() 回调方法实现和 JdkDynamicAopProxy 的 invoke() 非常相似,只是在 CglibAopProxy 中构造 CglibMethodInvocation 对象来完成拦截器链的调用,而在 JdkDynamicAopProxy 中则是通过构造 ReflectiveMethodInvocation 对象来完成的。
```java
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;
@ -542,9 +550,10 @@ CglibAopProxy 的 intercept() 回调方法实现和 JdkDynamicAopProxy 的 invok
}
}
}
}
```
### 3.3目标对象中目标方法的调用
对目标对象中目标方法的调用,是在 AopUtils 工具类中利用反射机制完成的。具体代码如下:
### 3.3 目标对象中目标方法的调用
对目标对象中目标方法的调用,是在 AopUtils 工具类中利用反射机制完成的,具体代码如下。
```java
public abstract class AopUtils {
@ -556,7 +565,7 @@ public abstract class AopUtils {
throws Throwable {
try {
//如果 method 是 private 等不可访问状态,则设置为 public 公开可访问
// 如果该 method 是 private的则将其访问权限设为 public的
ReflectionUtils.makeAccessible(method);
// 最后利用反射完成调用
return method.invoke(target, args);
@ -574,30 +583,59 @@ public abstract class AopUtils {
}
}
```
### 3.4AOP 拦截器链的调用
### 3.4 AOP 拦截器链的调用
JdkDynamicAopProxy 和 CglibAopProxy 虽然使用了不同的代理对象,但对 AOP 拦截的处理却是相同的,都是通过 ReflectiveMethodInvocation 的 proceed() 方法实现的。
```java
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<Object> 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() 方法完成的
// 从拦截器链中按顺序依次调用拦截器,直到所有的拦截器调用完毕,开始调用目标方法,对目标方法的调用
// 是在 invokeJoinpoint() 中通过 AopUtils 的 invokeJoinpointUsingReflection() 方法完成的
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// invokeJoinpoint() 直接通过 AopUtils 进行目标方法的调用
return invokeJoinpoint();
}
// 这里沿着定义好的 interceptorsAndDynamicMethodMatchers拦截器链 进行处理,
//它是一个 List也没有定义泛型interceptorOrInterceptionAdvice 是其中的一个元素,
// 它是一个 List也没有定义泛型interceptorOrInterceptionAdvice 是其中的一个元素
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 这里通过拦截器的 方法匹配器methodMatcher 进行方法匹配,
// 如果 目标类 的 目标方法 和配置的 Pointcut 匹配,那么这个 增强行为advice 将会被执行,
//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 {
@ -611,17 +649,29 @@ JdkDynamicAopProxy 和 CglibAopProxy 虽然使用了不同的代理对象,但
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
}
```
### 3.5配置通知器
### 3.5 配置通知器
AdvisedSupport 中实现了获取拦截器链的方法,并使用了缓存。
```java
public class AdvisedSupport extends ProxyConfig implements Advised {
/** TargetSource持有一个比较重要的属性targetClass */
TargetSource targetSource = EMPTY_TARGET_SOURCE;
/** 缓存 Method对象 和其对应的 拦截器链列表List<Advisor> */
private transient Map<MethodCacheKey, List<Object>> methodCache;
/** The AdvisorChainFactory to use */
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
/**
* 获取拦截器链,为提高效率,同时设置了缓存
*/
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {
//这里使用了缓存 cached如果缓存中有就从缓存中获取拦截器链
// 如果 缓存methodCache 中有就从缓存中获取 该Method对象 对应的拦截器链
// 没有,则调用 (DefaultAdvisorChainFactory)advisorChainFactory 的
//getInterceptorsAndDynamicInterceptionAdvice() 方法进行获取,并缓存到 cached
// getInterceptorsAndDynamicInterceptionAdvice() 方法进行获取,并缓存到 methodCache 中
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
@ -632,6 +682,7 @@ AdvisedSupport 中实现了获取拦截器链的方法,并使用了缓存。
}
return cached;
}
}
```
获取拦截器链的工作是由 AdvisorChainFactory 完成的,他是一个拦截器链的生成工厂。由于 AdvisorChainFactory 接口只有一个实现类 DefaultAdvisorChainFactory所以我们直接看这个类中的实现就行咯。
@ -642,8 +693,8 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class targetClass) {
//advisor 链已经在传进来的 config 中持有了,这里可以直接使用
//advisor 中持有切面 和 增强行为的引用
// Advisor链 已经在传进来的 config 中持有了,这里可以直接使用
// Advisor 中持有 切面Pointcut 和 增强行为Advice 两个重要属性
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
// 判断 config 中的 Advisors 是否符合配置要求
boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
@ -704,13 +755,15 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
}
return false;
}
}
```
这里的 advisor 通知器是从 AdvisedSupport 中获取的,而 advisor 的初始化则是在 ProxyFactoryBean 的 getObject() 方法中完成的。
```java
public class ProxyFactoryBean extends ProxyCreatorSupport
implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
/**
* 返回一个代理对象,当用户从 FactoryBean 中获取 bean 时调用,
* 创建此工厂要返回的 AOP 代理的实例,该实例将作为一个单例被缓存
@ -718,7 +771,7 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
public Object getObject() throws BeansException {
// 初始化通知器链
initializeAdvisorChain();
//这里对 Singleton 和 prototype 的类型进行区分,生成对应的 proxy
// 这里对 Singleton 和 Prototype 的类型进行区分,生成对应的 proxy
if (isSingleton()) {
return getSingletonInstance();
}
@ -753,8 +806,8 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
// 这里添加了 Advisor链 的调用,下面的 interceptorNames 是在配置文件中
// 通过 interceptorNames 进行配置的。由于每一个 Advisor 都是被配置为 bean 的,
//所以通过遍历 interceptorNames 得到的 name其实就是 bean 的 id通过这个 nameid
//我们就可以从 IoC 容器中获取对应的实例化 bean
// 所以通过遍历 interceptorNames 得到的 name其实就是 beanAdvisor 的 id通过这个 nameid
// 我们就可以从 IoC 容器中获取对应的实例化 beanAdvisor
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
@ -770,7 +823,7 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
}
else {
//对当前的 factoryBean 进行类型判断,是属于单例 bean 还是原型 bean
// 对当前的 factoryBean 进行类型判断,是属于 单例bean还是 原型bean
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// advisor 在文件中配置为 bean所以这里通过 beanFactory 的 getBean()方法
@ -787,22 +840,25 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
}
}
}
this.advisorChainInitialized = true;
}
}
```
注意Advisor 本身就被配置为 bean所以它的获取也是通过 IoC容器 获得的。
### 3.6、Advice 通知的实现
### 3.6 Advice 通知的实现
从 DefaultAdvisorChainFactory 类中的 getInterceptorsAndDynamicInterceptionAdvice() 方法我们可以看到,其通过 AdvisorAdapterRegistry 实例对象的 getInterceptors() 方法,利用配置的 advisor 完成了对拦截器的适配和注册。
```java
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class targetClass) {
//advisor 链已经在传进来的 config 中持有了,这里可以直接使用
//advisor 中持有切面 和 增强行为的引用
// Advisor链 已经在传进来的 config 中持有了,这里可以直接使用
// Advisor 中持有 切面Pointcut 和 增强行为Advice 的引用
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
// 判断 config 中的 Advisors 是否符合配置要求
boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
@ -847,6 +903,7 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
}
return interceptorList;
}
}
```
DefaultAdvisorAdapterRegistry 的 getInterceptors()方法 封装了 advice 织入实现的入口。
@ -855,7 +912,7 @@ DefaultAdvisorAdapterRegistry 的 getInterceptors() 方法封装了 advice 织
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
// 持有 AdvisorAdapter 的 list这个 list 中的 AdvisorAdapter 与
//实现 spring AOP 的 advice 增强功能相对应
// 实现 Spring AOP 的 advice 增强功能相对应
private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);
/**
@ -903,8 +960,7 @@ public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Se
// 对通知进行适配,使用已经配置好的三种 AdvisorAdapter然后从对应的
// adapter 中取出封装好的 AOP 编织功能的拦截器
for (AdvisorAdapter adapter : this.adapters) {
//adapter.supportsAdvice(advice) 方法中对 advice 的
//类型进行校验
// adapter.supportsAdvice(advice) 方法中对 advice 的类型进行校验
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
@ -917,8 +973,7 @@ public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Se
}
```
从 DefaultAdvisorAdapterRegistry 的实现中可以看到,其使用了一系列的 AdviceAdapter 适配器MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter它们完全和 advice 的类型
一一对应,它们都是实现了 AdviceAdapter 接口的同一层次类,各自承担着不同的适配任务,一对一地服务于不同的 advice 实现。下面我们以 MethodBeforeAdviceAdapter 为例,看一下其源码实现。
从 DefaultAdvisorAdapterRegistry 的实现中可以看到,其使用了一系列的 AdviceAdapter 适配器MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter它们完全和 Advice 的类型一一对应,它们都是实现了 AdviceAdapter 接口的同一层次类,各自承担着不同的适配任务,一对一地服务于不同的 Advice 实现。下面我们以 MethodBeforeAdviceAdapter 为例,看一下其源码实现。
```java
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@ -931,11 +986,10 @@ class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
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 {
@ -951,21 +1005,20 @@ public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Seriali
}
/**
* 这个 invoke 方法是拦截器的回调方法,会在代理对象的方法被调用时触发回调
* 这个 invoke()方法 是拦截器的回调方法,会在代理对象的方法被调用时触发回调
*/
public Object invoke(MethodInvocation mi) throws Throwable {
//首先触发了 advice 的 before() 方法的回调
// 首先触发了 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() 回调,其它两个以此类推,这里就不逐一分析咯。
另外,可以结合我 GitHub 上对 spring 框架源码的阅读及个人理解一起看,会更有助于各位开发大佬理解,如果对你们有帮助的,还望各位老爷 watchstarfork素质三连一波地址https://github.com/AmyliaY/spring-aop-reading
回顾一下之前的代码,在 AopProxy代理对象 触发的 ReflectiveMethodInvocation 的 proceed() 中,在取得 拦截器interceptor 后调用了其 invoke()方法。按照 AOP 的配置规则ReflectiveMethodInvocation 触发的拦截器 invoke()回调,最终会根据 Advice 类型的不同,触发 Spring 对不同的 Advice 的拦截器封装,比如 MethodBeforeAdvice 最终会触发 MethodBeforeAdviceInterceptor 的 invoke()回调,其它两个以此类推,这里就不逐一分析咯。
另外,可以结合我 GitHub 上对 Spring框架源码 的阅读及个人理解一起看,会更有助于各位开发大佬理解,如果本内容对你们有帮助的,还望各位同学 watchstarfork素质三连一波地址
https://github.com/AmyliaY/spring-aop-reading

@ -1,7 +1,7 @@
最近在看spring AOP部分的源码所以对JDK动态代理具体是如何实现的这件事产生了很高的兴趣而且能从源码上了解这个原理的话也有助于对spring-aop模块的理解。话不多说上代码。
最近在看 Spring AOP 部分的源码所以对JDK动态代理具体是如何实现的这件事产生了很高的兴趣而且能从源码上了解这个原理的话也有助于对 spring-aop 模块的理解。话不多说,上代码。
```java
/**
* 一般会使用实现了 InvocationHandler 的类作为代理对象的生产工厂,
* 一般会使用实现了 InvocationHandler接口 的类作为代理对象的生产工厂,
* 并且通过持有 被代理对象target来在 invoke()方法 中对被代理对象的目标方法进行调用和增强,
* 这些我们都能通过下面这段代码看懂但代理对象是如何生成的invoke()方法 又是如何被调用的呢?
*/
@ -36,7 +36,6 @@ public class TargetObject implements MyInterface {
@Override
public void play() {
System.out.println("妲己,陪你玩 ~");
}
}
@ -93,10 +92,9 @@ public class ProxyTest {
}
/**
* 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) {

@ -1,17 +1,21 @@
这篇文章分享一下 spring IoC 容器初始化第三部分的代码,也就是将前面解析得到的 BeanDefinition 注册进 IoC 容器,其实就是存入一个 ConcurrentHashMap<String, BeanDefinition> 中。
PS可以结合我 GitHub 上对 spring 框架源码的翻译注解一起看,会更有助于各位同学理解,地址:
## 前言
这篇文章分享一下 spring IoC 容器初始化第三部分的代码,也就是将前面解析出来的 BeanDefinition对象 注册进 IoC 容器,其实就是存入一个 ConcurrentHashMap<String, BeanDefinition> 中。
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 对象的普通元素
/**
* 将 .xml 文件中的元素解析成 BeanDefinition对象并注册到 IoC容器 中
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// BeanDefinitionHolder 是对 BeanDefinition 的封装,即 BeanDefinition 的封装类
// BeanDefinitionHolder 是对 BeanDefinition 的进一步封装,它持有一个 BeanDefinition 对象 及其对应
// 的 beanName、aliases别名。
// 对 Document 对象中 <Bean> 元素的解析由 BeanDefinitionParserDelegate 实现
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
@ -20,7 +24,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
try {
/**
*
* 向 Spring IoC 容器注册解析 BeanDefinition,这是 BeanDefinition 向 IoC 容器注册的入口
* 向 IoC 容器注册解析完成的 BeanDefinition对象,这是 BeanDefinition 向 IoC 容器注册的入口
*
*/
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
@ -29,28 +33,30 @@ spring-context https://github.com/AmyliaY/spring-context-reading
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 在完成向 Spring IOC 容器注册解析得到的 Bean 定义之后,发送注册事件
// 在完成向 IOC容器 注册 BeanDefinition对象 之后,发送注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
```
## 2、BeanDefinitionReaderUtils 的 registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) 方法
接着看一下 BeanDefinitionReaderUtils 的 registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) 方法
```java
// 将解析的 BeanDefinitionHold 注册到容器中
/**
* 将解析到的 BeanDefinition对象 注册到 IoC容器
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 获取解析的 BeanDefinition 的名称
// 获取解析的 <bean>元素 的名称 beanName
String beanName = definitionHolder.getBeanName();
/**
*
* 开始向 IOC 容器注册 BeanDefinition
* 开始向 IoC容器 注册 BeanDefinition对象
*
*/
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 如果解析的 BeanDefinition 有别名,向容器为其注册别名
// 如果解析的 <bean>元素 有别名alias向容器中注册别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String aliase : aliases) {
@ -59,16 +65,27 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
```
## 3、BeanDefinitionRegistry 中的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法在 DefaultListableBeanFactory 实现类中的具体实现
BeanDefinitionRegistry 中的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法在 DefaultListableBeanFactory 实现类中的具体实现
```java
// 向 IoC 容器注册解析的 BeanDefinito
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
/** 按注册顺序排列的 beanDefinition名称列表(即 beanName) */
private final List<String> beanDefinitionNames = new ArrayList<String>();
/** IoC容器 的实际体现key --> beanNamevalue --> BeanDefinition对象 */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(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
// 校验解析的 BeanDefiniton对象
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
@ -83,34 +100,34 @@ spring-context https://github.com/AmyliaY/spring-context-reading
synchronized (this.beanDefinitionMap) {
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
// 检查是否有同名的 BeanDefinition 已经在 IOC 容器中注册,如果已经注册,
// 并且不允许覆盖已注册的 BeanDefinition则抛出注册失败异常
// allowBeanDefinitionOverriding 默认为 true
// 检查是否有同名(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后注册的覆盖先注册的
// 如果允许覆盖同名的 bean后注册的会覆盖先注册的
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {// IOC 容器中没有已经注册同名的 Bean按正常注册流程注册
// 若该 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);
}
```
## 最后看一下 spring 的 IoC 容器在代码中最直接的体现
```java
// 存储注册信息的 BeanDefinition 集合,也就是所谓的 IoC 容器
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
}
```

@ -1,53 +1,55 @@
前面我们主要分析了 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 属性为 falseSpring 在 IoC容器 初始化会自动调用此 bean 的 getBean() 方法,提前完成依赖注入。总的来说,想提高运行时获取 bean 的效率,可以考虑配置此属性。
下面我将分别解读这两种依赖注入的触发方式,先看 getBean() 的,因为 lazy-init 最后也是通过调用 getBean 完成的依赖注入。
PS可以结合我 GitHub 上对 spring 框架源码的阅读及个人理解一起看,会更有助于各位开发姥爷理解,地址:
下面我将分别解读这两种依赖注入的触发方式,先看 getBean() 的,因为 lazy-init 最后也是通过调用 getBean() 完成的依赖注入。
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() 具体实现
## 正文
首先看一下 AbstractBeanFactory 中的 getBean() 系列方法及 doGetBean() 具体实现。
```java
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
//---------------------------------------------------------------------
// BeanFactory 接口的实现,下列的 getBean() 方法不论是哪种重载,最后都会走
// doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) 的具体实现
//---------------------------------------------------------------------
// 获取 IOC 容器中指定名称的 Bean
// 获取 IoC容器 中指定名称的 bean
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
// 获取 IOC 容器中指定名称和类型的 Bean
// 获取 IoC容器 中指定名称和类型的 bean
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
// 获取 IOC 容器中指定名称和参数的 Bean
// 获取 IoC容器 中指定名称和参数的 bean
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
// 获取 IOC 容器中指定名称、类型和参数的 Bean
// 获取 IoC容器 中指定名称、类型和参数的 bean
public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
return doGetBean(name, requiredType, args, false);
}
// 真正实现向 IOC 容器获取 Bean 的功能,也是触发依赖注入 (DI) 功能的地方
// 真正实现向 IoC容器 获取 bean 的功能,也是触发 依赖注入(DI) 的地方
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args,
boolean typeCheckOnly) throws BeansException {
// 根据用户指定的名称获取 IoC 容器中与 BeanDefinition 对应的 beanName
// 如果指定的是别名,则将别名转换为规范的 beanName
// 根据用户给定的名称(也可能是别名alias) 获取 IoC容器 中与 BeanDefinition 唯一对应的 beanName
final String beanName = transformedBeanName(name);
Object bean;
// 先查看缓存中是否有对应的,已创建的单例 Bean对于单例 Bean整个 IOC 容器中只创建一次
// 根据 beanName 查看缓存中是否有已实例化的 单例bean对于 单例bean整个 IoC容器 只创建一次
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
@ -59,12 +61,12 @@ spring-context https://github.com/AmyliaY/spring-context-reading
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 获取给定 Bean 的实例对象,主要是完成 FactoryBean 的相关处理
// 注意BeanFactory 本质上是一个 IoC 容器,而 FactoryBean 是 IoC 容器中一种特殊的工厂 bean
// 能够生产其他对象,注意两者之间的区别
// 获取给定 bean 的实例对象,主要是完成 FactoryBean 的相关处理
// 注意BeanFactory 是一个 IoC容器它保存了 bean 的基本配置信息。
// 而 FactoryBean 是 IoC容器 中一种特殊的 bean它能够实例化 bean对象,注意两者之间的区别
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 如果应用程序要获取的 bean 还未创建
else {
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
@ -75,7 +77,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
// 如果当前容器中没有指定的 bean且当前容器的父容器不为空
// 则从父容器中去找,如果父容器也没有,则沿着当前容器的继承体系一直向上查找
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 解析指定 Bean 名称的原始名称
// 根据用户传入的 name(有可能是别名alias),获取唯一标识的 beanName
String nameToLookup = originalBeanName(name);
if (args != null) {
// 委派父级容器根据指定名称和显式的参数查找
@ -87,9 +89,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 创建的 Bean 是否需要进行类型验证,一般不需要
// 创建的 bean 是否需要进行类型验证,一般不需要
if (!typeCheckOnly) {
// 向容器标记指定的 Bean 已经被创建
// 向容器标记指定的 bean 已经被创建
markBeanAsCreated(beanName);
}
@ -98,26 +100,28 @@ spring-context https://github.com/AmyliaY/spring-context-reading
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 获取当前 Bean 依赖的所有 Bean下面的 getBean(dependsOnBean) 方法会触发 getBean() 的递归调用,
// 直到取到一个不依赖任何其它 bean 的 bean 为止
// 获取当前 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 所依赖的 bean
// 递归调用 getBean() 方法,从末级节点依次实例化 依赖的bean
getBean(dependsOnBean);
// 把当前 bean 所依赖的 bean 进行注入
// 把 当前bean 直接依赖的bean 进行注册
//(也就是通过 setter 或构造方法将依赖的 bean 赋值给当前 bean 对应的属性)
registerDependentBean(dependsOnBean, beanName);
}
}
// 创建单例模式 bean 的实例对象
// 如果当前 bean 是单例的
if (mbd.isSingleton()) {
// 这里使用了一个匿名内部类,创建 Bean 实例对象,并且注册给所依赖的对象
// 这里使用了一个匿名内部类,创建 bean实例对象
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
// 创建一个指定 Bean 实例对象,如果有父级继承,则合并子类和父类的定义
// 根据给定的 beanName 及 RootBeanDefinition对象创建 bean 实例对象
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
@ -126,41 +130,42 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
});
// 获取给定 Bean 的实例对象
// 获取给定 bean 的实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// IoC 容器创建原型模式 Bean 实例对象
// 创建原型模式的 bean 实例对象
else if (mbd.isPrototype()) {
// 原型模式 (Prototype) 是每次都会创建一个新的对象
// 原型模式 (Prototype) 每次都会创建一个新的对象
Object prototypeInstance = null;
try {
// 回调 beforePrototypeCreation 方法,默认的功能是注册当前创建的原型对象
// 回调 beforePrototypeCreation() 方法,默认的功能是注册当前创建的原型对象
beforePrototypeCreation(beanName);
// 创建指定 Bean 对象实例
// 创建指定 bean 对象实例
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// 回调 afterPrototypeCreation 方法,默认的功能告诉 IoC 容器指定 Bean 的原型对象不再创建了
// 回调 afterPrototypeCreation() 方法,默认的功能是告诉 IoC容器
// 指定 bean 的原型对象不再创建了
afterPrototypeCreation(beanName);
}
// 获取给定 Bean 的实例对象
// 获取给定 bean 的实例对象
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 要创建的 Bean 既不是单例模式,也不是原型模式,则根据 Bean 定义资源
// 配置的生命周期范围,选择实例化 Bean 的合适方法,这种在 Web 应用程序中
// 要创建的 bean 既不是单例模式,也不是原型模式,则根据该 bean元素 在配置文件
// 配置的生命周期范围,选择实例化 bean 的合适方法,这种在 Web 应用程序中
// 比较常用request、session、application 等的生命周期
else {
// 获取此 bean 生命周期的范围
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
// Bean 定义资源中没有配置生命周期范围,则 Bean 定义不合法
// bean 定义资源中没有配置生命周期范围,则该 bean 的配置不合法
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
// 这里又使用了一个匿名内部类,获取一个指定生命周期范围的实例
// 这里又使用了一个 ObjectFactory 的匿名内部类,获取一个指定生命周期范围的实例
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
@ -172,7 +177,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
});
// 获取给定 Bean 的实例对象
// 获取给定 bean 的实例对象
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
@ -189,7 +194,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 对创建的 bean 实例对象进行非空验证和类型检查,如果没问题就返回这个已经完成依赖注入的 bean
// 对要返回的 bean实例对象 进行非空验证和类型检查,如果没问题就返回这个已经完成 依赖注入的bean
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
@ -204,12 +209,16 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
return (T) bean;
}
}
```
总的来说getBean() 方法是依赖注入的起点,之后会调用 createBean(),根据 BeanDefinition 的定义生成 bean 对象,下面我们看看 AbstractBeanFactory 的子类 AbstractAutowireCapableBeanFactory 中对 createBean() 的具体实现。
## 2、AbstractAutowireCapableBeanFactory 中的 createBean() 和 doCreateBean() 具体实现
总的来说getBean() 方法是依赖注入的起点,之后会调用 createBean(),根据之前解析生成的 BeanDefinition对象 生成 bean 对象,下面我们看看 AbstractBeanFactory 的子类 AbstractAutowireCapableBeanFactory 中对 createBean() 的具体实现。
```java
// 创建指定的 bean 实例对象
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
/**
* 创建指定的 bean 实例对象
*/
@Override
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
@ -217,11 +226,11 @@ spring-context https://github.com/AmyliaY/spring-context-reading
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
// 判断需要创建的 Bean 是否可以实例化,是否可以通过当前的类加载器加载
// 判断需要创建的 bean 是否可实例化,是否可以通过当前的类加载器加载
resolveBeanClass(mbd, beanName);
try {
// 校验和准备 Bean 中的方法覆盖
// 校验和准备 bean 中的方法覆盖
mbd.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
@ -230,7 +239,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
try {
// 如果 Bean 配置了后置处理器 PostProcessor则这里返回一个 proxy 代理对象
// 如果 bean 配置了后置处理器 PostProcessor则这里返回一个 proxy 代理对象
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
@ -241,7 +250,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
"BeanPostProcessor before instantiation of bean failed", ex);
}
// 创建 Bean 实例对象的具体实现
// 创建 bean 实例对象的具体实现
Object beanInstance = doCreateBean(beanName, mbd, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
@ -249,17 +258,17 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return beanInstance;
}
// 创建 Bean 实例对象的具体实现spring 中以 do 开头的都是方法的具体实现
/**
* 创建 bean 实例对象的具体实现Spring 中以 do 开头的都是方法的具体实现
*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// 封装被创建的 Bean 对象
BeanWrapper instanceWrapper = null;
// 如果这个 bean 是单例的,则从缓存中获取这个 BeanWrapper 实例并清除
// 如果这个 bean 是单例的,则从缓存中获取这个 beanName 对应的 BeanWrapper实例并清除
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
/**
*
* 创建实例对象
@ -280,7 +289,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 向容器中缓存单例模式的 Bean 对象,以防循环引用
// 向容器中缓存单例模式的 bean 对象,以防循环引用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
@ -288,7 +297,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用
// 这里是一个 ObjectFactory 的匿名内部类,为了防止循环引用,尽早持有对象的引用
addSingletonFactory(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
@ -296,8 +305,8 @@ spring-context https://github.com/AmyliaY/spring-context-reading
});
}
// Bean 对象的初始化,依赖注入在此触发
// 这个 exposedObject 在初始化完成之后,将返回作为依赖注入完成后的 Bean
// bean 对象的初始化,依赖注入在此触发
// 这个 exposedObject 在初始化完成之后,将返回作为依赖注入完成后的 bean
Object exposedObject = bean;
try {
/**
@ -307,9 +316,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
*/
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// 初始化 Bean 对象
// 在对 Bean 实例对象生成和依赖注入完成以后,开始对 Bean 实例对象
// 进行初始化 ,为 Bean 实例对象应用 BeanPostProcessor 后置处理器
// 初始化 bean对象
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
@ -323,21 +330,21 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
if (earlySingletonExposure) {
// 获取指定名称的已注册的单例模式 Bean 对象
// 获取指定名称的已注册的 单例bean对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 如果根据名称获取的已注册的 Bean 和正在实例化的 Bean 是同一个
// 如果根据名称获取的已注册的 bean 和正在实例化的 bean 是同一个
if (exposedObject == bean) {
// 当前实例化的 Bean 初始化完成
// 当前实例化的 bean 初始化完成
exposedObject = earlySingletonReference;
}
// 如果当前 Bean 依赖其他 Bean并且当发生循环引用时不允许新创建实例对象
// 如果当前 bean 依赖其他 bean并且当发生循环引用时不允许新创建实例对象
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
// 获取当前 Bean 所依赖的其他 Bean
// 获取当前 bean 所依赖的其他 bean
for (String dependentBean : dependentBeans) {
// 对依赖 Bean 进行类型检查
// 对 依赖bean 进行类型检查
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
@ -356,7 +363,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
try {
// 注册完成依赖注入的 Bean
// 注册 成完依赖注入的bean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
@ -366,23 +373,23 @@ spring-context https://github.com/AmyliaY/spring-context-reading
// 为应用返回所需要的实例对象
return exposedObject;
}
}
```
从源码中可以看到 createBeanInstance() 和 populateBean() 这两个方法与依赖注入的实现非常密切createBeanInstance() 方法中生成了 Bean 所包含的 Java 对象populateBean() 方法对这些生成的 bean 对象之间的依赖关系进行了处理。下面我们先看一下 createBeanInstance() 方法的实现。
## 3、createBeanInstance() 方法的具体实现
从源码中可以看到 createBeanInstance() 和 populateBean() 这两个方法与依赖注入的实现非常密切createBeanInstance() 方法中生成了 bean 所包含的 Java 对象populateBean() 方法对这些生成的 bean 对象之间的依赖关系进行了处理。下面我们先看一下 createBeanInstance() 方法的实现。
```java
// 创建 Bean 的实例对象
/**
* 创建 bean 的实例对象
*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 检查确认 Bean 是可实例化的
// 检查确认 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 进行实例化
// 使用 RootBeanDefinition对象 中的 factoryMethodName 对 bean 进行实例化
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
@ -400,8 +407,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
if (resolved) {
if (autowireNecessary) {
// 配置了自动装配属性,使用容器的自动装配实例化,
// 即,根据参数类型匹配 Bean 的构造方法
// 配置了自动装配属性,使用容器的自动装配实例化,即,根据参数类型匹配 bean 的构造方法
return autowireConstructor(beanName, mbd, null, null);
}
else {
@ -410,7 +416,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 使用 Bean 的构造方法进行实例化
// 使用 bean 的构造方法进行实例化
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
@ -422,14 +428,14 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return instantiateBean(beanName, mbd);
}
// 使用默认的无参构造方法实例化 Bean 对象
// 使用默认的无参构造方法实例化 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<Object>() {
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
@ -437,10 +443,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}, getAccessControlContext());
}
else {
/**
*
* 使用初始化策略实例化 Bean 对象
* 使用初始化策略实例化 bean 对象
*
*/
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
@ -453,23 +458,22 @@ spring-context https://github.com/AmyliaY/spring-context-reading
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 class SimpleInstantiationStrategy implements InstantiationStrategy {
// 使用初始化策略实例化 bean对象
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
// 如果 Bean 定义中没有方法覆盖,则使用 Java 的反射机制实例化对象,否则使用 CGLIB
// 如果 配置的bean 中没有方法覆盖,则使用 Java 的反射机制实例化对象,否则使用 CGLIB
if (beanDefinition.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (beanDefinition.constructorArgumentLock) {
// 获取对象的构造方法或生成对象的工厂方法对 bean 进行实例化
// 获取对象的构造方法对 bean 进行实例化
constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
// 如果前面没有获取到构造方法,则通过反射获取
if (constructorToUse == null) {
// 使用 JDK 的反射机制,判断要实例化的 Bean 是否是接口
// 使用 JDK 的反射机制,判断要实例化的 bean 是否是接口
final Class clazz = beanDefinition.getBeanClass();
// 如果 clazz 是一个接口,直接抛出异常
if (clazz.isInterface()) {
@ -477,7 +481,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
try {
if (System.getSecurityManager() != null) {
// 这里是一个匿名内置类,使用反射机制获取 Bean 的构造方法
// 这里使用了一个 PrivilegedExceptionAction 的匿名内部类,使用反射机制获取 bean 的构造方法
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
public Constructor run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
@ -494,7 +498,8 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
}
// 使用 BeanUtils 实例化,通过反射机制调用”构造方法.newInstance(arg)”来进行实例化
// 根据传入的 Constructor在 BeanUtils 中调用该 Constructor 的
// newInstance(Object...) 方法,实例化指定对象
return BeanUtils.instantiateClass(constructorToUse);
}
else {
@ -507,17 +512,19 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return instantiateWithMethodInjection(beanDefinition, beanName, owner);
}
}
}
```
在 SimpleInstantiationStrategy 的子类 CglibSubclassingInstantiationStrategy 中可以看到使用 CGLIB 进行实例化的源码实现。
## 5、CglibSubclassingInstantiationStrategy 中使用 CGLIB 进行实例化的源码实现
```java
// 下面两个方法都通过实例化自己的私有静态内部类 CglibSubclassCreator
// 然后调用该内部类对象的实例化方法 instantiate() 完成实例化
public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
/**
* 下面两个方法都通过实例化自己的私有静态内部类 CglibSubclassCreator
* 然后调用该内部类对象的实例化方法 instantiate() 完成实例化
*/
protected Object instantiateWithMethodInjection(
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
// 必须生成 cglib 子类
return new CglibSubclassCreator(beanDefinition, owner).instantiate(null, null);
}
@ -545,11 +552,11 @@ spring-context https://github.com/AmyliaY/spring-context-reading
this.owner = owner;
}
// 使用 CGLIB 进行 Bean 对象实例化
// 使用 CGLIB 进行 bean对象 实例化
public Object instantiate(Constructor ctor, Object[] args) {
// 实例化 Enhancer对象并为 Enhancer对象 设置父类,生成 Java 对象的参数,比如:基类、回调方法等
Enhancer enhancer = new Enhancer();
// 将 Bean 本身作为其父类
// 将 bean 本身作为其父类
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
enhancer.setCallbackFilter(new CallbackFilterImpl());
enhancer.setCallbacks(new Callback[] {
@ -558,33 +565,38 @@ spring-context https://github.com/AmyliaY/spring-context-reading
new ReplaceOverrideMethodInterceptor()
});
// 使用 CGLIB 的 create 方法生成实例对象
// 使用 CGLIB 的 create() 方法生成实例对象
return (ctor == null) ? enhancer.create() : enhancer.create(ctor.getParameterTypes(), args);
}
}
}
```
至此,完成了 bean 对象的实例化,然后就可以根据解析得到的 BeanDefinition 完成对各个属性的赋值处理,也就是依赖注入。这个实现方法就是前面 AbstractAutowireCapableBeanFactory 类中的 populateBean() 方法。
## 6、AbstractAutowireCapableBeanFactory 中的 populateBean(),完成依赖注入
至此,完成了 bean对象 的实例化,然后就可以根据解析得到的 BeanDefinition对象 完成对各个属性的赋值处理,也就是依赖注入。这个实现方法就是前面 AbstractAutowireCapableBeanFactory 类中的 populateBean() 方法。
```java
// 为属性赋值,完成依赖注入
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
/**
* 为属性赋值,完成依赖注入
*/
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
// 获取 BeanDefinition 中设置的 property这些 property 来自对 BeanDefinition 的解析
// 获取 RootBeanDefinition 中设置的 属性值PropertyValues这些属性值来自对
// .xml 文件中 bean元素 的解析
PropertyValues pvs = mbd.getPropertyValues();
// 如果实例对象为 null而要注入的属性值不为空则抛出下述异常
// 如果 BeanWrapper对象 为 null而要注入的属性值不为空则抛出下述异常
if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// 实例对象为 null属性值也为空不需要设置属性值直接返回
// BeanWrapper对象 为 null属性值也为空不需要设置属性值直接返回
return;
}
}
// 在设置属性之前调用 Bean 的 PostProcessor 后置处理器
// 在设置属性之前调用 bean 的 PostProcessor 后置处理器
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
@ -608,12 +620,12 @@ spring-context https://github.com/AmyliaY/spring-context-reading
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 对 autowire 自动装配的处理,根据 Bean 名称自动装配注入
// 对 autowire 自动装配的处理,根据 bean 名称自动装配注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 根据 Bean 类型自动装配注入
// 根据 bean 类型自动装配注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
@ -621,9 +633,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
pvs = newPvs;
}
// 检查容器是否持有用于处理单例模式 Bean 关闭时的后置处理器
// 检查容器是否持有用于处理单例模式 bean 关闭时的后置处理器
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// Bean 实例对象没有依赖,即没有继承基类
// bean实例对象 没有依赖,即没有继承基类
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
@ -654,7 +666,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
applyPropertyValues(beanName, mbd, bw, pvs);
}
// 解析并注入依赖属性的过程
/**
* 解析并注入依赖属性的过程
*/
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs == null || pvs.isEmpty()) {
return;
@ -697,7 +711,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
if (converter == null) {
converter = bw;
}
// 创建一个 BeanDefinition 属性值解析器,将 Bean 定义中的属性值解析为 Bean 实例对象的实际值
// 创建一个 BeanDefinition 属性值解析器,将 BeanDefinition 中的属性值解析为 bean 实例对象的实际值
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// 为属性的解析值创建一个副本,最后将属性值注入到实例对象中
@ -771,15 +785,17 @@ spring-context https://github.com/AmyliaY/spring-context-reading
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
}
```
## 7、BeanDefinitionValueResolver 中解析属性值,对注入类型进行转换的具体实现
BeanDefinitionValueResolver 中解析属性值,对注入类型进行转换的具体实现。
```java
// 解析属性值,对注入类型进行转换
class BeanDefinitionValueResolver {
/**
* 解析属性值,对注入类型进行转换
*/
public Object resolveValueIfNecessary(Object argName, Object value) {
// 对引用类型的属性进行解析RuntimeBeanReference 是在对
// BeanDefinition 进行解析时生成的数据对象
// 对引用类型的属性进行解析RuntimeBeanReference 是在对 BeanDefinition 进行解析时生成的数据对象
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
/**
@ -790,7 +806,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return resolveReference(argName, ref);
}
// 对属性值是引用容器中另一个 Bean 名称的解析
// 对属性值是引用容器中另一个 bean 名称的解析
else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(evaluate(refName));
@ -800,7 +816,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
return refName;
}
// 对 BeanDefinitionHolder 类型属性的解析,主要是 Bean 中的内部类
// 对 BeanDefinitionHolder 类型属性的解析,主要是 bean 中的内部类
else if (value instanceof BeanDefinitionHolder) {
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
@ -898,10 +914,12 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 解析引用类型的属性值
/**
* 解析引用类型的属性值
*/
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
// 获取引用的 BeanName
// 获取 所引用bean 的 beanName
String refName = ref.getBeanName();
refName = String.valueOf(evaluate(refName));
// 如果引用的对象在父容器中,则从父容器中获取指定的引用对象
@ -914,11 +932,11 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
return this.beanFactory.getParentBeanFactory().getBean(refName);
}
// 从当前的容器中获取指定的引用 Bean 对象,如果指定的 Bean 没有被实例化
// 则会递归触发引用 Bean 的初始化和依赖注入
// 从当前的容器中获取指定的引用 bean对象如果指定的 bean 没有被实例化
// 则会递归触发引用 bean 的初始化和依赖注入
else {
Object bean = this.beanFactory.getBean(refName);
// 为 refName 对应的 BeanDefinition 注入依赖的 Bean
// 为 refName对应的bean 注入 它所依赖的bean
this.beanFactory.registerDependentBean(refName, this.beanName);
return bean;
}
@ -930,7 +948,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 解析 array 类型的属性
/**
* 解析 array 类型的属性
*/
private Object resolveManagedArray(Object argName, List<?> ml, Class<?> elementType) {
// 创建一个指定类型的数组,用于存放和返回解析后的数组
Object resolved = Array.newInstance(elementType, ml.size());
@ -942,7 +962,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return resolved;
}
// 解析 list 类型的属性
/**
* 解析 list 类型的属性
*/
private List resolveManagedList(Object argName, List<?> ml) {
List<Object> resolved = new ArrayList<Object>(ml.size());
for (int i = 0; i < ml.size(); i++) {
@ -953,7 +975,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return resolved;
}
// 解析 set 类型的属性
/**
* 解析 set 类型的属性
*/
private Set resolveManagedSet(Object argName, Set<?> ms) {
Set<Object> resolved = new LinkedHashSet<Object>(ms.size());
int i = 0;
@ -965,7 +989,9 @@ spring-context https://github.com/AmyliaY/spring-context-reading
return resolved;
}
// 解析 map 类型的属性
/**
* 解析 map 类型的属性
*/
private Map resolveManagedMap(Object argName, Map<?, ?> mm) {
Map<Object, Object> resolved = new LinkedHashMap<Object, Object>(mm.size());
// 递归解析 map 中每一个元素的 key 和 value
@ -977,11 +1003,24 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
return resolved;
}
}
```
至此,已经为依赖注入做好了准备,下面就该将 bean 对象设置到它所依赖的另一个 bean 的属性中去。AbstractPropertyAccessor 和其子类 BeanWrapperImpl 完成了依赖注入的详细过程。
## 8、AbstractPropertyAccessor 中的实现
至此,已经为依赖注入做好了准备,下面就该将 bean对象 设置到它所依赖的另一个 bean 的属性中去。AbstractPropertyAccessor 和其子类 BeanWrapperImpl 完成了依赖注入的详细过程。先看一下 AbstractPropertyAccessor 中的实现。
```java
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);
}
@ -996,7 +1035,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
try {
/**
*
* 走 BeanWrapperImpl 中的实现,也是 bean 属性值注入具体实现的入口
* 该方法走 BeanWrapperImpl 中的实现,这是 bean属性值注入 具体实现的入口
*
*/
setPropertyValue(pv);
@ -1019,18 +1058,20 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
// 如果遇到个别异常,则抛出复合异常
// 如果出现 PropertyAccessException 异常,则将这些异常积累起来放到一个集合中,然后一次性抛出!!!
// 这种抛异常的方式 在实际的开发中也时常使用,可以好好看一下,对比一下
if (propertyAccessExceptions != null) {
PropertyAccessException[] paeArray =
propertyAccessExceptions.toArray(new PropertyAccessException[propertyAccessExceptions.size()]);
throw new PropertyBatchUpdateException(paeArray);
}
}
}
```
## 9、BeanWrapperImpl 中的实现
最后看一下 BeanWrapperImpl 中的实现。
```java
public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWrapper {
@Override
public void setPropertyValue(PropertyValue pv) throws BeansException {
// PropertyTokenHolder 是一个用于内部使用的内部类
@ -1064,17 +1105,17 @@ spring-context https://github.com/AmyliaY/spring-context-reading
/**
*
* 实现属性值依赖注入的具体实现
* 依赖注入将某个bean所依赖的值 注入到这个bean中 的具体实现
*
*/
@SuppressWarnings("unchecked")
private void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
// PropertyTokenHolder 主要保存属性的名称、路径、以及集合的 size 等信息
// PropertyTokenHolder 是定义在 BeanWrapperImpl 中的内部类,主要保存属性的名称、路径、
// 以及集合的 size 等信息
String propertyName = tokens.canonicalName;
String actualName = tokens.actualName;
// 对集合类型的属性注入
// keys 是用来保存集合类型属性的 size
// 对集合类型的属性注入PropertyTokenHolder 的 keys 是用来保存集合类型属性的 size
if (tokens.keys != null) {
// 将属性信息从 tokens 拷贝到 getterTokens
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
@ -1284,7 +1325,7 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
// 根据 Java 的内省机制,获取属性的 setter(写方法) 方法
// 根据 Java 的内省机制,获取属性的 setter方法
final Method writeMethod = (pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodForActualAccess() :
pd.getWriteMethod());
@ -1343,27 +1384,35 @@ spring-context https://github.com/AmyliaY/spring-context-reading
}
}
}
}
```
终于完成了对 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
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
/**
* 容器初始化的过程BeanDefinition 的 Resource 定位、BeanDefinition 的载入、BeanDefinition 的注册。
* BeanDefinition 的载入和 bean 的依赖注入是两个独立的过程,依赖注入一般发生在 应用第一次通过 getBean() 方法从容器获取 bean 时。
* 容器初始化的过程:
* 1、根据指定规则扫描指定目录获取所有 用于配置bean的配置文件
* 2、根据 Spring定义的规则解析配置文件中的各个元素将其封装成 IoC容器 可以装载的 BeanDefinition对象
* 3、将封装好的 BeanDefinition 注册进 IoC容器。
*
* 另外需要注意的是IoC 容器有一个预实例化的配置(即,将 AbstractBeanDefinition 中的 lazyInit 属性设为 true使用户可以对容器的初始化
* 过程做一个微小的调控lazyInit 设为 true 的 bean 将在容器初始化时进行依赖注入,而不会等到 getBean() 方法调用时才进行
* IoC容器的初始化 和 bean的依赖注入 是两个独立的过程,依赖注入一般发生在应用第一次通过 getBean()方法
* 从容器获取 bean 时。
* 另外需要注意的是IoC容器 有一个预实例化的配置(即,将 <bean>元素 的 lazyInit属性 设为 false
* 使该 <bean>元素对应的 bean可以提前实例化而不用等到调用 getBean()方法 时才开始实例化。
*/
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 调用容器准备刷新的方法,获取容器的当前时间,同时给容器设置同步标识
prepareRefresh();
// 告诉子类启动 refreshBeanFactory() 方法Bean 定义资源文件的载入从子类的 refreshBeanFactory() 方法启动开始
// 告诉子类启动 refreshBeanFactory() 方法BeanDefinition 资源文件的载入从子类的
// refreshBeanFactory() 方法启动开始
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 为 BeanFactory 配置容器特性,例如类加载器、事件处理器等
@ -1373,7 +1422,7 @@ lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 B
// 为容器的某些子类指定特殊的 BeanPost 事件处理器
postProcessBeanFactory(beanFactory);
// 调用所有注册的 BeanFactoryPostProcessor 的 Bean
// 调用所有注册的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 为 BeanFactory 注册 BeanPost 事件处理器.
@ -1394,7 +1443,7 @@ lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 B
/**
*
* 初始化 Bean并对 lazy-init 属性进行处理
* 对配置了 lazy-init属性为true的bean 进行预实例化
*
*/
finishBeanFactoryInitialization(beanFactory);
@ -1415,16 +1464,18 @@ lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 B
}
}
// 对配置了 lazy-init 属性的 Bean 进行预实例化处理
/**
* 对配置了 lazy-init属性为true的bean 进行预实例化
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 这是 Spring3 以后新加的代码,为容器指定一个转换服务 (ConversionService)
// 在对某些 Bean 属性进行转换时使用
// 在对某些 bean 属性进行转换时使用
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
/**
*
* 在这里调用了 getBean() 方法,触发依赖注入
* 在这里 通过调用 getBean()方法,触发依赖注入
*
*/
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
@ -1441,8 +1492,8 @@ lazy-init 触发的预实例化和依赖注入,发生在 IoC 容器完成对 B
// 缓存容器中所有注册的 BeanDefinition 元数据,以防被修改
beanFactory.freezeConfiguration();
// 对配置了 lazy-init 属性的单态模式 Bean 进行预实例化处理
// 对配置了 lazy-init属性 的 单例bean 进行预实例化处理
beanFactory.preInstantiateSingletons();
}
}
```

@ -1,5 +1,5 @@
## 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请求。
@ -28,7 +28,7 @@ web.xml是SpringMVC与Tomcat的接口部分。这个部署描述文件中
最后,作为 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时序图 如下图所示。
@ -40,8 +40,7 @@ IoC容器的启动过程就是建立上下文的过程该上下文是与Servl
在 ContextLoader 中,完成了两个 IoC容器 建立的基本过程,一个是在 Web容器 中建立起 双亲IoC容器另一个是生成相应的 WebApplicationContext 并将其初始化。
## 3 Web容器中的上下文设计
先从Web容器中的上下文入手看看Web环境中的上下文设置有哪些特别之处然后再
到ContextLoaderListener中去了解整个容器启动的过程。为了方便在Web环境中使用IoC容器
先从 Web容器 中的上下文入手,看看 Web环境 中的上下文设置有哪些特别之处,然后再到 ContextLoaderListener 中去了解整个容器启动的过程。为了方便在 Web环境 中使用 IoC容器
Spring 为 Web应用 提供了上下文的扩展接口 WebApplicationContext 来满足启动过程的需要,其继承关系如下图所示。
![avatar](/images/springMVC/WebApplicationContext接口的类继承关系.png)
@ -49,7 +48,7 @@ Spring为Web应用提供了上下文的扩展接口WebApplicationContext来满
在这个类继承关系中,可以从熟悉的 XmlWebApplicationContext 入手来了解它的接口实现。在接口设计中,最后是通过 ApplicationContex接口 与 BeanFactory接口 对接的,而对于具体的功能实现,很多都是封装在其基类 AbstractRefreshableWebApplicationContext 中完成的。
同样,在源代码中,也可以分析出类似的继承关系,在 WebApplicationContext 中可以看到相关的常量设计,比如 ROOT_ WEB_ APPLICATION_CONTEXT_ATTRIBUTE 等,这个常量是用来索引在 ServletContext 中存储的根上下文的。这个接口类定义的接口方法比较简单,在这个接口中,定义了一
个getServletContext方法通过这个方法可以得到当前Web容器的Servlet上下文环境通过
getServletContext()方法,通过这个方法可以得到当前 Web容器 Servlet上下文环境通过
这个方法,相当于提供了一个 Web容器级别的 全局环境。
```java
public interface WebApplicationContext extends ApplicationContext {
@ -65,11 +64,11 @@ public interface WebApplicationContext extends ApplicationContext {
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容器 */
/** 若不指定其它文件Spring 默认从 "/WEB-INF/applicationContext.xml" 目录文件 初始化 IoC容器 */
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
/** 默认的配置文件在 /WEB-INF/ 目录下 */
@ -86,9 +85,8 @@ public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationC
// 使用 XmlBeanDefinitionReader 对指定的 BeanFactory 进行解析
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 初始化beanDefinitionReader的属性其中设置ResourceLoader是因为
// XmlBeanDefinitionReader是DefaultResource的子类所有这里同样会使用
// DefaultResourceLoader来定位BeanDefinition
// 初始化 beanDefinitionReader 的属性,其中,设置 ResourceLoader 是因为 XmlBeanDefinitionReader
// 是 DefaultResource 的子类,所有这里同样会使用 DefaultResourceLoader 来定位 BeanDefinition
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
@ -129,7 +127,7 @@ public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationC
}
}
```
从上面的代码中可以看到在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相关的配置在概述中已经看到了这里就不重复了。
@ -219,8 +217,8 @@ public class ContextLoader {
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
// 配置 并且初始化IoC容器看到Refresh应该能想到AbstractApplicationContext
// 中的refresh()方法猜到它是前面介绍的IoC容器的初始化入口
// 配置并初始化 IoC容器看到下面方法中的 Refresh单词 应该能想到
// AbstractApplicationContext 中的 refresh()方法,猜到它是前面介绍的 IoC容器 的初始化入口
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}

@ -1,7 +1,7 @@
## 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 会建立自己的上下文来持有SpringMVC 的 Bean对象在建立这个自己持有的 IoC容器 时,会**从 ServletContext 中得到根上下文**作为 DispatcherServlet 持有上下文的双亲上下文。有了这个根上下文,再对自己持有的上下文进行初始化,最后把自己持有的这个上下文保存到 ServletContext 中,供以后检索和使用。
@ -12,7 +12,7 @@
DispatcherServlet 通过继承 FrameworkServlet 和 HttpServletBean 而继承了 HttpServlet通过使用Servlet API 来对 HTTP请求 进行响应,成为 SpringMVC 的前端处理器,同时成为 MVC模块 与 Web容器 集成的处理前端。
DispatcherServlet的工作大致可以分为两个部分一个是初始化部分由initServletBean()启动通过initWebApplicationContext()方法最终调用DispatcherServlet的initStrategies()方法在这个方法里DispatcherServlet对MVC模块的其他部分进行了初始化比如handlerMapping、ViewResolver等另一个是对HTTP请求进行响应作为一个ServletWeb容器会调用Servlet的doGet()和doPost()方法在经过FrameworkServlet的processRequest()简单处理后会调用DispatcherServlet的doService()方法在这个方法调用中封装了doDispatch()这个doDispatch()是Dispatcher实现MVC模式的主要部分下图为DispatcherServlet的处理过程时序图。
DispatcherServlet 的工作大致可以分为两个部分:一个是初始化部分,由 initServletBean()方法 启动,通过 initWebApplicationContext()方法 最终调用 DispatcherServlet initStrategies()方法在这个方法里DispatcherServlet MVC模块 的其他部分进行了初始化,比如 handlerMapping、ViewResolver 等;另一个是对 HTTP请求 进行响应,作为一个 ServletWeb容器 会调用 Servlet 的doGet() doPost()方法,在经过 FrameworkServlet processRequest() 简单处理后,会调用 DispatcherServlet doService()方法,在这个方法调用中封装了 doDispatch(),这个 doDispatch() Dispatcher 实现 MVC模式 的主要部分,下图为 DispatcherServlet 的处理过程时序图。
![avatar](/images/springMVC/DispatcherServlet的处理过程.png)
@ -24,6 +24,7 @@ DispatcherServlet的工作大致可以分为两个部分一个是初始化部
接着会执行 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() + "'");
@ -54,6 +55,7 @@ public abstract class HttpServletBean extends HttpServlet implements Environment
public abstract class FrameworkServlet extends HttpServletBean {
/** 此 servlet 的 WebApplicationContext */
private WebApplicationContext webApplicationContext;
@ -232,7 +234,7 @@ public abstract class FrameworkServlet extends HttpServletBean {
wac.setParent(parent);
wac.setConfigLocation(getContextConfigLocation());
// 配置并且刷新wac
// 配置并且刷新 WebApplicationContext对象
configureAndRefreshWebApplicationContext(wac);
return wac;
@ -272,7 +274,7 @@ public abstract class FrameworkServlet extends HttpServletBean {
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// 在刷新上下文的任何情况下,都将会调用wac环境的initPropertySources()方法。
// 在刷新上下文的任何情况下,都将会调用 此wac 的 env的 initPropertySources()方法。
// 在此处执行此方法以确保在刷新上下文之前servlet属性源 已准备就绪
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
@ -288,7 +290,7 @@ public abstract class FrameworkServlet extends HttpServletBean {
}
}
```
这时候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应用程序 的实现并没有太大的差别。
@ -372,14 +374,12 @@ HandlerMappings完成对MVC中Controller的定义和配置只不过在Web这
### 4.1 HandlerMapping的配置和设计原理
前面分析了 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的初始化函数中完成的。为了维护这个拦截器链和handlerHandlerExecutionChain还提供了一系列与拦截器链维护相关的操作比如为拦
截器链增加拦截器的addInterceptor()方法。
这个 HandlerExecutionChain 的实现看起来比较简洁,它持有一个 拦截器链(HandlerInterceptor对象列表) 和一个 handler对象这个 handler对象 实际上就是 HTTP请求 对应的 Controller在持有这个 handler对象 的同时,还在 HandlerExecutionChain 中设置了一个拦截器链,通过这个拦截器链中的拦截器,可以为 handler对象 提供功能的增强。要完成这些工作,需要对拦截器链和 handler 都进行配置,这些配置都是在 HandlerExecutionChain 的初始化函数中完成的。为了维护这个拦截器链和 handlerHandlerExecutionChain 还提供了一系列与拦截器链维护相关的操作,比如,为拦截器链增加拦截器的 addInterceptor()方法。
```java
public class HandlerExecutionChain {
@ -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();
@ -535,10 +534,10 @@ 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处理程序
*/
@ -622,18 +621,18 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
}
}
```
这里的handlerMap是一个HashMap其中保存了URL请求和Controller的映射关系这个handlerMap是在AbstractUrlHandlerMapping中定义的 Map<String, object> handlerMap = new LinkedHashMap<String, object>() 这个配置好URL请求和handler映射数据的handlerMap为Spring MVC响应HTTP请求准备好了基本的映射数据根据这个handlerMap以及设置于其中的映射数据可以方便地由
URL请求得到它所对应的handler。有了这些准备工作Spring MVC就可以等待HTTP请求的到来了。
这里的 handlerMap 是一个 HashMap其中保存了 “URL请求” --> “Controller对象” 的映射关系,这个 handlerMap 是在 AbstractUrlHandlerMapping 中定义的( Map<String, object> handlerMap = new LinkedHashMap<String, object>() ),这个配置好 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
*/
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 模板方法模式
// 这里用到了模板方法模式getHandler() 是一个模板方法定义了流程getHandlerInternal() 则是
// 一个抽象方法,交由子类实现
Object handler = getHandlerInternal(request);
// 如果找不到特定的 handler则取 defaultHandler
if (handler == null) {
@ -643,8 +642,8 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
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);
@ -658,7 +657,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
```java
public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
/**
* 查找给定请求的URL路径 对应的handler
* 查找 给定请求的URL 对应的 handler
*/
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
@ -765,10 +764,10 @@ DispatcherServlet是Spring MVC框架中非常重要的一个类不但建立
```java
public class DispatcherServlet extends FrameworkServlet {
/** 此servlet使用的HandlerMappings列表 */
/** 此 DispatcherServlet 使用的 HandlerMapping对象列表 */
private List<HandlerMapping> handlerMappings;
/** 此servlet使用的HandlerAdapter列表 */
/** 此 DispatcherServlet 使用的 HandlerAdapter对象列表 */
private List<HandlerAdapter> handlerAdapters;
@ -858,8 +857,8 @@ public class DispatcherServlet extends FrameworkServlet {
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// 2.取得处理当前请求的controller这里也称为hanlder处理器这里并不是
// 直接返回controller而是返回的HandlerExecutionChain请求处理器链对象
// 2.取得处理当前请求的 Controller对象这里也称为 hanlder处理器这里并不是
// 直接返回 controller对象,而是返回的 HandlerExecutionChain请求处理器链对象
// 该对象封装了 handler 和 interceptors
mappedHandler = getHandler(processedRequest, false);
// 如果 handler 为空,则返回 404
@ -868,7 +867,7 @@ public class DispatcherServlet extends FrameworkServlet {
return;
}
// 3. 获取处理request的处理器适配器handler adapter
// 3. 获取处理 request 的处理器适配器 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 获取 请求方式GET, POST, PUT
@ -1010,7 +1009,3 @@ public class SimpleControllerHandlerAdapter implements HandlerAdapter {
}
```
经过上面一系列的处理,得到了 handler对象接着就可以开始调用 handler对象 中的 HTTP响应动作了。在 handler 中封装了应用业务逻辑,由这些逻辑对 HTTP请求 进行相应的处理,生成需要的数据,并把这些数据封装到 ModelAndView对象 中去,这个 ModelAndView 的数据封装是 SpringMVC框架 的要求。对 handler 来说, 这些都是通过调用 handler()方法 中的 handleRequest()方法 来触发完成的。在得到 ModelAndView对象 以后,这个 ModelAndView对象 会被交给 MVC模式 中的视图类,由视图类对 ModelAndView对象 中的数据进行呈现。

Loading…
Cancel
Save