Spring中经典的7种设计模式源码分析
AbstractBeanFactory作为抽象基类,定义了getBean()方法的模板实现。
一、工厂模式
- 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 AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
// ...
}
- AbstractBeanFactory类
AbstractBeanFactory作为抽象基类,定义了getBean()方法的模板实现。
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
@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 {
// 合并父BeanFactory
final 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,考虑了 FactoryBean
final 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>() {
@Override
public 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 {
@Override
public 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);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用拦截器链执行方法
MethodInvocation invocation = new ReflectiveMethodInvocation(...);
return invocation.proceed();
}
}
- CGLIB代理
CGLIB代理通过继承目标对象的方式创建代理对象,代码如下:
public class ObjenesisCglibAopProxy extends CglibAopProxy {
@Override
public 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);
// 执行ResultSetExtractor
return 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> {
@Override
public void onApplicationEvent(MyEvent event) {
// 处理事件
}
}
// 发布事件
@Component
public class EventPublisher {
@Autowired
private 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 {
@Override
public 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 URL
URL 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 {
@Autowired
private ResourceLoader resourceLoader;
public void loadResource(String location) {
Resource resource = resourceLoader.getResource(location);
// 使用Resource执行相关操作
}
}
Spring 5通过Resource接口及其多个具体实现类,以及ResourceLoader加载器,实现了策略模式。不同的Resource实现类对应不同的资源访问策略,而ResourceLoader则根据资源位置的前缀来选择合适的Resource实现类。
七、装饰器模式
- Spring中的 HttpServletRequestDecorator和 HttpServletResponseDecorator 使用了装饰器模式。
- 装饰器模式可以在不修改原有对象结构的情况下,动态地给该对象增加新的行为和职责。
更多推荐
所有评论(0)