《深入分析Java Web技术内幕》笔记
13.1、Spring的骨骼架构
Spring框架
Spring框架的核心组件:Core、Bean、Context
13.1.1、Spring的设计理念
设计策略完全类似于Java实现OOP的设计里面,在Spring中没有Bean也就没有Spring存在的意义
13.1.2、核心组件如何协同工作
Bean:演员;Context:演出的舞台背景;Core:演出的道具
对Context来说它就是要发现每个Bean之间的关系,为它们建立这种关系并且维护好这种关系,所以Context就是一个Bean关系的集合,这个关系集合又叫做Ioc容器;
Core就是发现、建立和维护每个Bean之间的关系所需要的一系列工具
Bean、Context和Core之间的关系
13.2、核心组件详解
13.2.1、Bean组件
Bean组件在Spring的org.springframework.beans包下,包括:Bean的定义、Bean的创建以及对Bean的解析
Spring Bean的创建是典型的工厂模式
Bean工厂的集成层次关系如下:
BeanFactory有三个子类:ListableBeanFactory(表示Bean是可列表的)、HierarchicalBeanFactory(表示这些Bean是有继承关系的)和AutowireCapableBeanFactory(定义Bean的自动装配规则)
Bean的解析主要就是对Spring配置文件的解析
这个解析过程如下图所示
13.2.2、Context组件
Context在Spring的org.springframework.context包下,给Spring提供一个运行时的环境,用以保存各个对象的状态
Context相关的类结构图
ApplicationContext的子类主要包含:
ConfigurableApplicationContext
表示该Context是可修改的,也就是在构建Context中,用户可以动态添加或修改已有的配置信息,子类中AbstractRefreshableApplicationContext类最常用,表示可更新的Context
WebApplicationContext
为Web准备的Context,可以直接访问ServletContext
ApplicationContext需要完成的事情:
标识一个应用环境
利用BeanFactory创建Bean对象
保存对象关系表
能够捕获各种事情
13.2.3、Core组件
Resource相关的类结构图
Context和Resource的类关系图
Context把资源的加载、解析和描述工作委托给了ResourcePatternResolver类来完成
13.2.4、Ioc容器如何工作
如何创建BeanFactory
Ioc容器实际上是Context组件结合其他两个组件共同构建一个Bean关系网,这个构建的入口就在AbstractApplicationContext类的refresh方法
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //创建好BeanFactory后,添加一些Spring本身需要的工具类 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //获取实现BeanFactoryPostProcessor接口的子类,并执行它的postProcessBeanFactory方法 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //获取用户定义的实现了BeanPostProcessor接口的子类,并把它们注册到BeanFactory对象中的BeanPostProcessors变量中 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
这个方法构建整个Ioc容器,主要包含以下步骤:
构建BeanFactory,以便于产生所需的“演员”
注册可能感兴趣的事件
创建Bean实例对象
触发被监听的事件
当BeanFactory已经存在时更新,如果不存在就创建
protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
BeanFactory的原始对象是DefaultListableBeanFactory
DefaultListableBeanFactory类继承关系图如下:
refreshBeanFactory方法的loadBeanDefinitions(beanFactory)将装载、解析Bean的定义,也就是用户定义的数据结构转化为Ioc容器中的特定数据结构
创建BeanFactory的时序图如下:
Bean的解析和等级流程时序图如下:
2.如何创建Bean实例并构建Bean的关系网
Bean的实例化是从finishBeanFactoryInitialization方法开始的
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Initialize conversion service for this context. if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } // Register a default embedded value resolver if no bean post-processor // (such as a PropertyPlaceholderConfigurer bean) registered any before: // at this point, primarily for resolution in annotation attribute values. if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } // Stop using the temporary ClassLoader for type matching. beanFactory.setTempClassLoader(null); // Allow for caching all bean definition metadata, not expecting further changes. beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons(); }
Bean的实例化是在BeanFactory中发生的,preInstantiateSingletons()方法
public void preInstantiateSingletons() throws BeansException { if (logger.isTraceEnabled()) { logger.trace("Pre-instantiating singletons in " + this); } // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean> factory = (FactoryBean>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean>) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { getBean(beanName); } } } // Trigger post-initialization callback for all applicable beans... for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null; }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
FactoryBean是个工厂Bean,可以产生Bean的Bean,这里的产生Bean是指Bean的实例,如果一个类继承FactoryBean,用户可以自己定义产生实例对象的方法,只需实现它的getObject方法即可
如何创建Bean的实例
如果是普通的Bean就通过调用getBean方法直接创建它的实例
建立Bean对象实例之间的关系
Ioc容器的扩展点
BeanFactoryPostProcessor和BeanPostProcessor,分别构建BeanFactory和构建Bean对象时调用;
InitializingBean和DisposableBean,分别在Bean创建和销毁时调用;
这些扩展点就是使用Spring来完成特定任务的地点
Ioc容器如何为我所用
Spring必须要先构建Ioc容器,没有它Spring无法工作,ApplicationContext.xml就是Ioc容器的默认文件,Spring的所有特性功能都是基于Ioc容器工作的
13.3、Spring中AOP详解
13.3.1、动态代理的实现原理
AOP是基于动态代理实现的
Proxy类是构造代理类的入口
Proxy的类结构图如下
Proxy产生代理类的过程
13.3.2、SpringAOP如何实现
代理的目的是调用目标方法时可以转而执行InvocationHandler类的invoke方法
JDK动态代理的类图
Spring创建代理对象的时序图
Spring调用拦截器
13.4、Spring中的设计模式
代理模式(proxy)
SpringAOP中JDK动态代理就是利用代理模式技术实现的。在Spring中除了实现被代理对象的接口外,还有org.springframework.aop.SpringProxy和org.springdframework.aop.framework.Advised两个接口
Spring中使用代理模式的结构图
策略模式(Strategy)
Spring中策略模式结构图
简单工厂模式
spring中的BeanFactory就是简单工厂模式的体现
工厂方法(Factory Method)
通常由应用程序直接使用new创建新的对象,为了将对象的创建和使用相分离,采用工厂模式,即应用程序将对象的创建及初始化职责交给工厂对象;
一般情况下,应用程序有自己的工厂对象来创建bean.如果将应用程序自己的工厂对象交给Spring管理,那么Spring管理的就不是普通的bean,而是工厂Bean
单例模式(Singleton)
保证一个类仅有一个实例,并提供一个访问它的全局访问点。;spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是是任意的java对象。;
适配器模式(Adapter)
在Spring的Aop中,使用的Advice(通知)来增强被代理类的功能。Spring实现这一AOP功能的原理就使用代理模式(1、JDK动态代理。2、CGLib字节码生成技术代理。)对类进行方法级别的切面增强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,通过执行拦截器的内容增强了代理方法的功能,实现的面向切面编程
包装器(Decorator)
Spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责
观察者(Observer)
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,Spring中Observer模式常用的地方是listener的实现。如ApplicationListener
模版方法(Template Method)
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。Template Method模式一般是需要继承的。这里想要探讨另一种对Template Method的理解。spring中的JdbcTemplate,在用这个类时并不想去继承这个类,因为这个类的方法太多,但是我们还是想用到JdbcTemplate已有的稳定的、公用的数据库连接,那么我们怎么办呢?我们可以把变化的东西抽出来作为一个参数传入JdbcTemplate的方法中。但是变化的东西是一段代码,而且这段代码会用到JdbcTemplate中的变量。怎么办?那我们就用回调对象吧。在这个回调对象中定义一个操纵JdbcTemplate中变量的方法,我们去实现这个方法,就把变化的东西集中到这里了。然后我们再传入这个回调对象到JdbcTemplate,从而完成了调用。这可能是Template Method不需要继承的另一种实现方式吧。