工厂模式
Spring使用工厂模式通过 BeanFactory
或 ApplicationContext
创建 bean 对象。
首先,我们聊下 IOC,IoC(Inversion of Control, 控制翻转) 是 Spring 中一个非常非常重要的概念,它不是什么技术,而是一种解耦的设计思想。它的主要目的是借助于“第三方”(即Spring 中的 IOC 容器) 实现具有依赖关系的对象之间的解耦(通过 IOC 容器管理对象,你只管使用即可),从而降低代码之间的耦合度。IOC 是一个设计原则,而不是一个模式。
Spring IOC 容器就是一个大的工厂,把所有的bean实例都给放在了spring容器里,如果你要使用bean,就找spring容器就可以了,自己不用创建对象了,具体流程如下图所示:
BeanFactory
与 ApplicationContext
的区别
BeanFactory
:延迟注入(使用到某个 bean 的时候才会注入),相比于ApplicationContext
来说,会占用更少的内存,程序启动速度更快。ApplicationContext
:容器启动的时候,不管你用没用到,一次性创建所有的 bean 。
BeanFactory
仅提供了最基本的依赖注入支持,ApplicationContext
扩展了 BeanFactory
,除了有BeanFactory
的功能之外还有额外更多功能,所以一般开发人员使用ApplicationContext
会更多。
ApplicationContext 的三个实现类:
ClassPathXmlApplication
:把上下文文件当成类路径资源。FileSystemXmlApplication
:从文件系统中的 XML 文件载入上下文定义信息。XmlWebApplicationContext
:从Web系统中的XML文件载入上下文定义信息。
单例设计模式
Spring 中 bean 的默认作用域就是 singleton (单例)。
Spring通过ConcurrentHashMap
实现单例注册表的方式来实现单例模式。
// 通过 ConcurrentHashMap(线程安全) 实现单例注册表 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64); public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "'beanName' must not be null"); synchronized (this.singletonObjects) { // 检查缓存中是否存在实例 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { // 此处省略了很多代码 try { singletonObject = singletonFactory.getObject(); } // 此处省略了很多代码 // 如果实例对象在不存在,我们注册到单例注册表中。 addSingleton(beanName, singletonObject); } return (singletonObject != NULL_OBJECT ? singletonObject : null); } } //将对象添加到单例注册表 protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT)); } } } 复制代码
Spring实现单例的两种方式:
- xml:
<bean id="userService" class="top.snailclimb.UserService" scope="singleton"/>
- 注解:
@Scope(value = "singleton")
实际上,在我们的系统中,有一些对象其实只需要一个示例,比如说:线程池、缓存、注册表、日志对象、数据库连接池、显卡等设备驱动程序的对象。这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常、资源使用过量、或者不一致性的结果。
另外,Spring 中 Bean,除了singleton
作用域还有下面几种作用域:
prototype
: 每次请求都会创建一个新的 bean 实例。request
: 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP request 内有效。session
: 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。global-session
: 全局 session 作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。
代理模式
Spring AOP 功能就是基于动态代理的实现的。
在Spring中,如果要代理的对象实现了某个接口,那么Spring AOP 会使用 JDK Proxy ,去创建代理对象,而对于没有实现接口的对象,Spring AOP 会使用 Cglib,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理。
AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如:事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
模板方法模式
模板方法模式是一种行为设计模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤的实现方式。
在 Spring 中, jdbcTemplate
、hibernateTemplate
等以 Template 结尾的对数据库操作的类,它们就使用到了模板方法模式。
一般情况下,我们都是使用继承的方式来实现模板模式,但是 Spring 并没有使用这种方式,而是使用Callback(回调) 模式与模板方法模式配合,模板模式用于对一些不太变化的流程进行模板化,与回调模式结合,可以将变化的部分出离出来,使用回调模式实现。然后根据不同的情况,向template中注入不同的callback,那些模板代码就没有必要重复写了。这样既达到了代码复用的效果,同时又增加了灵活性。
例如:Hibernate Template 提供了常规的 CRUD 操作,但是Hibernate Template的封装也使程序失去了hibernate中直接使用Session进行操作的灵活性,所以Hibernate Template提供了execute(CallBack action)
等系列方法,允许程序员实现自己的HibernateCallBack
,实现具体的逻辑。
@FunctionalInterface public interface HibernateCallback<T> { /** * Gets called by {@code HibernateTemplate.execute} with an active * Hibernate {@code Session}. Does not need to care about activating * or closing the {@code Session}, or handling transactions. * <p>Allows for returning a result object created within the callback, * i.e. a domain object or a collection of domain objects. * A thrown custom RuntimeException is treated as an application exception: * It gets propagated to the caller of the template. * * @param session active Hibernate session * @return a result object, or {@code null} if none * @throws HibernateException if thrown by the Hibernate API * @see HibernateTemplate#execute */ @Nullable T doInHibernate(Session session) throws HibernateException; } public interface HibernateOperations { ... @Nullable <T> T execute(HibernateCallback<T> action) throws DataAccessException; ... } public class HibernateTemplate implements HibernateOperations, InitializingBean { @Override @Nullable public <T> T execute(HibernateCallback<T> action) throws DataAccessException { return doExecute(action, false); } @Nullable protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNativeSession) throws DataAccessException { Assert.notNull(action, "Callback object must not be null"); Session session = null; boolean isNew = false; ... try { enableFilters(session); Session sessionToExpose = (enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session)); return action.doInHibernate(sessionToExpose); } ... finally { if (isNew) { SessionFactoryUtils.closeSession(session); } else { disableFilters(session); } } } ... } 复制代码
装饰者模式
Spring 中配置 DataSource 的时候,DataSource 可能是不同的数据库和数据源。我们能否根据客户的需求在少修改原有类的代码下动态切换不同的数据源?这个时候就要用到装饰者模式。
通常,Spring 中用到的装饰器模式,在类名上大都含有 Wrapper
或者 Decorator
,这些类基本都是动态地给对象添加额外的职责。
例如,DataSource接口继承了Wrapper接口:
# 抽象角色 public interface DataSource extends CommonDataSource, Wrapper { // 尝试与此数据源对象表示的数据源建立连接。 Connection getConnection() throws SQLException; Connection getConnection(String username, String password) throws SQLException; } # 装饰类 public class DelegatingDataSource implements DataSource, InitializingBean { @Nullable private DataSource targetDataSource; public DelegatingDataSource() { } public DelegatingDataSource(DataSource targetDataSource) { this.setTargetDataSource(targetDataSource); } public void setTargetDataSource(@Nullable DataSource targetDataSource) { this.targetDataSource = targetDataSource; } @Nullable public DataSource getTargetDataSource() { return this.targetDataSource; } protected DataSource obtainTargetDataSource() { DataSource dataSource = this.getTargetDataSource(); Assert.state(dataSource != null, "No 'targetDataSource' set"); return dataSource; } public void afterPropertiesSet() { if (this.getTargetDataSource() == null) { throw new IllegalArgumentException("Property 'targetDataSource' is required"); } } public Connection getConnection() throws SQLException { return this.obtainTargetDataSource().getConnection(); } public Connection getConnection(String username, String password) throws SQLException { return this.obtainTargetDataSource().getConnection(username, password); } public PrintWriter getLogWriter() throws SQLException { return this.obtainTargetDataSource().getLogWriter(); } public void setLogWriter(PrintWriter out) throws SQLException { this.obtainTargetDataSource().setLogWriter(out); } public int getLoginTimeout() throws SQLException { return this.obtainTargetDataSource().getLoginTimeout(); } public void setLoginTimeout(int seconds) throws SQLException { this.obtainTargetDataSource().setLoginTimeout(seconds); } public <T> T unwrap(Class<T> iface) throws SQLException { return iface.isInstance(this) ? this : this.obtainTargetDataSource().unwrap(iface); } public boolean isWrapperFor(Class<?> iface) throws SQLException { return iface.isInstance(this) || this.obtainTargetDataSource().isWrapperFor(iface); } public Logger getParentLogger() { return Logger.getLogger("global"); } } 复制代码
还有,ServerHttpResponse
具有ServerHttpResponseDecorator
实现类。
// 装饰类 public class ServerHttpResponseDecorator implements ServerHttpResponse { private final ServerHttpResponse delegate; public ServerHttpResponseDecorator(ServerHttpResponse delegate) { Assert.notNull(delegate, "Delegate is required"); this.delegate = delegate; } public ServerHttpResponse getDelegate() { return this.delegate; } // ServerHttpResponse delegation methods... @Override public boolean setStatusCode(@Nullable HttpStatus status) { return getDelegate().setStatusCode(status); } @Override public HttpStatus getStatusCode() { return getDelegate().getStatusCode(); } @Override public HttpHeaders getHeaders() { return getDelegate().getHeaders(); } @Override public MultiValueMap<String, ResponseCookie> getCookies() { return getDelegate().getCookies(); } @Override public void addCookie(ResponseCookie cookie) { getDelegate().addCookie(cookie); } @Override public DataBufferFactory bufferFactory() { return getDelegate().bufferFactory(); } ... } 复制代码
观察者模式
观察者模式是一种对象行为型模式。它表示的是一种对象与对象之间具有依赖关系,当一个对象发生改变的时候,这个对象所依赖的对象也会做出反应。
Spring 事件驱动模型就是观察者模式很经典的一个应用。Spring 事件驱动模型非常有用,在很多场景都可以解耦我们的代码。比如,我们每次添加商品的时候都需要重新更新商品索引,这个时候就可以利用观察者模式来解决这个问题。
Spring 事件驱动模型中的三种角色
事件角色
ApplicationEvent充当事件的角色,这是一个抽象类,它继承了java.util.EventObject
。
Spring 中默认存在以下事件,他们都是对 ApplicationContextEvent
的实现(它继承自ApplicationEvent
):
ContextStartedEvent
:ApplicationContext
启动后触发的事件;ContextStoppedEvent
:ApplicationContext
停止后触发的事件;ContextRefreshedEvent
:ApplicationContext
初始化或刷新完成后触发的事件;ContextClosedEvent
:ApplicationContext
关闭后触发的事件。
事件监听者角色
ApplicationListener
充当了事件监听者角色,它是一个接口,里面只定义了一个 onApplicationEvent()
方法来处理ApplicationEvent
。
ApplicationListener
接口类源码如下。
@FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E var1); } 复制代码
在 Spring中我们只要实现 ApplicationListener
接口的 onApplicationEvent()
方法即可完成监听事件。
事件发布者角色
ApplicationEventPublisher
充当了事件的发布者,它也是一个接口。
@FunctionalInterface public interface ApplicationEventPublisher { default void publishEvent(ApplicationEvent event) { this.publishEvent((Object)event); } void publishEvent(Object var1); } 复制代码
ApplicationEventPublisher
接口的publishEvent()
这个方法在AbstractApplicationContext
类中被实现。实际上,事件真正是通过ApplicationEventMulticaster
来广播出去的。