写在前面:

        朋友分享了一个Spring的知识体系图片,把它整理成文字,以便阅读;

1、基本概念


Spring优点: 1、轻量级,非侵入式,对现有的类结构没有影响; 2、可以提供众多服务,如事务管理、WS等 3、AOP的很好支持,方便面向切面编程,使得业务逻辑和系统服务分开 4、对主流的框架提供了很好的集成支持 5、使用Spring IOC容器,将对象之间的依赖关系交给Spring,降低组件之间的耦合性,让我们更专注于应用逻辑 5、Spring DI机制降低了业务对象替换的复杂性 6、Spring的高度可开放性,可不强制依赖于Spring,开发者可以自由选择Spring部分或全部 Spring缺点: 1、缺少一个公用控制器 2、没有SpringBoot好用 3、Spring像一个胶水,将框架黏在一起,后面拆分就不容易拆分


2、AOP


基本概念: 1、核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能“编织在一起”,这就叫AOP 2、让关注点代码与业务代码分离 3、面向切面编程就是指:对很多功能都有很多的重复代码抽取,再在运行的时候往业务方法上动态植入“切面类代码” 4、应用场景:日志、事务管理、权限控制


实现原理: JDK动态代理: 主要通过Proxy:newProxyInstance()和InvocationHandler这两个类和方法实现 实现过程: 1、创建代理类Proxy实现invocation接口,重写invoke()方法,调用被代理类方法时默认调用此方法 2、将被代理类作为构造函数的参数传入代理类Proxy 3、调用Proxy:newProxyInstance(classloader,interfaces,handler)方法生成代理类(生成代理类 -> 代理对象会实现用户提供的的这组接口,因此可以将这个代理对象强制类型转化为这组接口中的任意一个 -> 通过反射生成对象) 实现过程总结:代理类调用自己的方法时,通过自身持有的中介类对象调用中间类对象的invoke方法,从而达到代理执行被代理对象的方法。 CGLIB动态代理: 1、生成对象类型为Enhancer 2、实现原理类似于JDK动态代理,只是他在运行期间生成的代理对象是针对目标类拓展的字类 3、Spring在运行期间通过CGLIB继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程 静态代理: 在编译的时候就直接生成代理类 缺点: 1、如果要代理一个接口的多个实现的话需要定义不同的代理类 2、代理类和被代理类必须实现同样的接口,万一接口有变动,代理、被代理类都得修改,难以维护 JDK动态代理和CGLIB的对比: 1、CGLIB所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高(1.6和1.7的时候,CGLIB更快;1.8的时候,JDK更快) 2、CGLIB在创建对象的时候所花费的时间比JDK动态代理多 3、singleton的代理对象或者具体实例池的代理,因为无需频繁的创建代理对象,所以比较适合CGLIB动态代理,反之,则适合用JDK动态代理 4、JDK动态代理是面向接口的,CGLIB动态代理是通过字节码底层继承代理类来实现(如果被代理类被final关键字所修饰,那么会失败) 5、JDK生成的代理类类型是Proxy(因为继承的是Proxy),CGLIB生成的代理类类型是Enhancer类型 6、如果要被代理类类型是个实现类,那么Spring会使用JDK动态代理来完成操作(Spring默认采用JDK动态代理实现机制);如果被代理对象不是实现类,那么Spring会强制使用 CGLIB来实现动态代理。


配置方式: 1、XML方式 2、注解方式 3、基于JAVA类配置,通过@Configuration过和@Bean这两个注解实现的,@Configuration作用于类上,相当于一个Xml配置文件;@Bean作用于方法上,相当于Xml配置中的<bean>标签


3、事务管理


基本概念: 如果需要某一组操作具有原子性,就用注解的方式开启事务,按照给定的事务规则来执行提交或者回滚操作 事务控制: 编程式事务控制: 用户通过代码的形式手动控制事务; Conn.setAutoCommite(false);//设置手动控制事务 粒度较细,比较灵活,但开发起来比较繁琐,每次开启都要开启、提交、回滚 声明式事务控制: Spring提供事务的控制管理:XML方式、注解方式 Spring事务管理接口 PlatformTransactionManager: 事务管理器; Spring并不直接管理事务,而是提供了多种事务管理器,通过PlatformTransactionManager这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了 TransactionDefinition: 事务定义属性(事务隔离级别、传播行为、超时、只读、回滚规则) TransactionStatus: 事务运行状态 事务一般在Service层: 1、如果在Dao层,回滚的时候只能回滚到当前方法,但一般我们的Service层的方法都是由很多Dao层的方法组成的; 2、如果在Dao层,Commit的次数会过多


事务属性: 事务传播行为: REQUIED<默认>:没有事务就创建一个新事物,存在则加入该事务; REQUIED_NEWS:创建新事物,无论存不存在都创建新事物; NESTED:如果当前存在事务,嵌套事务内执行,没有则新建; SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果不存在则已非事务执行; MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果不存在就抛出异常; NOT_SUPPORTS:以非事务方式执行,存在事务的话,就把事务挂起; NEVER:以非事务执行,如果当前存在事务,就抛出异常 数据库隔离级别: ISOLATION_DEFAULT:使用后端数据库默认的隔离级别 ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复度 ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或者不可重读仍有可能发生 ISOLATION_REPEATABLE_READ:对一个字段的多次读取结果都是一致的,除非数据库是被本身事务所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生 ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别,所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读,但是这将严重影响程序的性能,通常情况下也不会用到该级别。 事务超时属性: 指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。 事务只读属性: 对事务资源是否执行制度操作 回滚规则: 定义了哪些异常会导致事务回滚而哪些不会,默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚,也可以由用户自己定义


4、相关设计模式


1、单例模式 实现方式:Spring依赖注入Bean实例默认是单例的; 2、工厂模式: 实现方式: 静态工厂,beanFactory; 工厂模式,factoryBean; 3、代理模式: 实现方式:AOP中的JDK动态代理和CGLIB 4、适配器模式 实现方式:SpringMVC中的适配器HandlerAdatper 实现原理:HandlerAdatper根据Handler规则执行不同的Handler 5、装饰器模式: 实现方式:Spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decortor 6、观察者模式: 实现方式:SPring的事件驱动模型使用的是观察者模式,Spring中Observer模式常用的地方是listener的实现 具体实现:事件机制的实现需要三个部分,事件源,事件,事件监听器 7、策略模式: 实现方式:Spring框架的资源访问Resource接口,该接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource接口来访问底层资源 8、模板方法模式


5、IOC


依赖注入: 装配方式(依赖注入的具体行为): 基于注解的自动装配: 实现方式: 注解: @Autowired: 1、优先按照ByType方式进行查找 2、如果查询的结果不止一个,而且没有设置名称的话,那么会报错 3、否则Autowired会按照ByName方式来查找 4、如果查询结果为空,那么会抛出异常,可以使用require=false来解决 @Resource: 1、默认按照ByName当方式来进行装配,名称可以通过name属性进行指定 2、如果没有制定name属性,当注解写在字段上时,默认去字段名字进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配 3、当找不到与名称匹配的bean时才通过ByType进行装配。但是需要注意的是,如果name属性一旦制定,就只会按照名称进行装配 4、只指定@Resource注解的type属性,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常 自动扫描: 标签会开启SPring Beans的自动扫描,并可设置base-package属性,表示Spring将会扫描该目录以及子目录下所有被@Component标注修饰的类,对他们进行装配 基于XML配置的显示装配: 基于JAVA配置的显示装配: 能够在编译时就发现错误 依赖注入的方式: 构造器方式注入: 1、保证依赖不可变(final关键字) 2、保证依赖不为空: 3、避免循环依赖:在构造器注入参数时,比如在A中注入B,在B中注入A,先初始化A,那么需要传入B,这个时候发现需要B没有初始化,那么就要初始化B,这个时候就出现了问题,会排除循环依赖错误,而使用field注入方式则只能在运行时才会遇到这个问题。 setter方式注入:通过找到类的对应的setter方法,再进行对应的注入; Setter方法注入是容器通过调用无参构造器或无参statuc工厂方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入 循环依赖: 构造器方式无法解决,只能抛出异常:因为加入三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决; 多例方法无法解决,只能抛出异常:因为Spring容器不缓存prototype作用域的bean,因此无法提前暴露一个创建中的bean 单例模式可以解决: 通过三级缓存解决; 在createBeanInstance()之后会调用addSingleton()方法将bean注册到singletonFactorles中,通过提前暴露一个单例工厂方法,从而使其他bean能够引用到该bean提前暴露一个正在创建中的bean 举例:1、A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象;2、A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中;3、A发现自己依赖对象B,此时就尝试去get B,发现B还没有背create,所以走create流程4、B在初始化第一步的时候发现自己依赖了对象A,于是尝试get A,尝试一级缓存没有,因为A还没有初始化完全,尝试二级缓存也没有,尝试三级缓存,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象;5、B拿到A对象后顺利完成初始化阶段1、2、3,完全初始化后将自己放入到一级缓存singletonObjects中;6、返回A中,A此时能够拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,放到一级缓存中;7、由于B拿到了A的对象引用,所以B类中的A对象完成了初始化。


容器的初始化过程: 1、Resource定位:指对BeanDedinition的资源定位过程,通俗地讲,就是找到定义JavaBean信息的XML文件,并将其封装成Resource对象 2、BeanDefinition的载入:把用户定义好的JavaBean表示为IOC容器内部的数据结构,这个容器内部的数据结构就是BeanDefinition 3、向IOC容器注册这些BeanDefinition


Bean的知识: Bean的生命周期: 1、实例化bean 2、设置Bean的属性 3、检查Aware相关接口并设置相关依赖 4、检查BeanPostProcessor接口并进行前置处理 5、检查Bean在Spring配置文件中配置的init-method属性并自动调用其配置的初始化方法 6、检查beanPostProcessor接口并进行后置处理 7、当Bean不再需要时,会进过清理阶段,如果Bean实现了DisPosableBean这个接口,会调用那个其实现的destory方法; 8、最后,如果这个Bean的Spring配置中配置了destory- method属性,会自动调用其配置的销毁方法。 Bean的作用域: singleton: 是Bean的默认作用域,默认情况下是容器初始化的时候创建,但也可设定运行时再初始化Bean Spring容器可以管理singleton作用域下bean的生命周期,在此作用域下,Spring能够精确地知道bean何时被创建,何时初始化完成,以及何时被销毁 prototype: 每次通过Spring容器获取prototype定义的bean时,容器都将创建一个新的Bean实例,每个Bean实例都有自己的属性和状态;当容器创建了bean的实例后,bean的实例将交给客户端的代码管理,Spring容器将不会再跟踪其生命周期,并且不会管理那些配置成prototype作用域的生命周期;对有状态的bean使用prototype作用域,而对无状态的bean使用singleton作用域。 request: 再一次http请求中,容器会返回Bean的同一实例,而对不同的Http请求则会产生新的Bean,而且该Bean仅在当前Http Request内有效 session: 在一次Http Session中,容器会返回该Bean的同一实例,而对不同的Http请求则会产生新的Bean,而且该Bean实例仅会在当前Session内有效 Global Seesion: 在一个全局的Http Session中,容器会返回该Bean的同一个实例,仅在使用portlet context时有效。 Bean的创建过程: 1、进入getBean方法; 2、判断当前bean的作用域是否是单例,如果是,则去对应缓存中查找,没有查找的话则新建实例并保存,如果不是单例,则直接新建实例(createBeanInstance) 3、新建实例后再注入属性(popilateBean),并处理回调(创建Bean,找到@Autowired的对象,创建注入对象,并赋值)


IOC大致流程: 1、首先根据配置文件找到对应的包,读取包中的类,找到所有含有@Bean,@Service等注解的类,利用反射解析他们,包括解析构造器,方法,属性等等,然后封装成各种信息方法哦Container(其实是一个map)里<IOC容器初始化> 2、获取类时,首先从Container中查找是否有这个类,如果没有创建,如果有,则通过构造器新奇将这个类new出来; 3、如果这个类含有其他需要注入的属性,则进行依赖注入,如果有则还是从COntailer找到对应的解析类,new出对象,并通过之前解析出来的信息类找到setter方法(setter方法注入),然后用该方法注入对象(这就是依赖注入)。如果其中有一个类Container里没找到,则抛出异常 4、如果有嵌套Bean的情况,则通过递归解析; 5、如果Bean的scope时singleton,则会重用这个bean不用重新创建,将这个bean放到一个map里面找,如果作用域时session,则该bean会放到session里面 总结:通过解析xml文件,获取bean的属性里面的内容,利用反射原理创建配置文件里面的类的实例对象,存入到Spring的bean容器中


6、Spring MVC


执行流程: 1、用户发送请求至前端控制器DispatcherServlet 2、DIspatcherServlet收到请求调用HandlerMapping处理器映射器 3、处理器映射器根据请求url找到具体的处理器,生成处理器对象以及处理器拦截器一并返回给DispatherServlet 4、DispathcherServlet通过HandlerAdapter处理器适配器调用处理器 5、执行处理器(Controller,也叫后端处理器) 6、Controller执行完成饭后ModelView 7、HandlerAdapter将Controller执行结果返回ModelAndView返回给DispathcherServlet 8、DispatcherServlet将ModelAndView传给View Resource视图解析器 9、ViewReslover解析后返回具体View 10、Dispatcher Servlet对View进行渲染视图(即将模型数据填充至视图中)。 11、DispatcherServlet响应用户 常用注释: @Compoent(@Controller、@Service、@Repository) @RequestMapping @RequesParam @Autowired @Resource Servlet的生命周期: 1、加载和实例化 2、初始化 3、请求处理 4、服务终止


7、Spring类


ApplicationContext: FileSystemXmlApplicationContext ClassPathXmlApplicationContext WebXmlApplicationContext