1.简单工厂
BeanFactory。首先看看它的API。
不难看出,它的作用是通过传入唯一的标识(可以是 bean名称,bean类型或者二者的组合)获得Bean对象,但具体是在传入参数前还是传入参数后创建要取决于实际情况。
实现过程
bean容器的启动阶段:
- 通过注解或者xml配置读取Bean配置,将Bean转换一个个的BeanDefinition对象;
- 通过BeanDefinitionRegistry将这些Bean注册到BeanFactory中,保存在内部的一个ConcurrentHashMap中;
- 调用Spring提供的扩展接口,允许通过实现 BeanFactoryPostProcessor.postProcessBeanFactory 在此处执行自定义的代码。比如PropertyPlaceholderConfigurer,解析 dataSource时用到的占位符,就是在这里执行的。
Bean容器的实例化阶段:
通过反射或者Cglib动态代理创建对象后,bean会走完以下周期:
- aware接口:如BeanFactoryAware,ApplicationContextAware,ResourceLoaderAware等;
- BeanPostProcessor.postProcessBeforeInitialization: Bean的后置处理器的Bean初始化之前的方法
- InitializingBean接口和 bean指定的 init-method 方法: Bean的初始化方法。
- BeanPostProcessor.postProcessAfterInitialization: Bean的后置处理器的Bean初始化之hou的方法
- DisposableBean接口: Bean的销毁方法 :destroy()。
设计意义
松耦合: 通过引入一个BeanFactory的工厂类,在依赖方和被依赖方的两个角色之间增加了一个第三方角色,由它来专门负责Bean的管理和解决依赖问题。
可扩展性强: Spring设计了很多个接口,可以在Bean的每个阶段通过实现接口的方式自定义很多处理,这样可以让Spring的可扩展性非常强。
2.工厂方法
FactoryBean。API如下:
实现原理
实现了FactoryBean的Bean,Spring通过 getBean() 获取该 bean 时,会调用 getObject() 方法,该方法返回的对象就是最终注册到 Spring 容器的对象,类型是 getObjectType() 获取到的类型。所以 getBean() 获取到的对象是 getObject() 返回的对象。
例子:
Mybatis 和 Spring的结合。
Mybatis首先配置一个扫描 Mapper 的类,该类扫描后将 Mapper 的class 类型修改为 MapperFactoryBean。 MapperFactoryBean 实现了 FactoryBean 接口,在这里返回的对象是通过 MapperProxyFactory 创建的 MapperProxy 代理对象,MapperProxy 才是真正执行的类。即被 Spring 扫描并创建的Mapper 对象,是通过 FactoryBean 创建的 MapperProxy 代理对象。
设计意义
一般情况下,Spring 是利用 class 属性通过反射创建Bean,但是如果创建的 Bean 过程和参数都比较复杂,如果通过反射的方法创建则需要大量的配置,使得代码难以维护,这时候如果能采用编程的方式是更好的选择。所以 Spring 提供了 FactoryBean 接口,用户只需要实现这个接口,则可以定制化的创建 Bean 对象,隐藏一些实例化 Bean 的细节。
3.单例模式
Spring 注入 Bean 实例在默认情况下就是单例的。
Spring 注入 Bean 都是发生在 AbstractBeanFactory.getBean()里,getBean() 里在真正创建 Bean 时首先会通过 getSingleton() 从容器里获取当前 Bean,如果获取到了,则不会往下走创建 Bean的逻辑,分析下 getSingleton():
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 检查一级缓存里是否有实例,如果有代表则说明已创建完毕
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//如果为空,锁定一级缓存并进行处理
synchronized (this.singletonObjects) {
// 如果二级缓存有该实例,则说明还在创建中,不处理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 这里是解决循环依赖的重要方法
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
4.适配器模式
Spring MVC 的适配器 HandlerAdatper。
实现原理(过程)
首先描述下Spring MVC的处理过程:
- 请求到达 DispatcherServlet.doService()。
- 调用处理器映射器HandlerMapping根据请求URL获取到Handler。
HandlerExecutionChain handler = mapping.getHandler(request);
- 根据找到的Handler寻找对应的处理器适配器HandlerAdapter。对应的Handler类别和Adapter的对照关系:
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
- 处理器适配器 HandlerApapter 处理请求,返回 ModelAndView对象。
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
- 视图解析器ViewResolver 解析 ModelAndView 返回具体的View
- DispatcherServlet 对 View 渲染视图。
设计意义
从上面的流程可以看到,HandlerAdapter 最主要的作用是调用 Handler 对用户的请求执行具体的业务代码。
HandlerApapter 的存在使Handler的扩展十分容易,如果想新增一个新的 Handler 类别,只需要新增一个新的 HandlerApapter 即可。
每个 Conroller 返回的结果类型可能都是不一样的,HandlerAdapter 可以帮助Spring 对这些结果的适配和转换。
5.装饰器模式
Spring的应用体现在两个地方:1. 类名带Wrapper 2. 类名带Decorator。
实现原理:即动态的给对象添加额外的职责
6.代理模式
典型应用就是 Aop 的动态代理。Aop也分两种代理模式:
JDK动态代理:主要涉及到两个类:Proxy 和 InvocationHandler。原理是通过 Proxy 利用 InvocationHandler 动态创建某一接口的实例,生成目标类的代理对象。JDK动态代理只适用于有实现接口的类。
CGLIB动态代理: 对指定的类生成一个子类,并重写其中的方法。主要原理是通过字节码底层继承要代理类实现。
对比:运行效率CGLIB高很多,创建对象上JDK高很多。
7.观察者模式
Spring 事件驱动模型就是用观察者模式实现的。
具体实现:
观察者模式主要分为三个角色:事件,事件发布者(事件源),事件订阅者(监听者)
事件: ApplicationEvent 抽象类,继承 java.util.EventObject,可通过 getSource() 获取事件源。在 Spring 中发布的事件对象都要继承该类。
public abstract class ApplicationEvent extends EventObject {
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp() {
return this.timestamp;
}
事件发布者(事件源): ApplicationEventPublisher 接口。其中最重要的继承接口是 ApplicationContext。 ApplicationContext 是spring 管理 bean 的全局容器。它负责加载 bean 配置,创建 bean 实例,维护 bean 的生命周期,也就是 IOC 容器。在特定的阶段便会发布事件 ApplicationEvent。
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
public abstract class AbstractApplicationContext implements ApplicationContext {
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
}
其中真正执行事件发布的是 ApplicationEventMulticaster(事件广播器)。他的作用是将事件发布给所有的事件监听器。
public interface ApplicationEventMulticaster {
void multicastEvent(ApplicationEvent event);
}
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
事件订阅者(监听者): ApplicationListener接口,继承自 java.util.EventListener。spring 容器里所有的事件监听器都要实现该接口。
ApplicationListener 只有一个方法 onApplicationEvent(E event)。实现该接口的类根据传入事件的具体类型进行处理。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
8.策略模式
Spring 的资源访问接口 Resource,Spring 本身大量使用了 Resource 接口访问底层资源。
Resoure api:
public interface Resource extends InputStreamSource {
// 返回Resource访问的资源是否存在
boolean exists();
//返回资源文件是否代开
default boolean isOpen() {
return false;
}
URL getURL() throws IOException;
URI getURI() throws IOException;
// 返回资源文件的描述信息,通常是全限定文件名或者是URL
String getDescription();
}
public interface InputStreamSource {
//返回资源文件的输入流。每次调用都会创建一个新的输入流,调用者使用完必须关闭输入流。
InputStream getInputStream() throws IOException;
}
Resource作为策略接口,本身并不提供对资源访问的实现逻辑,针对不同的资源访问方式,spring 会提供不同的实现类,由这些实现类负责不同的资源访问逻辑。
Spring 提供的 Resource 实现类:
- UrlResource:访问网络资源的实现类。
- ClassPathResource:访问类加载路径里资源的实现类。
- FileSystemResource:访问文件系统里资源的实现类
- ServletContextResource:访问相对于ServletContext 路径里的资源的实现类。
- InputStreamResource:访问输入流资源的实现类。
- ByteArrayResource:访问字节数组资源的实现类。
9.责任链模式
AOP 的 CglibAopProxy 实现。