spring框架学习(一)

spring

传统servlet维护

web.xml维护url到servlet的映射,由tomcat启动时加载

外部请求到来时,服务器查看web.xml找到请求的url对应的servlet,然后将请求转发到响应的servlet,servlet处理完毕后再将响应回复给客户端

这种servlet维护方式的问题
1、项目变大以后web.xml里很多映射项,文件大而杂
2、每次都要实现servlet的全部接口,没有必要

spring调度流程

spring引入了总管一样的角色,DispatcherServlet,它在tomcat里配置了根目录路径符(/),表示所有请求都由它受理。
spring把servlet简化成MappingHandler,就是Controller里的一个方法,可以通过requestMapping注解配置url。
请求到达DispatcherServlet后,由它转发给相应的MappingHandler

优点是配置分散,同时不同功能的servlet由不同的Controller管理

怎么让框架知道有哪些Controller?
使用类加载器,通过类的全限定名获取类的二进制字节流,classloader通过jvm解析二进制字节流,获取Class实例。类加载器还可以加载classpath下的静态资源

怎么获取所有的类的全限定名?
利用classloader的getResources方法,传入包名代表的路径后,遍历包下的每一个资源,根据资源类型(jar包,Class文件,

请求执行过程

1、首先DispatcherServlet在tomcat先注册好,处理路径设置为根目录""。客户端请求到来时,tomcat把请求交给DispatcherServlet
2、然后tomcat调用DispatcherServlet的service方法
3、service方法:通过HandlerManager遍历每一个MappingHandler的handle方法
4、MappingHandler的handle方法:handle方法有两个参数,HttpServletRequest以及HttpServletResponse,从req取出uri判断是否跟handler的uri相同,相同的话从req中取出参数,然后通过反射调用Controller的方法,将处理结果写入resp中返回
5、tomcat将resp进一步处理后返回给客户端

HandlerManager是怎么持有MappingHandler列表的?
在Application类的run方法里,先通过classloader获取包下的所有Class实例,将Class列表传入HandlerManager的resolveMappingHandler方法进行解析,根据Controller注解筛选出Controller类,根据RequestMapping注解筛选出处理特定uri请求的方法,根据RequestParam注解获得方法的参数名,将每一个方法包成一个MappingHandler对象,放入HandlerManager类的静态对象里

IOC

bean管理

bean是啥
1、生命周期长
2、在整个jvm都可见
3、维护成本高,所以通常单例存在

bean的优势
运行期效率高:项目启动时初始化,使用时就不需要初始化了;减少了很多对象使用后抛弃的情况,减轻了gc的压力
统一维护,便于管理和拓展:对某些类进行统一操作更简单,如添加类的代理等
bean的依赖关系通过框架管理后,不必在创建对象时set各种properties,也不必再处理链式依赖

普通类创建与spring类创建的对比

普通类:
如A对象里有Z对象,B对象里有Z对象,C里有B对象。如果用普通的new的方式创建类,等A,B,C三个对象创建完毕后,jvm中就存在1个A对象,2个B对象,1个C对象,3个Z对象,造成资源浪费

spring实现方式
1、类是在启动服务时由spring进行包扫描后通过反射自动实例化
2、bean通过BeanFactory统一管理,通过beanFactory可以通过类型、名字获取到对应的bean,也可以判断某个bean是否在工厂内
3、通过依赖注入策略管理bean之间依赖关系

控制反转和依赖注入

普通方式:A中有一个Z,创建A时,先要创建一个Z,再将Zset到A里(A主动创建Z)

控制反转IoC:除了A和Z之外,还必须有一个第三方容器(BeanFactory)来调控系统内所有对象的外界实体。A类通过属性声明它的依赖X后,BeanFactory会知道这个信息,在创建A对象之前,就先创建好X对象,并将Z对象set到A对象属性里。A对象没法控制自己依赖的对象,而是由第三方控制,即控制反转

上述实现IoC的动作(把Z对象set到A的属性)就是依赖注入

依赖查找也可以实现IoC,比如A对象需要使用Z对象时,便到BeanFactory去查找Z的一个实例给它用

spring的bean创建方式

假设A依赖Z,B依赖Z,C依赖B
一开始BeanFactory先实例化Z,把Z的实例保存下来,在创建A时,直接把Z实例注入到A的属性,然后把A的实例加入到工厂。创建B实例时bean工厂里已经有Z的实例了,直接把Z实例注入给B,创建完后把B的实例放入工厂。创建C时bean工厂已有B的实例,直接把B实例注入给C,然后把C的实例加入工厂中
此时jvm中各类的实例都只有1个

实现依赖注入的具体步骤

1、扫描包获取类定义
2、使用反射初始化bean,并实现依赖注入
3、解决bean初始化顺序问题

依赖注入次序问题
一开始,获取到了项目内所有的Classes,并放入Class容器内,对容器进行循环遍历,先判断创建这个bean是否需要解决依赖(看其属性即可),如果没有依赖,就直接实例化并把类的实例放入工厂。如果bean依赖其他bean,就检查需要的bean是否在工厂内,在的话从工厂拿到依赖bean的实例,用反射set到正在创建的bean里,完成bean的创建,然后把新bean放入工厂;bean的依赖在工厂中还找不到,就暂时先放弃它,继续创建后面的bean,等后面的bean创建完了,再重头遍历创建失败的bean。

出现bean之间相互依赖咋办??

怎么发现bean之间的相互依赖?
每次遍历待创建bean列表时记录下已创建数量,如果遍历结束后数量没变,说明出现了相互依赖

AOP

基本概念

  1. Aspect
    A modularization of a concern that cuts across multiple classes
  2. JoinPoint
    程序执行期间的某一个点,比如一个函数的执行或者一个异常的处理,在spring aop中通常代表函数执行
  3. Advice
    切面在特定JoinPoint执行的某个动作。不同类型的JoinPoint包括around,before,after,许多aop框架将advice建模成一个拦截器,并在joinpoint周围维护一条拦截器链
  4. Pointcut
    对joinpoint的一个匹配模式表述,advice在任何能匹配pointcut的joinpoint处运行(如运行特定名称的函数)
  5. Introduction
    定义额外的方法或者字段到某个特定的类型,如可以通过introduction让某个bean实现IsModified接口,可以简化缓存实现
  6. TargetObject
    被代理的对象
  7. AOP Proxy
    由aop框架创建的代理对象
  8. Weaving
    将aspects跟其他应用类型或者对象链接起来,产生一个advised对象

实现原理

aop有多个目标对象,每个目标对象的特定地方JoinPoint切一刀,当运行到JoinPoint时运行预先定义好的方法,通常是一些通用的业务代码,如日志收集。在PointCut里定义好业务方法,定义要拦截的对象、具体的点。最后将业务方法织入到JoinPoint里。织入方式有3种,编译时织入,需要使用特殊的编译器;类装载时织入,需要使用特殊的类加载器;运行时织入,需要为目标生成代理对象

AspectJ:编译期时织入
spring aop:运行时通过代理的方式织入代码,只支持方法类型的连接点。底层有两种实现方式,一个是jdk动态代理技术,可以在运行时创建接口的代理实例,spring aop默认采用这种方式。如果目标对象不存在接口,spring采用cglib动态代理,它采用底层的字节码技术,在运行时创建子类代理实例

jdk动态代理的实现方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值