一、工厂模式
- Spring使用工厂模式来创建Bean对象,如BeanFactory、ApplicationContext等。
- 工厂模式为bean的创建过程提供了一个框架,同时隔离了实例化细节,使得代码更加解耦。
- BeanFactory接口
BeanFactory接口仍然是Spring工厂模式的基础,它定义了获取Bean实例的基本方法。
public interface BeanFactory {Object getBean(String name) throws BeansException;// ...
}
- DefaultListableBeanFactory类
DefaultListableBeanFactory继承自AbstractAutowireCapableBeanFactory,实现了BeanDefinitionRegistry接口,用于存储和管理BeanDefinition。它是最常用的BeanFactory实现类。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry {// ...
}
- AbstractBeanFactory类
AbstractBeanFactory作为抽象基类,定义了getBean()方法的模板实现。
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {@Overridepublic Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);}protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {// 合并父BeanFactoryfinal String beanName = transformedBeanName(name);Object sharedInstance = getSingleton(beanName);// ...// 创建Bean实例RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);Object instance = null;if (mbd.isSingleton()) {instance = resolveBeforeInstantiation(beanName, mbd);if (instance == null) {instance = createBean(beanName, mbd, args);}} else {instance = createBean(beanName, mbd, args);}// ...return instance;}
}
- 创建Bean实例
AbstractAutowireCapableBeanFactory提供了createBean()方法,用于创建Bean实例。该方法委托给了AbstractAutowireCapableBeanFactory的createBeanInstance()方法,来实现不同的实例化策略。
protected Object createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {// 决定使用哪种实例化策略Constructor<?> constructorToUse = null;// ...// 使用适当的实例化策略boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {// ...autowireNecessary = mbd.resolvedConstructorOrFactoryMethod != null;resolved = true;}}Object beanInstance = null;if (resolved) {// 使用工厂方法实例化beanInstance = getInstantiationStrategy().instantiate(mbd, null, this);}// ...return beanInstance;
}
- 实例化策略
Spring 5中提供了多种实例化策略,包括:
- 简单实例化策略(SimpleInstantiationStrategy)
- CGLIB实例化策略(CglibSubclassingInstantiationStrategy)
- 通过工厂方法实例化(FactoryMethodInstantiationStrategy)
- 通过静态工厂方法实例化
这些实例化策略均实现了InstantiationStrategy接口,并在AbstractAutowireCapableBeanFactory的createBeanInstance()方法中根据条件来选择合适的策略。
二、单例模式
- Spring默认情况下将每个bean创建为单例模式,可以通过配置修改为原型模式。
- 单例模式确保了在整个应用程序中只有一个bean实例,从而节省内存资源。
- 单例 Bean 缓存
DefaultSingletonBeanRegistry 使用 ConcurrentHashMap
来缓存单例 Bean 的实例:
/** Cache of singleton objects: bean name to bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
- getSingleton() 方法
在 AbstractBeanFactory 的 getBean() 方法中,首先会尝试从单例 Bean 缓存中获取 Bean 实例:
@Override
public Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);
}protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {// 获取"真实"的 beanName,考虑了 FactoryBeanfinal String beanName = transformedBeanName(name);Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {// ...}// ...
}
getSingleton() 方法定义在 DefaultSingletonBeanRegistry 中:
public Object getSingleton(String beanName) {return getSingleton(beanName, true);
}protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 检查缓存中是否存在实例Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 如果当前 Bean 正在创建中,则需要处理循环依赖singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// ...}}return singletonObject;
}
- addSingleton() 方法
如果缓存中不存在该 Bean 的实例,Spring 会调用相应的实例化策略创建 Bean 实例,并在创建完成后,将其缓存到单例缓存中:
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);// 从 singletonFactories 中移除this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}
}
- 单例作用域
在解析 Bean 定义时,Spring 会根据 scope 属性确定 Bean 的作用域,默认为 singleton,即单例模式。如果是单例作用域,Spring 会在获取 Bean 实例时从单例缓存中获取或创建一个实例并加入缓存。
public Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);
}protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) {// ...// 创建或获取已经创建的实例if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {@Overridepublic Object getObject() throws BeansException {try {return createBean(beanName, mbd, args);} catch (BeansException ex) {// ...}}});// ...}// ...
}
在上面的代码中,如果 Bean 的作用域是单例,Spring 会调用 getSingleton() 方法尝试从单例缓存中获取 Bean 实例。如果缓存中不存在,则使用传入的 ObjectFactory 回调函数创建 Bean 实例,并将其加入单例缓存中。
- 循环依赖处理
Spring 还提供了处理单例 Bean 循环依赖的机制。在 getSingleton() 方法中,如果发现当前 Bean 正在创建中,会尝试从 earlySingletonObjects 缓存中获取提前曝光的 Bean 实例(ObjectFactory),从而解决循环依赖问题。
总结起来,Spring 5 中通过维护一个单例 Bean 缓存 (ConcurrentHashMap)、getSingleton() 方法从缓存中获取或创建 Bean 实例、以及 addSingleton() 方法将 Bean 实例加入缓存,实现了单例模式的管理。同时,Spring 还根据 Bean 定义的 scope 属性确定 Bean 的作用域,默认为单例模式。这种实现方式保证了在同一个 Spring IoC 容器中,单例 Bean 只会被实例化一次,提高了性能并节省了内存资源,
三、代理模式
- Spring的AOP (Aspect Oriented Programming) 功能就是利用代理模式实现的。
- 代理模式在不修改目标对象的情况下,通过代理对象来增强目标对象的功能。Spring AOP的实现主要依赖两个模块:Spring AOP和AspectJ
- AOP代理创建
在Spring AOP中,如果目标对象实现了接口,则默认使用JDK动态代理创建AOP代理。如果目标对象没有实现接口,则使用CGLIB创建代理对象。这种选择是由AopProxyFactory决定的:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");}if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}}
}
- JDK动态代理
JDK动态代理通过实现InvocationHandler接口和使用Proxy类来创建代理对象,代码如下:
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {private final Class<?> proxiedInterface;public Object getProxy(ClassLoader classLoader) {// 使用Proxy创建代理对象return Proxy.newProxyInstance(classLoader, new Class<?>[] { this.proxiedInterface }, this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 调用拦截器链执行方法MethodInvocation invocation = new ReflectiveMethodInvocation(...);return invocation.proceed();}
}
- CGLIB代理
CGLIB代理通过继承目标对象的方式创建代理对象,代码如下:
public class ObjenesisCglibAopProxy extends CglibAopProxy {@Overridepublic Object getProxy(ClassLoader classLoader) {// 使用Enhancer创建代理对象Enhancer enhancer = new Enhancer();enhancer.setSuperclass(this.advised.getTargetClass());enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));Callback[] callbacks = getCallbacks(this.advised);Class<?>[] types = new Class<?>[callbacks.length];for (int x = 0; x < types.length; x++) {types[x] = callbacks[x].getClass();}// 设置过滤器enhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), types));enhancer.setCallbackTypes(types);// 创建代理对象return createProtectedProxy(enhancer, callbacks, this.advised);}
}
- Advice链执行
无论是JDK动态代理还是CGLIB代理,在目标方法调用时都会执行相应的Advice链。Spring使用MethodInvocation类来执行Advice链:
public class ReflectiveMethodInvocation implements ProxyMethodInvocation {protected final Object[] arguments;public Object proceed() throws Throwable {// 获取适当的拦截器链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);if (chain.isEmpty()) {// 直接执行目标方法retVal = invokeSingalTarget();}else {// 执行拦截器链retVal = new ReflectiveMethodInvocation(proxy, target, method, arguments, target.getClass(), chain).proceed();}return retVal;}
}
在执行Advice链的过程中,Spring会根据Advice的类型(前置、环绕、异常、最终返回)在适当的位置执行对应的Advice逻辑。
总的来说,Spring 5利用JDK动态代理和CGLIB两种方式创建AOP代理对象,并通过执行相应的Advice链来增强目标对象的功能。代理模式的使用使得Spring AOP能够在不修改目标对象的前提下,动态地为目标对象增加新的行为和职责。可以自定义Advice,从而灵活地扩展目标对象的功能。
四、模板方法模式
- Spring中的 JDBCTemplate、HibernateTemplate等以模板方法模式为基础。
- 模板方法模式定义了一个算法的骨架,并允许子类重写特定的步骤。
- JdbcTemplate
JdbcTemplate是Spring JDBC中的核心类,用于简化JDBC操作。它提供了一系列执行SQL语句的模板方法,如query()、update()等。这些模板方法都遵循相同的模式:
public <T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException {// 创建语句PreparedStatement stmt = null;try {stmt = createPreparedStatement(sql);// 设置参数applyStatementSettings(stmt);// 执行查询ResultSet rs = null;try {rs = executeQuery(stmt);// 执行ResultSetExtractorreturn rse.extractData(rs);} finally {// ...}} finally {// ...}
}
- 模板方法骨架
在JdbcTemplate的模板方法中,有一些固定的步骤是不可变的,如创建语句、设置参数、执行查询等,这些步骤构成了模板方法的骨架。
- 钩子方法
在模板方法中,也会调用一些抽象方法或钩子方法,这些方法留给子类去实现。比如executeQuery()、applyStatementSettings()等。子类可以通过扩展JdbcTemplate并重写这些钩子方法来自定义相应的行为。
protected PreparedStatement createPreparedStatement(String sql, @Nullable List<Object> paramList) throws SQLException {PreparedStatement stmt = getPreparedStatementCreator().createPreparedStatement(sql, this.getRetrieveKeys(paramList));applyStatementSettings(stmt);return stmt;
}protected abstract PreparedStatementCreator getPreparedStatementCreator();protected void applyStatementSettings(PreparedStatement stmt) {// ...
}
- 回调接口
除了通过子类继承的方式来自定义行为,Spring还提供了一些回调接口,允许开发者在执行模板方法时注入自定义的逻辑。比如ResultSetExtractor、PreparedStatementSetter等。
public <T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException {// ...return rse.extractData(rs);
}
总的来说,Spring 5中通过模板方法模式提供了一些可复用的模板类,如JdbcTemplate。这些模板类定义了一系列算法的骨架,并通过钩子方法和回调接口,允许开发者在不改变模板结构的情况下,自定义相应的行为。这种模式提高了代码的可重用性和可扩展性,同时也增强了代码的可维护性。Spring框架中还有许多其他模板类的实现,如RedisTemplate、RestTemplate等,都遵循了模板方法模式的设计思想。
五、观察者模式
- Spring的事件机制就是基于观察者模式实现的。
- 观察者模式定义了对象之间的一对多依赖关系,当一个对象改变状态时,它的所有依赖者都会得到通知。
Spring 5中使用观察者模式来实现事件驱动机制,主要通过ApplicationEvent和ApplicationListener来实现。
- ApplicationEvent
ApplicationEvent是Spring中事件的基类,它继承自jdk的EventObject。所有的事件都需要继承ApplicationEvent。
public abstract class ApplicationEvent extends EventObject {private static final long serialVersionUID = 7099057708183571937L;private final long timestamp;public ApplicationEvent(Object source) {super(source);this.timestamp = System.currentTimeMillis();}// ...
}
- ApplicationListener
ApplicationListener是观察者接口,用于监听并处理ApplicationEvent事件。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {void onApplicationEvent(E event);
}
- ApplicationEventMulticaster
ApplicationEventMulticaster是观察者模式中的主题或发布者角色,它维护了一个ApplicationListener集合,用于发布事件并通知所有监听器。
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster {private final ListenerRetriever defaultRetriever = new DefListenerRetriever(false);private final ListenerRetriever retrieverWithSet = new DefListenerRetriever(true);// 添加监听器public void addApplicationListener(ApplicationListener<?> listener) {synchronized (this.retrieveListeners) {this.retrieveListeners.add(listener);this.singletonRetrievers.clear();}}// 发布事件并通知监听器public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {resolveListeners(event, retrieverCache.getListeners(eventType, this.defaultRetriever, this.applicationContext.getId()));}// 内部通知监听器处理事件protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {listener.onApplicationEvent(event);}// ...
}
- 注册和发布事件
在Spring中,可以通过实现ApplicationListener接口并将其注册为Bean来监听事件。发布事件时,ApplicationEventMulticaster会遍历所有的监听器并调用其onApplicationEvent()方法。
// 定义事件
public class MyEvent extends ApplicationEvent {// ...
}// 定义监听器
@Component
public class MyListener implements ApplicationListener<MyEvent> {@Overridepublic void onApplicationEvent(MyEvent event) {// 处理事件}
}// 发布事件
@Component
public class EventPublisher {@Autowiredprivate ApplicationContext context;public void publish() {context.publishEvent(new MyEvent("Hello Event"));}
}
Spring 5中通过ApplicationEvent、ApplicationListener和ApplicationEventMulticaster实现了观察者模式。ApplicationEvent是事件对象,ApplicationListener是观察者接口,ApplicationEventMulticaster扮演发布者的角色,负责管理监听器并发布事件。开发者可以自定义事件和监听器,并通过ApplicationContext发布事件。这种实现方式使得Spring框架具有了良好的可扩展性和灵活性,能够很好地支持事件驱动编程。
六、策略模式
- Spring的资源访问模块(Resource)中使用了策略模式。
- 策略模式定义了一系列算法,并将每个算法封装成一个对象,从而使它们可以互相替换。
Spring 5中使用了策略模式来实现一些功能,允许在运行时根据不同的条件选择不同的算法或策略。以Spring中的Resource接口为例,我们来分析一下策略模式在Spring 5中的实现。
- Resource接口
Resource接口定义了一组用于获取低级资源的操作方法。它是Spring资源访问策略的入口接口。
public interface Resource extends InputStreamSource {boolean exists();boolean isOpen();URL getURL() throws IOException;File getFile() throws IOException;// ...
}
- Resource实现类
Spring提供了多个Resource接口的具体实现类,每个实现类都对应一种资源访问策略。
ClassPathResource
: 用于访问类路径下的资源FileSystemResource
: 用于访问文件系统中的资源UrlResource
: 用于访问URL资源ByteArrayResource
: 用于访问字节数组资源InputStreamResource
: 用于访问输入流资源
public class ClassPathResource extends AbstractResource {// ...
}public class FileSystemResource extends AbstractResource implements ResourceLoaderAware {// ...
}public class UrlResource extends AbstractFileResolvingResource {// ...
}
- Resource加载器
Spring提供了ResourceLoader接口及其实现类DefaultResourceLoader,用于根据不同的前缀来选择合适的Resource实现类。
public interface ResourceLoader {Resource getResource(String location);
}public class DefaultResourceLoader implements ResourceLoader {@Overridepublic Resource getResource(String location) {if (location.startsWith("/")) {return getResourceByPath(location);} else if (location.startsWith("classpath:")) {return new ClassPathResource(location.substring("classpath:".length()), getClassLoader());} else {try {// Try URLURL url = new URL(location);return new UrlResource(url);} catch (MalformedURLException ex) {// No URL -> resolve as resource path.return getResourceByPath(location);}}}// ...
}
- 使用示例
在应用程序中,可以通过ResourceLoader或ApplicationContext来获取不同类型的Resource实例。
@Component
public class MyService {@Autowiredprivate ResourceLoader resourceLoader;public void loadResource(String location) {Resource resource = resourceLoader.getResource(location);// 使用Resource执行相关操作}
}
Spring 5通过Resource接口及其多个具体实现类,以及ResourceLoader加载器,实现了策略模式。不同的Resource实现类对应不同的资源访问策略,而ResourceLoader则根据资源位置的前缀来选择合适的Resource实现类。
七、装饰器模式
- Spring中的 HttpServletRequestDecorator和 HttpServletResponseDecorator 使用了装饰器模式。
- 装饰器模式可以在不修改原有对象结构的情况下,动态地给该对象增加新的行为和职责。