1. 简单工厂模式
介绍
Spring中应用
BeanFactory。Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。
容器中bean启动阶段:
- 读取XML文件的配置文件,将bean的配置信息转换为一个BeanDefinition 对象
- 通过BeanDefinitionRegistry将这些bean注册到BeanFactory中,保存在一个ConcurrentHashMap中,key为bean的名称,value为BeanDefinition对象
- 将BeanDefinition注册到BeanFactory对象后,Spring为我们提供了一个扩展切口,允许我们通过实现BeanFactoryPostProcessor在此处修改我们的BeanDefinition信息
容器中bean实例化阶段:
实例化阶段是通过反射或者CGLIB对bean进行实例化,实例化Bean后在执行bean的初始化方法前后提供了扩展:
- 各种的Aware接口 ,比如 BeanFactoryAware,对于实现了这些Aware接口的bean,在实例化bean时Spring会帮我们注入对应的BeanFactory的实例。
- BeanPostProcessor接口 ,实现了BeanPostProcessor接口的bean,在实例化bean时Spring会帮我们调用接口中的方法。
- InitializingBean接口 ,实现了InitializingBean接口的bean,在实例化bean时Spring会帮我们调用接口中的方法。
- DisposableBean接口 ,实现了BeanPostProcessor接口的bean,在该bean死亡时Spring会帮我们调用接口中的方法。
设计的意义
松耦合。可以将原来硬编码的依赖,通过Spring这个beanFactory这个工厂来注入依赖,也就是说原来只有依赖方和被依赖方,现在我们引入了第三方——spring这个beanFactory,由它来解决bean之间的依赖问题,达到了松耦合的效果.
bean的额外处理。通过Spring接口的暴露,在实例化bean的阶段我们可以进行一些额外的处理,这些额外的处理只需要让bean实现对应的接口即可,那么spring就会在bean的生命周期调用我们实现的接口来处理该bean。
2. 工厂方法
介绍
在父类中提供一个创建对象方法,允许子类决定实例化对象类型简单的说就是为了提供代码结构的扩展性,屏蔽一些创建对象的逻辑,让调用方只要知道怎么调用即可,减少ifelse的使用
Spring中应用
实现FactoryBean接口
public abstract class AbstractFactoryBean<T> implements FactoryBean<T> {}
实现FactoryBean接口的类,有一个特点就是在Spring创建这个bean实例时,最终不会返回BeanFactory创建的bean,而是调用FactoryBean接口中的getBean()方法返回的bean
截取Bean的创建片段,来说明FactoryBean的实现原理
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
// 在这里执行实现了FactoryBean接口的getObject()方法
// 注意这里,如果是FactoryBean的子类,返回getObject()方法返回的值
// 如果不是返回createBean()方法的返回值
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
设计意义
为我们提供了扩展bean的方法,比如在集成mybatis时,不直接mybatis的SqlSessionFactoryBean这个bean,而是通过调用getObject()方法去读取mybatis的配置文件
SqlSessionFactoryBean的getObject()方法代码
@Override
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
3. 单例模式
介绍
单例模式其实是设计模式中最简单的一种模式,他的目的是在软件系统中,保证我们的实例只存在一个。 保证软件系统中只存在一个实例有两种实现方式,懒汉模式和饿汉模式,饿汉模式不存在线程安全,懒汉模式会存在线程安全问题。
Spring 中应用
Spring依赖注入Bean实例默认是单例的,Spring的依赖注入(包括lazy-init方式)都是发生在AbstractBeanFactory的getBean里。getBean的doGetBean方法调用getSingleton进行bean的创建。
getSingleton()方法
public Object getSingleton(String beanName){
//参数true设置标识允许早期依赖
return getSingleton(beanName,true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//检查缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//如果为空,则锁定全局变量并进行处理。
synchronized (this.singletonObjects) {
//如果此bean正在加载,则不处理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//当某些方法需要提前初始化的时候则会调用addSingleFactory 方法将对应的ObjectFactory初始化策略存储在singletonFactories
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//调用预先设定的getObject方法
singletonObject = singletonFactory.getObject();
//记录在缓存中,earlysingletonObjects和singletonFactories互斥
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
实现原理
Spring 依赖注入时使用双重判断加锁,实现单例模式,其实三级缓存解决循环依赖问题也是这个逻辑
设计意义
单例模式保证在应用中一个类只有一个实例存在,并提供一个全局的访问该实例的方法
spring对单例的实现:spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是任意的java对象。
4. 适配器模式
介绍
适配器模式的主要目的是将多个不同的接口实现统一的输出,让原本不兼容的类可以兼容。适配器模式主要分为三类:类适配器模式、对象适配器模式、接口适配器模式。类适配器模式和对象适配器模式非常相似,区别在于类适配器模式是在适配器类中继承被适配类,对象适配模式是在类中组合被适配类
Spring中应用
Spring MVC中的适配器HandlerAdapter
工作原理:
- HandlerAdatper根据Handler规则执行不同的Handler。
- DispatcherServlet根据HandlerMapping返回的handler,向HandlerAdatper发起请求,处理Handler。
- HandlerAdapter根据规则找到对应的Handler并让其执行,执行完毕后Handler会向HandlerAdapter返回一个ModelAndView,最后由HandlerAdapter向DispatchServelet返回一个ModelAndView。
设计意义
HandlerAdatper使得Handler的扩展变得容易,只需要增加一个新的Handler和一个对应的HandlerAdapter即可。
因此Spring定义了一个适配接口,使得每一种Controller有一种对应的适配器实现类,让适配器代替Controller执行相应的方法。这样在扩展Controller时,只需要增加一个适配器类就完成了SpringMVC的扩展了。
5. 装饰器模式
Spring中实现装饰器模式有两种表现,一种是类名中含有Wrapper,一种是类名中含有Decorator
设计意义
动态的给对象添加额外的功能,这种模式比继承子类来说更加灵活
6. 代理模式
介绍
- 代理模式是指为一个对象提供一个替身,以控制这个对象的访问,也就是说通过这个代理对象来访问这个目标对象,这样做的好处是可以在这个目标对象的基础上而外增加一些功能操作,扩展目标对象的功能
- 被代理对象可以是一个远程对象,创建开销大的对象或者需要安全控制的对象
- 代理模式有2种方式实现,静态代理和动态代理
- 静态代理的优点在于可以在不修改目标对象的情况下,对目标对象的功能扩展。缺点在于一个目标对象会对应一个代理对象,导致类爆炸,一旦修改了目标对象的方法那么目标对象和代理对象都需要维护
Spring中的应用
Spring中AOP底层实现就是动态代理模式的实现,它在创建Bean的时候,为Bean创建动态代理来增强bean的功能。如:@AspectJ
切面在应用运行的时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象创建动态的创建一个代理对象。SpringAOP就是以这种方式织入切面的。
织入:把切面应用到目标对象并创建新的代理对象的过程。
动态代理
在内存中构建的,不需要手动编写代理类
静态代理
需要手工编写代理类,代理类引用被代理对象
7. 观察者模式
介绍
观察者模式简单来讲就是一个行为发生时(一个用法修改了自己的信息),其他的用户会接收这个修改的行为并作出相应的动作。
Spring中应用
Spring的事件驱动模型用的是观察者模式,常用的地方是Spring的监听器(Listener)实现
实现方式
事件机制的实现需要三个部分,分别是事件源、事件、事件监听器
ApplicationEvent 抽象类(事件)继承自JDK的EventObject,Spring中所有的事件都是继承自ApplicationEvent,并且通过构造函数得到事件源
public abstract class ApplicationEvent extends EventObject {
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = 7099057708183571937L;
/** System time when the event happened. */
private final long timestamp;
/**
* Create a new {@code ApplicationEvent}.
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
// 通过构造函数传递事件源
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Return the system time in milliseconds when the event occurred.
*/
public final long getTimestamp() {
return this.timestamp;
}
}
ApplicationListener接口(事件监听器),继承自JDK的EventListener接口,所有的监听器都实现这个接口。ApplicationListener接口只有一个onApplicationListener()方法,该方法用来接收一个ApplicationEvent事件对象,也可以是它的子类事件对象,在该方法中可以通过不同的Event类来判断进行相应的逻辑处理,当事件触发时,所有的监听器都会监听收到消息
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
ApplicationContext接口(事件源),继承ApplicationEventPublisher接口
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
// 代码省略
}
ApplicationContextPublisher接口,提供publishEven()方法,用于发布事件。
public interface ApplicationEventPublisher {
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an application event. Events may be framework events
* (such as ContextRefreshedEvent) or application-specific events.
* <p>Such an event publication step is effectively a hand-off to the
* multicaster and does not imply synchronous/asynchronous execution
* or even immediate execution at all. Event listeners are encouraged
* to be as efficient as possible, individually using asynchronous
* execution for longer-running and potentially blocking operations.
* @param event the event to publish
* @see #publishEvent(Object)
* @see org.springframework.context.event.ContextRefreshedEvent
* @see org.springframework.context.event.ContextClosedEvent
*/
default void publishEvent(ApplicationEvent event) {
// 发布事件方法
publishEvent((Object) event);
}
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an event.
* <p>If the specified {@code event} is not an {@link ApplicationEvent},
* it is wrapped in a {@link PayloadApplicationEvent}.
* <p>Such an event publication step is effectively a hand-off to the
* multicaster and does not imply synchronous/asynchronous execution
* or even immediate execution at all. Event listeners are encouraged
* to be as efficient as possible, individually using asynchronous
* execution for longer-running and potentially blocking operations.
* @param event the event to publish
* @since 4.2
* @see #publishEvent(ApplicationEvent)
* @see PayloadApplicationEvent
*/
void publishEvent(Object event);
}
ApplicationEventMulticaster接口,Spring会通过这个接口的子类来注册监听器,事件。将事件广播给监听器接收
public interface ApplicationEventMulticaster {
/**
* 添加监听器
* @param listener the listener to add
*/
void addApplicationListener(ApplicationListener<?> listener);
/**
* 添加监听器
* @param listenerBeanName the name of the listener bean to add
*/
void addApplicationListenerBean(String listenerBeanName);
/**
* Remove a listener from the notification list.
* @param listener the listener to remove
*/
void removeApplicationListener(ApplicationListener<?> listener);
/**
* Remove a listener bean from the notification list.
* @param listenerBeanName the name of the listener bean to remove
*/
void removeApplicationListenerBean(String listenerBeanName);
/**
* Remove all listeners registered with this multicaster.
* <p>After a remove call, the multicaster will perform no action
* on event notification until new listeners are registered.
*/
void removeAllListeners();
/**
* 为监听器广播事件
* @param event the event to multicast
*/
void multicastEvent(ApplicationEvent event);
/**
* 为监听器广播事件
* @param event the event to multicast
* @param eventType the type of event (can be {@code null})
* @since 4.2
*/
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
SimpleApplicationEventMulticaster 是Spring默认提供的事件广播器,实现ApplicationEventMulticaster接口,作用是管理所有的监听器,循环的为监听器广播事件。
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
// 省略部分代码
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
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);
}
}
}
/**
* Invoke the given listener with the given event.
* @param listener the ApplicationListener to invoke
* @param event the current event to propagate
* @since 4.1
*/
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 调用监听器的onApplicationEvent方法
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message.
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
}
8. 策略模式
介绍
策略模式将算法分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。替代大量的ifelse。
Spring中应用
Spring框架中的资源访问(Resource)接口,提供了资源访问能力,如加载xml文件为每个bean组装成BeanDefinition对象。
Resource 接口主要提供了以下方法
- getInputStream():定位并打开资源,返回资源对应的输入流。每次调用都返回新的输入流。调用者必须负责关闭输入流。
- exists():返回 Resource 所指向的资源是否存在。
- isOpen():返回资源文件是否打开,如果资源文件不能多次读取,每次读取结束应该显式关闭,以防止资源泄漏。
- getDescription():返回资源的描述信息,通常用于资源处理出错时输出该信息,通常是全限定文件名或实际 URL。
- getFile:返回资源对应的 File 对象。
- getURL:返回资源对应的 URL 对象。
最后两个方法通常无须使用,仅在通过简单方式访问无法实现时,Resource 提供传统的资源访问的功能
Resource 接口本身没有提供访问任何底层资源的实现逻辑,针对不同的底层资源,Spring 将会提供不同的 Resource 实现类,不同的实现类负责不同的资源访问逻辑。
Spring 为 Resource 接口提供了如下实现类:
- UrlResource:访问网络资源的实现类。
- ClassPathResource:访问类加载路径里资源的实现类。
- FileSystemResource:访问文件系统里资源的实现类。
- ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类.
- InputStreamResource:访问输入流资源的实现类。
- ByteArrayResource:访问字节数组资源的实现类。
这些 Resource 实现类,针对不同的的底层资源,提供了相应的资源访问逻辑,并提供便捷的包装,以利于客户端程序的资源访问。
模板方法模式
介绍
模板方法的核心是在父类定义好方法的执行顺序,子类只要实现这些方法,并不需要关心方法的执行顺序。最大的好处是方法的执行顺序在父类中已经定义好了,不需要在子类中定义执行顺序,来达到代码复用,减少重复代码的目的。
在父类中,有两类方法:
第一类:通用方法,所有子类都需要用到的方法
第二类:钩子方法,父类只定义一个空方法,由子类来实现。这类方法的逻辑都是不同的,由子类来实现
Spring中应用
Spring中模板模式的实质是模板模式和回调模式的结合,是模板方法不需要继承的另一种实现方式,Spring几乎所有的外接扩展都采用这种模式
以JdbcTemplate 为例,JDBC的抽象和对Hibernate的继承,都采用了一种模板方法和Callback 接口相结合的方式。采用模板方法模式是为了以一种统一而集中的方式来处理资源的获取和释放。
public abstract class JdbcTemplate {
public final Object execute(String sql){
Connection con=null;
Statement stmt=null;
try{
con=getConnection();
stmt=con.createStatement();
Object retValue=executeWithStatement(stmt,sql);
return retValue;
}catch(SQLException e){
...
}finally{
closeStatement(stmt);
releaseConnection(con);
}
}
protected abstract Object executeWithStatement(Statement stmt, String sql);
}
引入回调的原因
JdbcTemplate是抽象类,不能够独立使用,我们每次进行数据访问的时候都要给出一个相应的子类实现,这样肯定不方便,所以就引入了回调。
public interface StatementCallback{
Object doWithStatement(Statement stmt);
}
利用回调方法重写JdbcTemplate方法
public class JdbcTemplate {
public final Object execute(StatementCallback callback){
Connection con=null;
Statement stmt=null;
try{
con=getConnection();
stmt=con.createStatement();
Object retValue=callback.doWithStatement(stmt);
return retValue;
}catch(SQLException e){
...
}finally{
closeStatement(stmt);
releaseConnection(con);
}
}
...//其它方法定义
}
Jdbc使用方法如下
JdbcTemplate jdbcTemplate=...;
final String sql=...;
StatementCallback callback=new StatementCallback(){
public Object=doWithStatement(Statement stmt){
return ...;
}
}
jdbcTemplate.execute(callback);
为什么JdbcTemplate没有使用继承?
因为这个类的方法太多,但是我们还是想用到JdbcTemplate已有的稳定的、公用的数据库连接,那么我们怎么办呢?
我们可以把变化的东西抽出来作为一个参数传入JdbcTemplate的方法中。但是变化的东西是一段代码,而且这段代码会用到JdbcTemplate中的变量。怎么办?
那我们就用回调对象吧。在这个回调对象中定义一个操纵JdbcTemplate中变量的方法,我们去实现这个方法,就把变化的东西集中到这里了。然后我们再传入这个回调对象到JdbcTemplate,从而完成了调用。