一篇文章让你知道spring原理剖析

  • Spring模块
  • Core(核心容器)
  • 说明
  • 核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现
  • BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开
  • IOC(控制反转模式 )
  • 不建立对象,可是描述建立它们的方式。在代码中不直接与对象和服务链接,但在配置文件中描述哪个组件须要哪一项服务。容器(在 Spring 框架中是 IOC 容器) 负责将这些联系在一块儿,保持应用程序和对象依赖的松散耦合
  • 控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转
  • 注入方式
  • 服务须要实现专门的接口,经过接口,由对象提供这些服务,能够从对象查询依赖性
  • 经过 JavaBean 的属性(例如 setter 方法)分配依赖性(经常使用)
  • 依赖性以构造函数的形式提供,不以 JavaBean 属性的形式公开
  • org.springframework.beans 包,这个包一般不是由用户直接使用,而是由服务器将其用做其余多数功能的底层中介
  • BeanFactory 接口
  • 它是工厂设计模式的实现,容许经过名称建立和检索对象。BeanFactory 也能够管理对象之间的关系
  • Bean 是被消极加载的,这意味在须要 bean 以前,bean 自己不会被初始化
  • 支持两种对象模型
  • 单例
  • 原型
  • Bean工厂继承关系(BeanFactory )
  • ListableBeanFactory
  • HierarchicalBeanFactory
  • AutowireCapableBeanFactory
  • DefaultListableBeanFactory
  • Bean定义:完整的描述了在 Spring 的配置文件中你定义的 <bean/> 节点中全部的信息,包括各类子节点,在 Spring 的内部他就被转化成 BeanDefinition 对象
  • Bean解析类
  • BeanDefinitionReader
  • BeanDefinitionDocumentReader
  • XmlBeanDefinitionReader
  • 建立BeanFactory
  • Ioc 容器实际上就是 Context 组件结合其余两个(Core和BeanFactory)组件共同构建了一个 Bean 关系网
  • 构建的入口就在 AbstractApplicationContext 类的 refresh 方法中
  • Spring Context(上下文)
  • 说明
  • Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息
  • Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能
  • 组件
  • ApplicationContext
  • ConfigurableApplicationContext
  • 表示该 Context 是可修改的,也就是在构建 Context 中用户能够动态添加或修改已有的配置信息
  • 下面又有多个子类,其中最常用的是可更新的 Context,即 AbstractRefreshableApplicationContext 类
  • WebApplicationContext
  • 为 web 准备的 Context 他能够直接访问到 ServletContext
  • Resource
  • 全部的资源都被能够经过 InputStream 这个类来获取,因此也屏蔽了资源的提供者
  • ResourceLoader 接口负责资源的统一加载
  • Context 是把资源的加载、解析和描述工做委托给了 ResourcePatternResolver 类来完成,他至关于一个接头人,他把资源的加载、解析和资源的定义整合在一块儿便于其余组件使用
  • Spring AOP
  • 说明
  • 经过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。因此,能够很容易地使 Spring 框架管理的任何对象支持 AOP
  • Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。经过使用 Spring AOP,不用依赖 EJB 组件,就能够将声明性事务管理集成到应用程序中
  • 什么是AOP
  • AOP(Aspect Orient Programming),也就是面向切面编程
  • 面向对象编程(OOP)是从静态角度考虑程序结构,
面向切面编程(AOP)是从动态角度考虑程序运行过程
  • AOP的做用
  • 处理一些具备横切性质的系统性服务,如事务管理、安全检查、缓存、对象池管理等
  • AOP的实现原理
  • AOP 其实是由目标类的代理类实现的。AOP 代理实际上是由AOP 框架动态生成的一个对象,该对象可做为目标对象使用
  • AOP 代理包含了目标对象的所有方法,但AOP 代理中的方法与目标对象的方法存在差别,AOP 方法在特定切入点添加了加强处理,并回调了目标对象的方法
  • AOP实现
  • 静态AOP
  • 机制:静态织入
  • 原理:在编译期,切面直接以字节码的形式编译到目标字节码文件中
  • 优势:对系统无性能影响
  • 缺点:灵活性不够
  • 动态AOP
  • 机制:动态代理
  • 原理:在运行期,目标类加载后,为接口动态生成代理类,将切面植入到代理类中
  • 优势:相对于静态AOP更加灵活
  • 缺点:切入的关注点须要实现接口。对系统有一点性能影响
  • 表明:JDK动态代理
  • 接口 + InvocationHandler + 目标对象 = 代理
  • 动态字节码生成
  • 机制:在运行期,目标类加载后,动态构建字节码文件生成目标类的子类,将切面逻辑加入到子类中
  • 原理:没有接口也能够织入
  • 优势:扩展类的实例方法为final时,则没法进行织入
  • 表明:Cglib动态代理(依赖ASM)
  • 接口或类 + MethodInterceptor + 目标对象 = 代理
  • 自定义加载器
  • 机制:在运行期,目标加载前,将切面逻辑加到目标字节码里
  • 原理:能够对绝大部分类进行织入
  • 优势:代码中若是使用了其余类加载器,则这些类将不会被织入
  • 表明:Javassist
  • 字节码转换
  • 机制:在运行期,全部类加载器加载字节码前,前进行拦截
  • 原理:能够对全部类进行织入
  • 表明:Javassit + Instrumentation
  • Spring对AOP的支持
  • Spring 中AOP 代理由Spring 的IoC 容器负责生成、管理,其依赖关系也由IoC 容器负责管理。所以,AOP 代理能够直接使用容器中的其余Bean 实例做为目标,这种关系可由IoC 容器的依赖注入提供
  • Spring 默认使用Java 动态代理来建立AOP 代理, 这样就能够为任何接口实例建立代理了。当须要代理的类不是代理接口的时候, Spring 自动会切换为使用CGLIB 代理,也可
强制使用CGLIB
  • AOP 编程
  • 定义普通业务组件
  • 定义切入点,一个切入点可能横切多个业务组件
  • 定义加强处理,加强处理就是在AOP 框架为普通业务组件织入的处理动做
  • 因此进行AOP 编程的关键就是定义切入点和定义加强处理。一旦定义了合适的切入点和加强处理,AOP 框架将会自动生成AOP 代理,即:代理对象的方法 = 加强处理 + 被代理对象的方法
  • Spring中AOP的实现
  • 基于Annotation 的“零配置”方式:使用@Aspect、@Pointcut 等Annotation 来标注切入点和加强处理
  • 首先启用Spring 对@AspectJ 切面配置的支持
  • 定义切面Bean
  • 当启动了@AspectJ 支持后,只要在Spring 容器中配置一个带@Aspect 注释的Bean, Spring 将会自动识别该Bean 并做为切面处理
  • 定义@Before 加强处理
  • 定义@AfterReturning 加强处理
  • 定义@AfterThrowing 加强处理
  • 定义@After 加强处理
  • After 加强处理与AfterReturning 加强处理有点类似,但也有区别
  • AfterReturning 加强处理处理只有在目标方法成功完成后才会被织入
  • After加强处理无论目标方法如何结束(保存成功完成和遇到异常停止两种状况),它都会被织入
  • @Around 加强处理
  • 访问目标方法的参数
  • 定义切入点
  • 所谓切入点,其实质就是为一个切入点表达式起一个名称,从而容许在多个加强处理中重用该名称
  • 一个切入点表达式
  • 一个包含名字和任意参数的方法签名
  • 基于XML 配置文件的管理方式:使用Spring 配置文件来定义切入点和加强点
  • 使用Spring ProxyFactoryBean建立代理
  • 使用 ProxyFactoryBean 来建立 AOP 代理的最重要的优势之一是 IoC 能够管理通知和切入点。 这是一个很是的强大的功能,可以实现其余 AOP 框架很难实现的特定的方法。例如,一个通知自己能够引用应用对象(除了目标对象,它在任何 AOP 框架中均可以引用应用对象),这彻底得益于依赖注入所提供的可插入性
  • ProxyFactoryBean的proxyInterfaces属性,指明要代理的接口
  • ProxyFactoryBean的target属性,指明要代理的目标类 ,这个目标类实现了上面proxyInterfaces属性指定的接口
  • ProxyFactoryBean的interceptorNames属性,指明要在代理的目标类中插入的Adivce
  • ProxyFactoryBean还有一个proxyTargetClass属性,若是这个属性被设定为“true”,说明 ProxyFactoryBean要代理的不是接口类,而是要使用CGLIB方式来进行代理,后面会详细讲解使用CGLIB方式来进行代理
  • IntroductionIntercepter
  • 影响了目标物件的行为定义,直接增 加了目标物件的职责
  • Spring DAO
  • 说明
  • JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不一样数据库供应商抛出的错误消息。异常层次结构简化了错误处理,而且极大地下降了须要编写的异常代码数量(例如打开和关闭链接)。Spring DAO 的面向 JDBC 的异常听从通用的 DAO 异常层次结构
  • Spring ORM
  • 说明
  • Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map
  • 全部这些都听从 Spring 的通用事务和 DAO 异常层次结构
  • Spring Web 模块
  • 说明
  • Web 上下文模块创建在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。因此,Spring 框架支持与 Jakarta Struts 的集成
  • Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工做
  • Spring MVC 框架
  • 说明
  • MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现
  • 经过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI
  • Spring事务
  • 概述
  • 事务首先是一系列操做组成的工做单元,该工做单元内的操做是不可分割的,即要么全部操做都作,要么全部操做都不作
  • ACID
  • 原子性(Atomicity)
  • 即事务是不可分割的最小工做单元,事务内的操做要么全作,要么全不作
  • 一致性(Consistency)

工做一到五年的java 开发工程师朋友能够加入咱们Java架构交流群:760940986 群内提供 高可用,高并发,spring源码,mybatis源码,JVM,大数据,Netty等多个技术知识的架构视频资料 还有大把大牛在群内交流以及解答面试指导,问题答疑~~要进来和大牛交流学习提高提高本身吗~~~~
java

  • 在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据仍是处于正确的状态,即数据完整性约束没有被破坏
  • 如银行转账,A转账给B,必须保证A的钱必定转给B,必定不会出现A的钱转了但B没收到,不然数据库的数据就处于不一致(不正确)的状态
  • 隔离性(Isolation)
  • 并发事务执行之间无影响,在一个事务内部的操做对其余事务是不产生影响,这须要事务隔离级别来指定隔离性
  • 持久性(Durability)
  • 事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因好比遇到系统故障或断电形成数据不一致或丢失
  • 常见问题
  • 丢失更新、
  • 两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而致使第一个事务更新的数据丢失,这是因为没有加锁形成的
  • 脏读
  • 一个事务看到了另外一个事务未提交的更新数据
  • 不可重复读、
  • 在同一事务中,屡次读取同一数据却返回不一样的结果;也就是有其余事务更改了这些数据
  • 不可重复读的重点是修改
  • 幻读
  • 一个事务在执行过程当中读取到了另外一个事务已提交的插入数据;即在第一个事务开始时读取到一批数据,但此后另外一个事务又插入了新数据并提交,此时第一个事务又读取这批数据但发现多了一条,即好像发生幻觉同样
  • 幻读的重点在于新增或者删除
  • 隔离级别
  • 未提交读(Read Uncommitted)
  • 最低隔离级别,一个事务能读取到别的事务未提交的更新数据,很不安全,可能出现丢失更新、脏读、不可重复读、幻读
  • 提交读(Read Committed)
  • 一个事务能读取到别的事务提交的更新数据,不能看到未提交的更新数据,不可能可能出现丢失更新、脏读,但可能出现不可重复读、幻读
  • 可重复读(Repeatable Read)
  • 保证同一事务中前后执行的屡次查询将返回同一结果,不受其余事务影响,可能出现丢失更新、脏读、不可重复读,但可能出现幻读
  • 序列化(Serializable)
  • 最高隔离级别,不容许事务并发执行,而必须串行化执行,最安全,不可能出现更新、脏读、不可重复读、幻读
  • 隔离级别越高,数据库事务并发执行性能越差,能处理的操做越少。所以在实际项目开发中为了考虑并发性能通常使用提交读隔离级别,它能避免丢失更新和脏读,尽管不可重复读和幻读不能避免,但能够在可能出现的场合使用悲观锁或乐观锁来解决这些问题
  • 从数据库系统的角度来看,锁分为如下三种类型
  • 独占锁(Exclusive Lock)
  • 独占锁锁定的资源只容许进行锁定操做的程序使用,其它任何对它的操做均不会被接受。执行数据更新命令,即INSERT、 UPDATE或DELETE 命令时,SQL Server 会自动使用独占锁。但当对象上有其它锁存在时,没法对其加独占锁。独占锁一直到事务结束才能被释放
  • 共享锁(Shared Lock)
  • 共享锁锁定的资源能够被其它用户读取,但其它用户不能修改它。在SELECT 命令执行时,SQL Server 一般会对对象进行共享锁锁定。一般加共享锁的数据页被读取完毕后,共享锁就会当即被释放
  • 更新锁(Update Lock)
  • 更新锁是为了防止死锁而设立的。当SQL Server 准备更新数据时,它首先对数据对象做更新锁锁定,这样数据将不能被修改,但能够读取。等到SQL Server 肯定要进行更新数据操做时,它会自动将更新锁换为独占锁。但当对象上有其它锁存在时,没法对其做更新锁锁定
  • 从程序员的角度看,锁分为如下两种类型
  • 悲观锁(Pessimistic Lock)
  • 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其余事务,以及来自外部系统的事务处理)修改持保守态度,所以在整个数据处理过程当中,将数据处于锁定状态。悲观锁的实现,每每依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,不然,即便在本系统中实现了加锁机制,也没法保证外部系统不会修改数据)
  • 乐观锁(Optimistic Lock)
  • 相对悲观锁而言,乐观锁机制采起了更加宽松的加锁机制。悲观锁大多数状况下依靠数据库的锁机制实现,以保证操做最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销每每没法承受
  • 而乐观锁机制在必定程度上解决了这个问题。乐观锁,大可能是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增长一个版本标识,在基于数据库表的版本解决方案中,通常是经过为数据库表增长一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,以后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如 果提交的数据版本号大于数据库表当前版本号,则予以更新,不然认为是过时数据
  • 数据库事务类型
  • 本地事务
  • 就是普通事务,能保证单台数据库上的操做的ACID,被限定在一台数据库上
  • 分布式事务
  • 涉及两个或多个数据库源的事务,即跨越多台同类或异类数据库的事务(由每台数据库的本地事务组成的),分布式事务旨在保证这些本地事务的全部操做的ACID,使事务能够跨越多台数据库
  • Java事务类型
  • JDBC事务:就是数据库事务类型中的本地事务,经过Connection对象的控制来管理事务
  • JTA事务:JTA指Java事务API(Java Transaction API),是Java EE数据库事务规范, JTA只提供了事务管理接口,由应用程序服务器厂商(如WebSphere Application Server)提供实现,JTA事务比JDBC更强大,支持分布式事务
  • Java EE事务类型
  • 本地事务:使用JDBC编程实现事务
  • 全局事务:由应用程序服务器提供,使用JTA事务
  • 编程实现
  • 声明式事务: 经过注解或XML配置文件指定事务信息
  • 编程式事务:经过编写代码实现事务
  • Spring事务使用
  • 说明
  • 结构
  • DataSource
  • JdbcDataSource
  • SessionFactory
  • EntityManager
  • TransactionManager
  • DataSourceTransactionManager
  • HibernateTransactionManager
  • JpaTransactionManager
  • 代理机制
  • Bean和代理
  • 每一个Bean有一个代理
  • 全部Bean共享一个代理基类
  • 使用拦截器
  • 使用TX标签配置的拦截器
  • 全注解配置
  • 不管哪一种配置方式,通常变化的只是代理机制这部分
  • 5种实现方式
  • 每一个Bean都有一个代理
  • 每一个Bean用TransactionProxyFactoryBean代理
  • 全部Bean共享一个代理基类
  • 全部Bean都集成TransactionProxyFactoryBean
  • 使用拦截器
  • 拦截器:TransactionInterceptor
  • 根据beanName匹配后进行自动代理: BeanNameAutoProxyCreator
  • 使用tx标签配置的拦截器
  • <tx:advice/>
  • <aop:config/>
  • 全注解
  • Transactional
  • Spring扩展
  • BeanPostProcessor
  • BeanPostProcessor是Spring容器的一个扩展点,能够进行自定义的实例化、初始化、依赖装配、依赖检查等流程,便可以覆盖默认的实例化,也能够加强初始化、依赖注入、依赖检查等流程
  • BeanFactory <- AbstractBeanFactory <- AbstractAutowireCapableBeanFactory <- DefaultListableBeanFactory:AbstractAutowireCapableBeanFactory.createBean()负责Bean的初始化到消亡周期
  • resolveBeanClass(mbd, beanName); 解析Bean class,若class配置错误将抛出CannotLoadBeanClassException
  • mbd.prepareMethodOverrides(); 准备和验证配置的方法注入,若验证失败抛出BeanDefinitionValidationException
  • Object bean = resolveBeforeInstantiation(beanName, mbd)
  • 执行InstantiationAwareBeanPostProcessor的实例化的预处理回调方法postProcessBeforeInstantiation(自定义的实例化,如建立代理)
  • 执行InstantiationAwareBeanPostProcessor的实例化的后处理回调方法postProcessAfterInitialization(如依赖注入),若是3.1处返回的Bean不为null才执行
  • 若是3处的扩展点返回的bean不为空,直接返回该bean,后续流程不须要执行
  • Object beanInstance = doCreateBean(beanName, mbd, args); 执行spring的建立bean实例的流程
  • createBeanInstance(beanName, mbd, args); 实例化Bean
  • instantiateUsingFactoryMethod 工厂方法实例化
  • 构造器实例化
  • 若是以前已经解析过构造器
  • autowireConstructor:有参调用autowireConstructor实例化
  • instantiateBean:无参调用instantiateBean实例化
  • 若是以前没有解析过构造器
  • 经过SmartInstantiationAwareBeanPostProcessor 的determineCandidateConstructors 回调方法解析构造器,第二个BeanPostProcessor扩展点,返回第一个解析成功(返回值不为null)的构造器组
  • autowireConstructor:若是(6.2.2.1返回的不为null,且是有参构造器,调用autowireConstructor实例化
  • instantiateBean: 不然调用无参构造器实例化
  • applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName):执行Bean定义的合并
  • 执行MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition回调方法,进行bean定义的合并
  • addSingletonFactory(beanName, new ObjectFactory())
  • SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference,当存在循环依赖时,经过该回调方法获取及早暴露的Bean实例
  • populateBean(beanName, mbd, instanceWrapper);装配Bean依赖
  • InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation;第五个BeanPostProcessor扩展点,在实例化Bean以后,全部其余装配逻辑以前执行,若是false将阻止其余的InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation的执行和从(9.2到(9.5的执行,一般返回true
  • autowireByName、autowireByType:根据名字和类型进行自动装配
  • InstantiationAwareBeanPostProcessor的postProcessPropertyValues,完成其余定制的一些依赖注入,如
  • AutowiredAnnotationBeanPostProcessor执行@Autowired注解注入
  • CommonAnnotationBeanPostProcessor执行@Resource等注解的注入
  • PersistenceAnnotationBeanPostProcessor执行@ PersistenceContext等JPA注解的注入
  • RequiredAnnotationBeanPostProcessor执行@Required注解的检查等等
  • checkDependencies:依赖检查
  • applyPropertyValues:应用明确的setter属性注入
  • initializeBean(beanName, exposedObject, mbd); 执行初始化Bean流程
  • invokeAwareMethods(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware):调用一些Aware标识接口注入如BeanName、BeanFactory
  • BeanPostProcessor的postProcessBeforeInitialization:在调用初始化以前完成一些定制的初始化任务,如:
  • BeanValidationPostProcessor完成JSR-303 @Valid注解Bean验证
  • InitDestroyAnnotationBeanPostProcessor完成@PostConstruct注解的初始化方法调用
  • ApplicationContextAwareProcessor完成一些Aware接口的注入(如EnvironmentAware、ResourceLoaderAware、ApplicationContextAware),其返回值将替代原始的Bean对象
  • invokeInitMethods : 调用初始化方法
  • InitializingBean的afterPropertiesSet :调用InitializingBean的afterPropertiesSet回调方法
  • 经过xml指定的自定义init-method :调用经过xml配置的自定义init-method
  • BeanPostProcessor的postProcessAfterInitialization
  • AspectJAwareAdvisorAutoProxyCreator(完成xml风格的AOP配置(<aop:config>)的目标对象包装到AOP代理对象)
  • AnnotationAwareAspectJAutoProxyCreator(完成@Aspectj注解风格(<aop:aspectj-autoproxy> @Aspect)的AOP配置的目标对象包装到AOP代理对象),其返回值将替代原始的Bean对象
  • registerDisposableBeanIfNecessary(beanName, bean, mbd) : 注册Bean的销毁方法(只有非原型Bean可注册)
  • 单例Bean的销毁流程
  • DestructionAwareBeanPostProcessor的postProcessBeforeDestruction : 如InitDestroyAnnotationBeanPostProcessor完成@PreDestroy注解的销毁方法注册和调用
  • DisposableBean的destroy:注册/调用DisposableBean的destroy销毁方法
  • 经过xml指定的自定义destroy-method : 注册/调用经过XML指定的destroy-method销毁方法
  • Scope的registerDestructionCallback:注册自定义的Scope的销毁回调方法,如RequestScope、SessionScope等
  • Spring内置的BeanPostProcessor
  • ApplicationContextAwareProcessor
  • 容器启动时会自动注册
  • 注入那些实现ApplicationContextAware、MessageSourceAware、ResourceLoaderAware、EnvironmentAware、
EmbeddedValueResolverAware、ApplicationEventPublisherAware标识接口的Bean须要的相应实例
  • 在postProcessBeforeInitialization回调方法中进行实施
  • CommonAnnotationBeanPostProcessor
  • CommonAnnotationBeanPostProcessor继承InitDestroyAnnotationBeanPostProcessor,当在配置文件有<context:annotation-config>或<context:component-scan>会自动注册
  • 提供对JSR-250规范注解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持、
  • 经过@Resource注解进行依赖注入
  • postProcessPropertyValues:经过此回调进行@Resource注解的依赖注入
  • 用于执行@PostConstruct 和@PreDestroy 注解的初始化和销毁方法的扩展点
  • postProcessBeforeInitialization()将会调用bean的@PostConstruct方法
  • postProcessBeforeDestruction()将会调用单例 Bean的@PreDestroy方法(此回调方法会在容器销毁时调用)
  • AutowiredAnnotationBeanPostProcessor
  • 当在配置文件有<context:annotation-config>或<context:component-scan>会自动注册
  • 提供对JSR-330规范注解的支持和Spring自带注解的支持
  • Spring自带注解的依赖注入支持,@Autowired和@Value
  • determineCandidateConstructors :决定候选构造器
  • postProcessPropertyValues :进行依赖注入
  • 对JSR-330规范注解的依赖注入支持,@Inject
  • RequiredAnnotationBeanPostProcessor
  • 当在配置文件有<context:annotation-config>或<context:component-scan>会自动注册
  • 提供对@Required注解的方法进行依赖检查支持
  • postProcessPropertyValues:若是检测到没有进行依赖注入时抛出BeanInitializationException异常
  • PersistenceAnnotationBeanPostProcessor
  • 当在配置文件有<context:annotation-config>或<context:component-scan>会自动注册
  • 经过对JPA @javax.persistence.PersistenceUnit和@ javax.persistence.PersistenceContext注解进行依赖注入的支持
  • postProcessPropertyValues : 根据@PersistenceUnit/@PersistenceContext进行EntityManagerFactory和EntityManager的支持
  • AbstractAutoProxyCreator
  • AspectJAwareAdvisorAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator都是继承AbstractAutoProxyCreator
  • AspectJAwareAdvisorAutoProxyCreator提供对(<aop:config>)声明式AOP的支持、
  • AnnotationAwareAspectJAutoProxyCreator提供对(<aop:aspectj-autoproxy>)注解式(@AspectJ)AOP的支持
  • 当使用<aop:config>配置时自动注册AspectJAwareAdvisorAutoProxyCreator
  • 使用<aop:aspectj-autoproxy>时会自动注册AnnotationAwareAspectJAutoProxyCreator
  • predictBeanType:预测Bean的类型,若是目标对象被AOP代理对象包装,此处将返回AOP代理对象的类型
  • postProcessBeforeInstantiation:配置TargetSourceCreator进行自定义TargetSource建立时,会建立代理对象并中断默认Spring建立流程
  • getEarlyBeanReference和postProcessAfterInitialization是两者选一的,并且单例Bean目标对象只能被加强一次,而原型Bean目标对象可能被包装屡次
  • BeanValidationPostProcessor
  • 默认不自动注册,Spring3.0开始支持
  • 提供对JSR-303验证规范支持
  • 根据afterInitialization是false/true决定调用postProcessBeforeInitialization或postProcessAfterInitialization来经过JSR-303规范验证Bean,默认false
  • BeanPostProcessor如何注册
  • 如ApplicationContextAwareProcessor会在ApplicationContext容器启动时自动注册,而CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor会在当你使用<context:annotation-config>或<context:component-scan>配置时自动注册
  • 只要将BeanPostProcessor注册到容器中,Spring会在启动时自动获取并注册
  • BeanPostProcessor的执行顺序
  • 若是使用BeanFactory实现,非ApplicationContext实现,BeanPostProcessor执行顺序就是添加顺序
  • 若是使用的是AbstractApplicationContext(实现了ApplicationContext)的实现,则经过以下规则指定顺序
  • PriorityOrdered(继承了Ordered),实现了该接口的BeanPostProcessor会在第一个顺序注册,标识高优先级顺序,即比实现Ordered的具备更高的优先级
  • Ordered,实现了该接口的BeanPostProcessor会第二个顺序注册
  • Spring自定义功能标签
  • XML一般经过DTD、XSD定义,但DTD的表达能力较弱,XSD定义则能力比较强,可以定义类型,出现次数等。自定义标签须要XSD支持,在实现时使用Namespace扩展来支持自定义标签
  • 工做过程
  • Spring经过XML解析程序将其解析为DOM树,经过NamespaceHandler指定对应的Namespace的BeanDefinitionParser将其转换成BeanDefinition
  • 再经过Spring自身的功能对BeanDefinition实例化对象
  • 制做定义标签
  • 编写XSD文件
  • META-INF/spring.schemas :配置XSD文件
  • 在解析XML文件时将XSD重定向到本地文件,避免在解析XML文件时须要上网下载XSD文件。经过现实org.xml.sax.EntityResolver接口来实现该功能
  • META-INF/spring.handlers
  • 指定NamespaceHandler(实现org.springframework.beans.factory.xml.NamespaceHandler)接口,或使用org.springframework.beans.factory.xml.NamespaceHandlerSupport的子类
  • NamespaceHandler实现中注册标签和解析器
  • 实现配置 BeanDefinitionParser
  • 解析XML,实例构造想要的Bean为BeanDefinition对象
  • 配置自定义标签并获取对应的Bean
  • Spring自定义注解
  • 使用Spring扩展机制
  • Spring PropertyPlaceholderConfigurer配置扩展
  • 经过扩展PropertyPlaceholderConfigurer类自定义Spring取配置值的行为
  • 如经过扩展PropertyPlaceholderConfigurer,内部封装调用ZooKeeper动态配置获取,从而把ZooKeeper的Name Service集成到现有的Spring容器中
  • Spring设计模式
  • 单例模式
  • Spring的Bean默认是单例的(Singleton)
  • 工厂模式
  • 简单工厂模式(Simple Factory)
  • 简单工厂模式又称静态工厂方法模式。重命名上就能够看出这个模式必定很简单。它存在的目的很简单:定义一个用于建立对象的接口
  • 在简单工厂模式中,一个工厂类处于对产品类实例化调用的中心位置上,它决定哪个产品类应当被实例化, 如同一个交通警察站在来往的车辆流中,决定放行那一个方向的车辆向那一个方向流动同样
  • 组成
  • 工厂类角色:这是本模式的核心,含有必定的商业逻辑和判断逻辑。在Java中它每每由一个具体类实现
  • 抽象产品角色:它通常是具体产品继承的父类或者实现的接口。在Java中由接口或者抽象类来实现
  • 具体产品角色:工厂类所建立的对象就是此角色的实例。在java中由一个具体类实现
  • 工厂方法模式(Factory Method)
  • 工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式里再也不只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去作
  • 组成
  • 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现
  • 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以建立对应的具体产品的对象
  • 抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中通常有抽象类或者接口来实现
  • 具体产品角色:具体工厂角色所建立的对象就是此角色的实例。在java中由具体的类来实现
  • 工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;并且这样使得结构变得灵活 起来——当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就能够被客户使用,而没必要去修改任何已有的代 码。能够看出工厂角色的结构也是符合开闭原则的
  • 能够看出工厂方法的加入,使得对象的数量成倍增加。当产品种类很是多时,会出现大量的与之对应的工厂对象,这不是咱们所但愿的。由于若是不能避免这种情 况,能够考虑使用简单工厂模式与工厂方法模式相结合的方式来减小工厂类:即对于产品树上相似的种类(通常是树的叶子中互为兄弟的)使用简单工厂模式来实现
  • 简单工厂和工厂方法模式的比较
  • 工厂方法模式和简单工厂模式在定义上的不一样是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式能够容许不少实的工厂类从抽象工厂类继承下来, 从而能够在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式
  • 反过来说,简单工厂模式是由工厂方法模式退化而来。设想若是咱们很是肯定一个系统只须要一个实的工厂类, 那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,咱们就退化到简单工厂模式了
  • 应用场景
  • 当一个类不知道它所必须建立的对象的类的时候
  • 当一个类但愿由它的子类来指定它所建立的对象的时候
  • 当类将建立对象的职责委托给多个帮助子类中的某一个,而且你但愿将哪个帮助子类是代理者这一信息局部化的时候
  • 抽象工厂模式(Abstract Factory)
  • 应用场景
  • 一个系统不该当依赖于产品类实例如何被建立、组合和表达的细节,这对于全部形态的工厂模式都是重要的
  • 这个系统有多于一个的产品族,而系统只消费其中某一产品族
  • 同属于同一个产品族的产品是在一块儿使用的,这一约束必须在系统的设计中体现出来
  • 系统提供一个产品类的库,全部的产品以一样的接口出现,从而使客户端不依赖于实现
  • 总结
  • 简单工厂模式是由一个具体的类去建立其余类的实例,父类是相同的,父类是具体的
  • 工厂方法模式是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样作的目的是将类的实例化操做延迟到子类中完成
  • 抽象工厂模式提供一个建立一系列相关或相互依赖对象的接口,而无须指定他们具体的类。它针对的是有多个产品的等级结构。而工厂方法模式针对的是一个产品的等级结构
  • 论是简单工厂模式,工厂方法模式,仍是抽象工厂模式,他们都属于工厂模式,在形式和特色上也是极为类似的,他们的最终目的都是为了解耦。在使用时,咱们没必要去在乎这个模式到底工厂方法模式仍是抽象工厂模式,由于他们之间的演变经常是使人琢磨不透的。常常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,因为类中的产品构成了不一样等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减小一个方法使的提供的产品再也不构成产品族以后,它就演变成了工厂方法模式
  • 代理模式
  • 对其余对象提供一种代理以控制对这个对象的访问
  • 代理模式的主要做用是为其余对象提供一种代理以控制对这个对象的访问。在某些状况下,一个对象不想或者不能直接引用另外一个对象,而代理对象能够在客户端和目标对象之间起到中介的做用
  • 代理模式的思想是为了提供额外的处理或者不一样的操做而在实际对象与调用者之间插入一个代理对象
  • 代理模式的三个角色
  • 抽象角色:声明真实对象和代理对象的共同接口
  • 代理角色:代理对象角色内部含有对真实对象的引用,从而能够操做真实对象,同时代理对象提供与真实对象相同的接口以便在任什么时候刻都能代替真实对象。同时,代理对象能够在执行真实对象操做时,附加其余的操做,至关于对真实对象进行封装
  • 真实角色:代理角色所表明的真实对象,是咱们最终要引用的对象
  • Spring动态代理
  • JDK动态代理(JdkDynamicAopProxy )
  • JDK动态代理只能针对实现了接口的类生成代理
  • 接口 + InvocationHandler + 目标对象 = 代理
  • Cglib动态代理(Cglib2AopProxy )
  • CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的全部方法,因此该类或方法不能声明称final的
  • 若是目标对象没有实现接口,则默认会采用CGLIB代理
  • 接口或类 + MethodInterceptor + 目标对象 = 代理
  • Facade门面(外观)模式
  • 概述
  • 外观模式,咱们经过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会下降应用程序的复杂度,而且提升了程序的可维护性
  • 问题
  • 为了下降复杂性,经常将系统划分为若干个子系统。可是如何作到各个系统之间的通讯和相互依赖关系达到最小呢?
  • 解决方案
  • 为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。引入外观角色以后,用户只须要直接与外观角色交互,用户与子系统之间的复杂关系由外观角色来实现,从而下降了系统的耦合度
  • 适用性
  • 当你要为一个复杂子系统提供一个简单接口时,子系统每每由于不断演化而变得愈来愈复杂。大多数模式使用时都会产生更多更小的类
  • 这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不须要定制子系统的用户带来一些使用上的困难。Facade能够提供一个简单的缺省视图
  • 这一视图对大多数用户来讲已经足够,而那些须要更多的可定制性的用户能够越过Facade层
  • 客户程序与抽象类的实现部分之间存在着很大的依赖性。引入 Facade将这个子系统与客户以及其余的子系统分离,能够提升子系统的独立性和可移植性
  • 当你须要构建一个层次结构的子系统时,使用 Facade模式定义子系统中每层的入口点。若是子系统之间是相互依赖的,你可让它们仅经过Facade进行通信,从而简化了它们之间的依赖关系
  • 构建模式的组成
  • 外观角色(Facade):是模式的核心,他被客户Client角色调用,知道各个子系统的功能。同时根据客户角色已有的需求预订了几种功能组合
  • 子系统角色(Subsystem classes):实现子系统的功能,并处理由Facade对象指派的任务。对子系统而言,Facade和Client角色是未知的,没有Facade的任何相关信息;即没有指向Facade的实例
  • 客户角色(client):调用Facade角色得到完成相应的功能
  • 效果优势
  • 优势
  • 对客户屏蔽子系统组件,减小了客户处理的对象数目并使得子系统使用起来更加容易。经过引入外观模式,客户代码将变得很简单,与之关联的对象也不多
  • 实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只须要调整外观类便可
  • 下降了大型软件系统中的编译依赖性,并简化了系统在不一样平台之间的移植过程,由于编译一个子系统通常不须要编译全部其余的子系统。一个子系统的修改对其余子系统没有任何影响,并且子系统内部变化也不会影响到外观对象
  • 只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类
  • 缺点
  • 不能很好地限制客户使用子系统类,若是对客户访问子系统类作太多的限制则减小了可变性和灵活性
  • 在不引入抽象外观类的状况下,增长新的子系统可能须要修改外观类或客户端的源代码,违背了“开闭原则”
  • 与其余相关模式对比
  • 抽象工厂模式
  • Abstract Factory式能够与Facade模式一块儿使用以提供一个接口,这一接口可用来以一种子系统独立的方式建立子系统对象。 Abstract Factory也能够代替Facade模式隐藏那些与平台相关的类
  • Mediator模式与Facade模式的类似之处是,它抽象了一些已有的类的功能。然而,Mediator的目的是对同事之间的任意通信进行抽象,一般集中不属于任何单个对象的功能
  • Mediator的同事对象知道中介者并与它通讯,而不是直接与其余同类对象通讯。相对而言,Facade模式仅对子系统对象的接口进行抽象,从而使它们更容易使用;它并不定义新功能,子系统也不知道Facade的存在
  • 适配器模式是将一个接口经过适配来间接转换为另外一个接口
  • 外观模式的话,其主要是提供一个整洁的一致的接口给客户端
  • 总结
  • 根据“单一职责原则”,在软件中将一个系统划分为若干个子系统有利于下降整个系统的复杂性,一个常见的设计目标是使子系统间的通讯和相互依赖关系达到最小,而达到该目标的途径之一就是引入一个外观对象,它为子系统的访问提供了一个简单而单一的入口
  • 外观模式是“迪米特法则”的体现,经过引入一个新的外观类能够下降原有系统的复杂度,外观类充当了客户类与子系统类之间的“第三者”,同时下降客户类与子系统类的耦合度。外观模式就是实现代码重构以便达到“迪米特法则”要求的一个强有力的武器
  • 外观模式要求一个子系统的外部与其内部的通讯经过一个统一的外观对象进行,外观类将客户端与子系统的内部复杂性分隔开,使得客户端只须要与外观对象打交道,而不须要与子系统内部的不少对象打交道
  • 外观模式从很大程度上提升了客户端使用的便捷性,使得客户端无须关心子系统的工做细节,经过外观角色便可调用相关功能
  • 不要试图经过外观类为子系统增长新行为 ,不要经过继承一个外观类在子系统中加入新的行为,这种作法是错误的。外观模式的用意是为子系统提供一个集中化和简化的沟通渠道,而不是向子系统加入新的行为,新的行为的增长应该经过修改原有子系统类或增长新的子系统类来实现,不能经过外观类来实现
  • 模式扩展
  • 一个系统有多个外观类
  • 在外观模式中,一般只须要一个外观类,而且此外观类只有一个实例,换言之它是一个单例类。在不少状况下为了节约系统资源,通常将外观类设计为单例类。固然这并不意味着在整个系统里只能有一个外观类,在一个系统中能够设计多个外观类,每一个外观类都负责和一些特定的子系统交互,向用户提供相应的业务功能
  • 不要试图经过外观类为子系统增长新行为
  • 不要经过继承一个外观类在子系统中加入新的行为,这种作法是错误的。外观模式的用意是为子系统提供一个集中化和简化的沟通渠道,而不是向子系统加入新的行为,新的行为的增长应该经过修改原有子系统类或增长新的子系统类来实现,不能经过外观类来实现
  • 外观模式与迪米特法则
  • 外观模式创造出一个外观对象,将客户端所涉及的属于一个子系统的协做伙伴的数量减到最少,使得客户端与子系统内部的对象的相互做用被外观对象所取代。外观类充当了客户类与子系统类之间的“第三者”,下降了客户类与子系统类之间的耦合度,外观模式就是实现代码重构以便达到“迪米特法则”要求的一个强有力的武器
  • 抽象外观类的引入
  • 外观模式最大的缺点在于违背了“开闭原则”
  • 当增长新的子系统或者移除子系统时须要修改外观类,能够经过引入抽象外观类在必定程度上解决该问题,客户端针对抽象外观类进行编程。对于新的业务需求,不修改原有外观类,而对应增长一个新的具体外观类,由新的具体外观类来关联新的子系统对象,同时经过修改配置文件来达到不修改源代码并更换外观类的目的
  • 命令模式
  • 命令模式角色
  • Client:建立一个具体命令(ConcreteCommand)对象并肯定其接收者
  • Command 命令:声明了一个给全部具体命令类的抽象接口
  • ConcreteCommand:具体命令,定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操做。execute()方法一般叫作执行方法
  • Invoker 请求者:负责调用命令对象执行请求,相关的方法叫作行动方法
  • Receiver 接受者:负责具体实施和执行一个请求。任何一个类均可以成为接收者,实施和执行请求的方法叫作行动方法
  • 命令模式的优势
  • 更松散的耦合
  • 命令模式使得发起命令的对象——客户端,和具体实现命令的对象——接收者对象彻底解耦,也就是说发起命令的对象彻底不知道具体实现对象是谁,也不知道如何实现
  • 更动态的控制
  • 命令模式把请求封装起来,能够动态地对它进行参数化、队列化和日志化等操做,从而使得系统更灵活
  • 很天然的复合命令
  • 命令模式中的命令对象可以很容易地组合成复合命令,也就是宏命令,从而使系统操做更简单,功能更强大
  • 更好的扩展性
  • 因为发起命令的对象和具体的实现彻底解耦,所以扩展新的命令就很容易,只须要实现新的命令对象,而后在装配的时候,把具体的实现对象设置到命令对象中,而后就可使用这个命令对象,已有的实现彻底不用变化
  • Tomcat命令模式
  • 把 Tomcat 中两个核心组件 Connector 和 Container,比做一对夫妻。男的将接受过来的请求以命令的方式交给女主人。对应到 Connector 和 Container,Connector 也是经过命令模式调用 Container 的
  • 模块
  • Connector 做为抽象请求者(Invoker )
  • HttpConnector 做为具体请求者(Invoker )
  • HttpProcessor 做为命令(Command)
  • Container 做为命令的抽象接受者(Receiver)
  • ContainerBase 做为具体的接受者(Receiver)
  • 客户端就是应用服务器 Server 组件了(Client)
  • Server 首先建立命令请求者 HttpConnector 对象,而后建立命令 HttpProcessor 命令对象。再把命令对象交给命令接受者 ContainerBase 容器来处理命令。命令的最终是被 Tomcat 的 Container 执行的。命令能够以队列的方式进来,Container 也能够以不一样的方式来处理请求,如 HTTP1.0 协议和 HTTP1.1 的处理方式就会不一样
  • 更多例子请看文章“Java设计模式之命令模式”中的遥控器例子
  • 适用状况
  • 系统须要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互
  • 命令模式容许请求的一方和接收的一方独立开来,使得请求的一方没必要知道接收请求的一方的接口,更没必要知道请求是怎么被接收,以及操做是否被执行、什么时候被执行,以及是怎么被执行的
  • 系统须要在不一样的时间指定请求、将请求排队和执行请求
  • 系统须要支持命令的撤销(Undo)操做和恢复(Redo)操做
  • 系统须要将一组操做组合在一块儿,即支持宏命令
  • 命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联
  • 装饰者模式
  • 说明
  • 装饰模式又名包装(Wrapper)模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案
  • 装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会以为对象在装饰前和装饰后有什么不一样。装饰模式能够在不使用创造更多子类的状况下,将对象的功能加以扩展
  • 装饰模式的结构
  • 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象
  • 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类
  • 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口
  • 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任
  • 装饰模式的简化
  • 若是只有一个ConcreteComponent类,那么能够考虑去掉抽象的Component类(接口),把Decorator做为一个ConcreteComponent子类
  • 若是只有一个ConcreteDecorator类,那么就没有必要创建一个单独的Decorator类,而能够把Decorator和ConcreteDecorator的责任合并成一个类。甚至在只有两个ConcreteDecorator类的状况下,均可以这样作
  • 装饰模式的优势
  • 装饰模式与继承关系的目的都是要扩展对象的功能,可是装饰模式能够提供比继承更多的灵活性。装饰模式容许系统动态决定“贴上”一个须要的“装饰”,或者除掉一个不须要的“装饰”。继承关系则不一样,继承关系是静态的,它在系统运行前就决定了
  • 经过使用不一样的具体装饰类以及这些装饰类的排列组合,设计师能够创造出不少不一样行为的组合
  • 装饰模式的缺点
  • 因为使用装饰模式,能够比使用继承关系须要较少数目的类。使用较少的类,固然使设计比较易于进行。可是,在另外一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像
  • 在JAVA I/O库中的应用
  • 装饰模式在Java语言中的最著名的应用莫过于Java I/O标准库的设计了
  • 因为Java I/O库须要不少性能的各类组合,若是这些性能都是用继承的方法实现的,那么每一种组合都须要一个类,这样就会形成大量性能重复的类出现。而若是采用装饰模式,那么类的数目就会大大减小,性能的重复也能够减至最少。所以装饰模式是Java I/O库的基本模式
  • 结构
  • 抽象构件(Component)角色:由InputStream扮演。这是一个抽象类,为各类子类型提供统一的接口
  • 具体构件(ConcreteComponent)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStream等类扮演。它们实现了抽象构件角色所规定的接口
  • 抽象装饰(Decorator)角色:由FilterInputStream扮演。它实现了InputStream所规定的接口
  • 具体装饰(ConcreteDecorator)角色:由几个类扮演,分别是BufferedInputStream、DataInputStream以及两个不经常使用到的类LineNumberInputStream、PushbackInputStream
  • 半透明的装饰模式
  • 装饰模式和适配器模式都是“包装模式(Wrapper Pattern)”,它们都是经过封装其余对象达到设计的目的的,可是它们的形态有很大区别
  • 理想的装饰模式在对被装饰对象进行功能加强的同时,要求具体构件角色、装饰角色的接口与抽象构件角色的接口彻底一致
  • 而适配器模式则否则,通常而言,适配器模式并不要求对源对象的功能进行加强,可是会改变源对象的接口,以便和目标接口相符合
  • 装饰模式有透明和半透明两种,这两种的区别就在于装饰角色的接口与抽象构件角色的接口是否彻底一致
  • 透明的装饰模式也就是理想的装饰模式,要求具体构件角色、装饰角色的接口与抽象构件角色的接口彻底一致
  • 若是装饰角色的接口与抽象构件角色接口不一致,也就是说装饰角色的接口比抽象构件角色的接口宽的话,装饰角色实际上已经成了一个适配器角色,这种装饰模式也是能够接受的,称为“半透明”的装饰模式
  • 在适配器模式里面,适配器类的接口一般会与目标类的接口重叠,但每每并不彻底相同。换言之,适配器类的接口会比被装饰的目标类接口宽
  • 半透明的装饰模式实际上就是处于适配器模式与装饰模式之间的灰色地带。若是将装饰模式与适配器模式合并成为一个“包装模式”的话,那么半透明的装饰模式倒能够成为这种合并后的“包装模式”的表明
  • InputStream类型中的装饰模式是半透明的
  • 现实世界与理论总归是有一段差距的。纯粹的装饰模式在真实的系统中很难找到。通常所遇到的,都是这种半透明的装饰模式
  • 观察上面的代码,会发现最里层是一个FileInputStream对象,而后把它传递给一个BufferedInputStream对象,通过BufferedInputStream处理,再把处理后的对象传递给了DataInputStream对象进行处理,这个过程其实就是装饰器的组装过程,FileInputStream对象至关于原始的被装饰的对象,而BufferedInputStream对象和DataInputStream对象则至关于装饰器
  • 适配器模式
  • 适配器模式把一个类的接口变换成客户端所期待的另外一种接口,从而使本来因接口不匹配而没法在一块儿工做的两个类可以在一块儿工做
  • 适用场景
  • 系统须要使用现有的类,而这些类的接口不符合系统的接口
  • 想要创建一个能够重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在未来引进的类一块儿工
  • 两个类所作的事情相同或类似,可是具备不一样接口的时候
  • 旧的系统开发的类已经实现了一些功能,可是客户端却只能以另外接口的形式访问,但咱们不但愿手动更改原有类的时候
  • 使用第三方组件,组件接口定义和本身定义的不一样,不但愿修改本身的接口,可是要使用第三方组件接口的功能
  • 角色
  • 目标(Target)角色:这就是所期待获得的接口。注意:因为这里讨论的是类适配器模式,所以目标不能够是类
  • 源(Adapee)角色:如今须要适配的接口
  • 适配器(Adaper)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不能够是接口,而必须是具体类
  • 类适配器模式
  • class Adapter extends Adaptee implements Target
  • 适配器角色Adapter扩展了Adaptee,同时又实现了目标(Target)接口。因为Adaptee没有提供targetMethod()方法,而目标接口又要求这个方法,所以适配器角色Adapter实现了这个方法
  • 对象的适配器模式
  • 与类的适配器模式同样,对象的适配器模式把被适配的类的API转换成为目标类的API
  • 与类的适配器模式不一样的是,对象的适配器模式不是使用继承关系链接到Adaptee类,而是使用委派关系链接到Adaptee类
  • Adaptee类并无targetMethod()方法,而客户端则期待这个方法。为使客户端可以使用Adaptee类,须要提供一个包装(Wrapper)类Adapter。这个包装类包装了一个Adaptee的实例,从而此包装类可以把Adaptee的API与Target类的API衔接起来。Adapter与Adaptee是委派关系,这决定了适配器模式是对象的
  • 类适配器和对象适配器的权衡
  • 类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式
  • 对于类适配器,因为适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一块儿工做,由于继承是静态的关系,当适配器继承了Adaptee后,就不可能再去处理 Adaptee的子类了
  • 对于对象适配器,一个适配器能够把多种不一样的源适配到同一个目标。换言之,同一个适配器能够把源类和它的子类都适配到目标接口。由于对象适配器采用的是对象组合的关系,只要对象类型正确,是否是子类都无所谓
  • 对于类适配器,适配器能够重定义Adaptee的部分行为,至关于子类覆盖父类的部分实现方法
  • 对于对象适配器,要重定义Adaptee的行为比较困难,这种状况下,须要定义Adaptee的子类来实现重定义,而后让适配器组合子类。虽然重定义Adaptee的行为比较困难,可是想要增长一些新的行为则方便的很,并且新增长的行为可同时适用于全部的源
  • 对于类适配器,仅仅引入了一个对象,并不须要额外的引用来间接获得Adaptee
  • 对于对象适配器,须要额外的引用来间接获得Adaptee
  • 建议尽可能使用对象适配器的实现方式,多用合成/聚合、少用继承。固然,具体问题具体分析,根据须要来选用实现方式,最适合的才是最好的
  • 适配器模式的优势
  • 更好的复用性: 系统须要使用现有的类,而此类的接口不符合系统的须要。那么经过适配器模式就可让这些功能获得更好的复用
  • 更好的扩展性: 在实现适配器功能的时候,能够调用本身开发的功能,从而天然地扩展系统的功能
  • 经过适配器,客户端能够调用同一接口,于是对客户端来讲是透明的。这样作更简单、更直接、更紧凑
  • 复用了现存的类,解决了现存类和复用环境要求不一致的问题
  • 将目标类和适配者类解耦,经过引入一个适配器类重用现有的适配者类,而无需修改原有代码
  • 一个对象适配器能够把多个不一样的适配者类适配到同一个目标,也就是说,同一个适配器能够把适配者类和它的子类都适配到目标接口
  • 适配器模式的缺点
  • 过多的使用适配器,会让系统很是零乱,不易总体进行把握。好比,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统若是太多出现这种状况,无异于一场灾难。所以若是不是颇有必要,能够不使用适配器,而是直接对系统进行重构
  • Spring中的适配器模式
  • Spring aop框架对BeforeAdvice、AfterAdvice、ThrowsAdvice三种通知类型的支持其实是借助适配器模式来实现的,这样的好处是使得框架容许用户向框架中加入本身想要支持的任何一种通知类型,上述三种通知类型是Spring aop框架定义的,它们是aop联盟定义的Advice的子类型
  • AdvisorAdapter是一个适配器接口,它定义了本身支持的Advice类型,而且能把一个Advisor适配成MethodInterceptor
  • Adapter
  • MethodBeforeAdviceAdapter
  • AfterReturningAdviceAdapter
  • ThrowsAdviceAdapter
  • 责任链(Chain of Responsibility )模式
  • 说明
  • 责任链模式是一种对象的行为模式。在责任链模式里,不少对象由每个对象对其下家的引用而链接起来造成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求
  • 发出这个请求的客户端并不知道链上的哪个对象最终处理这个请求,这使得系统能够在不影响客户端的状况下动态地从新组织和分配责任
  • 责任链多是一条直线、一个环链或者一个树结构的一部分
  • 结构
  • 抽象处理者(Handler)角色:定义出一个处理请求的接口。若是须要,接口能够定义 出一个方法以设定和返回对下家的引用。这个角色一般由一个Java抽象类或者Java接口实现。上图中Handler类的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操做
  • 具体处理者(ConcreteHandler)角色:具体处理者接到请求后,能够选择将请求处理掉,或者将请求传给下家。因为具体处理者持有对下家的引用,所以,若是须要,具体处理者能够访问下家
  • 适用场景
  • 有多个的对象能够处理一个请求,哪一个对象处理该请求运行时刻自动肯定
  • 在不明确指定接收者的状况下,向多个对象中的一个提交一个请求
  • 处理一个请求的对象集合应被动态指定
  • 跟命令模式区别
  • 职责链模式对于请求的处理是不知道最终处理者是谁,因此是运行动态寻找并指定
  • 而命令模式中对于命令的处理时在建立命令是已经显式或隐式绑定了接收者
  • 在 Tomcat 中这种设计模式几乎被完整的使用,tomcat 的容器设置就是责任链模式,从 Engine 到 Host 再到 Context 一直到 Wrapper 都是经过一个链传递请求
  • 监听模式
  • 概念
  • Event Object
  • 继承java.util.EventObject
  • 事件状态对象,用于listener的相应的方法之中,做为参数,通常存在与listerner的方法之中
  • Event Source
  • 具体的事件源,好比说,你点击一个button,那么button就是event source,要想使button对某些事件进行响应,你就须要注册特定的listener
  • Event Listener
  • 继承 java.util.EventListener
  • 对每一个明确的事件的发生,都相应地定义一个明确的Java方法。这些方法都集中定义在事件监听者(EventListener)接口中。 实现了事件监听者接口中一些或所有方法的类就是事件监听者
  • Spring监听模式
  • Tomcat的ServletContextListener
  • 说明
  • Event Object: ServletContextEvent
  • Event Listener: ServletContextListener
  • Event Source: Container 加载Web 应用程序或容器移除Web 应用程序时
  • 监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期
  • 当Servlet 容器启动或终止Web 应用时,会触发ServletContextEvent 事件,该事件由ServletContextListener 来处理
  • ServletContextListener 接口中定义了处理ServletContextEvent事件的两个方法
  • contextInitialized:当Servlet 容器启动Web 应用时调用该方法。在调用完该方法以后,容器再对Filter 初始化,而且对那些在Web 应用启动时就须要被初始化的Servlet 进行初始化
  • contextDestroyed:当Servlet 容器终止Web 应用时调用该方法。在调用该方法以前,容器会先销毁全部的Servlet 和Filter 过滤器
  • 在 web.xml 中进行以下配置,以使得监听器能够起做用(listener和listener-class)
  • Servlet 容器会在启动或终止 Web 应用时,会调用监听器的相关方法。在 web.xml 文件中, <listener> 元素用于向容器注册监听器
  • 在Container 加载Web 应用程序时(例如启动 Container 以后),会呼叫contextInitialized() ,而当容器移除Web 应用程序时,会呼叫contextDestroyed () 方法
  • 当 Web 应用启动时,Servlet 容器先调用contextInitialized() 方法,再调用lifeInit 的init() 方法;当Web 应用终止时,Servlet 容器先调用lifeInit 的destroy() 方法,再调用contextDestroyed() 方法
  • 因而可知,在Web 应用的生命周期中,ServletContext 对象最先被建立,最晚被销毁
  • Spring的ContextLoaderListener
  • 本质上是个ServletContextListener
  • 监听器是启动根IoC容器并把它载入到Web容器的主要功能模块,也是整个Spring Web应用加载IoC的第一个地方
  • ConfigurableWebApplicationContext.refresh()自动装配ApplicationContext的配置信息
  • Spring的ApplicationListener
  • 说明
  • Event Object:
  • ApplicationEvent
  • 是事件,它就是媒介,充当介质的做用
  • Event Listener ( Observer)
  • ApplicationListener
  • 须要到容器中注册。他要关心他所关心的ApplicationEvent
  • Event Source:
  • ApplicationContext(ApplicationEventPublisher)
  • ApplicationEventMulticaster
  • SUBJECT一个代理。他会管理咱们的 ApplicationListener
  • Spring提供了ApplicationEventMulticaster接口,负责管理ApplicationListener和发布ApplicationEvent。ApplicationContext会把相应的事件相关工做委派给ApplicationEventMulticaster接口实现类来作
  • 当ApplicationContext接收到事件后,事件的广播是Spring内部给咱们作的,不须要了解具体的细节
  • 其实在 Spring读取配置文件以后,利用反射,将全部实现ApplicationListener的Bean找出来,注册为容器的事件监听器
  • 当接收到事件的时候,Spring会逐个调用事件配置文件中的监听器
  • ContextClosedEvent:当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的全部 单例Bean都被销毁
  • ContextRefreshedEvent: 当ApplicationContext初始化或者刷新时触发该事件
  • ContextStartedEvent: 当容器调用ConfigurableApplicationContext的 Start()方法开始/从新开始容器时触发该事件
  • ContextStoppedEvent: 当容器调用ConfigurableApplicationContext 的Stop()方法中止容器时触发该事件
  • RequestHandleEvent: 在Web应用中,当一个http请求(request)结束触发该事件
  • 跟观察者模式的区别
  • 模型结构不一样
  • EventListener是传统的c/s界面事件模型,分事件源和事件(状态)角色,事件源要通过事件的包装、成为事件的属性之一再传递给事件监听/处理者,这个事件监听者就至关于观察者。我记得好像VB或C#也是这种模型
  • Observer模式的模型就简洁多了,没有分事件源和事件,两者合二为一为一个角色:被观察者,从字面语义上也应该这样,另外一个是观察者角色
  • 就是我上面说的Observer模式比较EventListener的不一样之处还在于将大部分工做收归Observable根类实现了、包括定义监听者队列、通知方法都实现了,咱们只要继承、调用和传值就好了
  • 如今想一想多是EventListener监听机制是从c/s时代就延续下来的,而Observer模式则是和iterator迭代器模式一样被整合进jdk的,因此如今这两种功用存在交叉的api会同时存在
  • 观察者模式
  • 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,全部依赖于它的对象都获得通知并被自动更新
  • Observer模式的典型应用
  • 侦听事件驱动程序设计中的外部事件
  • 侦听/监视某个对象的状态变化
  • 发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发时,通知邮件列表中的订阅者
  • Observer模式的优势
  • 对象之间能够进行同步通讯
  • 能够同时通知一到多个关联对象
  • 对象之间的关系以松耦合的形式组合,互不依赖
  • Observer模式的结构
  • Subject(被观察者): 被观察的对象。当须要被观察的状态发生变化时,须要通知队列中全部观察者对象。Subject须要维持(添加,删除,通知)一个观察者对象的队列列表
  • ConcreteSubject: 被观察者的具体实现。包含一些基本的属性状态及其余操做
  • Observer(观察者): 接口或抽象类。当Subject的状态发生变化时,Observer对象将经过一个callback函数获得通知
  • ConcreteObserver: 观察者的具体实现。获得通知后将完成一些具体的业务逻辑处理
  • Spring观察者模式应用:跟监听模式相似,参考监听模式
  • 策略模式
  • 定义
  • 策略模式属于对象的行为模式。其用意是针对一组算法,将每个算法封装到具备共同接口的独立的类中,从而使得它们能够相互替换。策略模式使得算法能够在不影响到客户端的状况下发生变化
  • 策略模式,又叫算法簇模式,就是定义了不一样的算法族,而且之间能够互相替换,此模式让算法的变化独立于使用算法的客户
  • 策略模式的好处在于你能够动态的改变对象的行为
  • 设计原则是把一个类中常常改变或者未来可能改变的部分提取出来,做为一个接口,而后在类中包含这个对象的实例,这样类的实例在运行时就能够随意调用实现了这个接口的类的行为
  • 策略模式结构
  • 策略模式是对算法的包装,是把使用算法的责任和算法自己分割开来,委派给不一样的对象管理。策略模式一般把一个系列的算法包装到一系列的策略类里面,做为一个抽象策略类的子类。用一句话来讲,就是:“准备一组算法,并将每个算法封装起来,使得它们能够互换”
  • 策略模式仅仅封装算法,提供新的算法插入到已有系统中,以及老算法从系统中“退休”的方法,策略模式并不决定在什么时候使用何种算法。在什么状况下使用什么算法是由客户端决定的
  • 包含三个角色
  • Context(上下文):使用不一样策略的环境,它能够根据自身的条件选择不一样的策略实现类来完成所要的操做。它持有一个策略实例的引用。建立具体策略对象的方法也能够由他完成
  • Strategy( 抽象策略):抽象策略,定义每一个策略都要实现的策略方法
  • Concrete Strategy( 具体策略对象):具体策略实现类,实现抽象策略中定义的策略方法
  • 认识策略模式
  • 策略模式的重心
  • 策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具备更好的维护性和扩展性
  • 算法的平等性
  • 策略模式一个很大的特色就是各个策略算法的平等性。对于一系列具体的策略算法,你们的地位是彻底同样的,正由于这个平等性,才能实现算法之间能够相互替换。全部的策略算法在实现上也是相互独立的,相互之间是没有依赖的
  • 因此能够这样描述这一系列策略算法:策略算法是相同行为的不一样实现
  • 运行时策略的惟一性
  • 运行期间,策略模式在每个时刻只能使用一个具体的策略实现对象,虽然能够动态地在不一样的策略实现中切换,可是同时只能使用一个
  • 公有的行为
  • 常常见到的是,全部的具体策略类都有一些公有的行为。这时候,就应当把这些公有的行为放到共同的抽象策略角色Strategy类里面。固然这时候抽象策略角色必需要用Java抽象类实现,而不能使用接口
  • 策略模式的优势
  • 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承能够把公共的代码移到父类里面,从而避免代码重复
  • 使用策略模式能够避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采起哪种算法或采起哪种行为的逻辑与算法或行为的逻辑混合在一块儿,通通列在一个多重条件语句里面,比使用继承的办法还要原始和落后
  • 策略模式的缺点
  • 客户端必须知道全部的策略类,并自行决定使用哪个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的状况
  • 因为策略模式把每一个具体的策略实现都单独封装成为类,若是备选的策略不少的话,那么对象的数目就会很可观
  • Spring策略模式的实现
  • Spring 中策略模式使用有多个地方,如 Bean 定义对象的建立以及代理对象的建立等
  • Spring 的代理方式有两个 Jdk 动态代理和 CGLIB 代理,这两个代理方式的使用正是使用了策略模式
  • 抽象策略是 AopProxy 接口
  • Cglib2AopProxy 和 JdkDynamicAopProxy 分别表明两种策略的实现方式
  • ProxyFactoryBean 就是表明 Context 角色,它根据条件选择使用 Jdk 代理方式仍是 CGLIB 方式
  • 三个类(AopProxyFactory,DefaultAopProxyFactory,ProxyCreatorSupport)主要是来负责建立具体策略对象,ProxyFactoryBean 是经过依赖的方法来关联具体策略对象的,它是经过调用策略对象的 getProxy(ClassLoader classLoader) 方法来完成操做
  • 策略模式和工厂模式的区别
  • 用途不同
  • 工厂是建立型模式,它的做用就是建立对象
  • 策略是行为型模式,它的做用是让一个对象在许多行为中选择一种行为
  • 关注点不同
  • 一个关注对象建立
  • 一个关注行为的封装
  • 解决不一样的问题
  • 工厂模式是建立型的设计模式,它接受指令,建立出符合要求的实例;它主要解决的是资源的统一分发,将对象的建立彻底独立出来,让对象的建立和具体的使用客户无关。主要应用在多数据库选择,类库文件加载等
  • 策略模式是为了解决的是策略的切换与扩展,更简洁的说是定义策略族,分别封装起来,让他们之间能够相互替换,策略模式让策略的变化独立于使用策略的客户
  • 工厂至关于黑盒子,策略至关于白盒子
  • 模板方法模式
  • 定义一个操做中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类能够不改变一个算法的结构便可重定义该算法的某些特定步骤
  • 为了提升代码的复用性和系统的灵活性,可使用一种称之为模板方法模式的设计模式来对这类状况进行设计,在模板方法模式中,将实现功能的每个步骤所对应的方法称为基本方法(例如“点单”、“吃东西”和“买单”),而调用这些基本方法同时定义基本方法的执行次序的方法称为模板方法(例如“请客”)
  • 在模板方法模式中,能够将相同的代码放在父类中,例如将模板方法“请客”以及基本方法“点单”和“买单”的实现放在父类中
  • 而对于基本方法“吃东西”,在父类中只作一个声明,将其具体实现放在不一样的子类中,在一个子类中提供“吃面条”的实现,而另外一个子类提供“吃满汉全席”的实现
  • 好处
  • 提升了代码的复用性
  • 还能够利用面向对象的多态性,在运行时选择一种具体子类,实现完整的“请客”方法,提升系统的灵活性和可扩展性
  • 两种方式
  • 继承
  • 用回调
  • 变化的东西是一段代码,并且这段代码会用到原类中的变量,用回调对象
  • 咱们去实现这个回调方法,就把变化的东西集中到这里了
  • Spring的JdbcTemplate用的是回调的方式实现模板方法模式
  • 设计模式区分
  • Façade模式、Adapter模式、Bridge模式与Decorator模式区别
  • Façade模式注重简化接口
  • Adapter模式注重转换接口
  • Bridge模式注重分离接口(抽象)与其实现
  • Decorator模式注重稳定接口的前提下为对象扩展功能

工做一到五年的java 开发工程师朋友能够加入咱们Java架构交流群:760940986 群内提供 高可用,高并发,spring源码,mybatis源码,JVM,大数据,Netty等多个技术知识的架构视频资料 还有大把大牛在群内交流以及解答面试指导,问题答疑~~要进来和大牛交流学习提高提高本身吗~~~~
程序员

相关文章
相关标签/搜索