谈谈对Spring的理解

一、Spring的优缺点

  1. 优点
  • 轻量级框架,采用非侵入式设计,对现有的类结构没有影响;
  • 可以提供众多服务,如事务管理、日志管理等;
  • AOP的支持很好,方便面向切面编程,使得业务逻辑和系统服务分开;
  • 对主流的框架提供了很好的继承;
  • 使用IOC容器负责对象装配、依赖管理,降低组件之间的耦合度;
  • DI机制降低了业务对象替换的复杂度。
  1. 缺点
  • 缺少一个公用控制器;
  • 没有SpringBoot实用。

二、IOC

  1. 大致流程
  • 首先根据配置文件找到对应包,读取类,找到包含@Bean、@Service等注解的类,利用反射解析构造器、方法、属性等,然后封装成各种信息放入到容器中;
  • 获取类时,先从容器中查找是否,如果没有则报错,如果有则通过构造器信息创建实例;
  • 如果这个类含有其他需要注入的属性,则进行依赖注入,找到对应的解析类,实例化后通过类的setter方法注入。如果其中有个类在容器中没找到则抛出异常;
  • 如果有嵌套bean的情况,则通过递归解析;
  • 如果bean是单例,会重用这个bean,把这个bean放入map中;
  • 通过解析xml文件,获取bean的属性内容,利用反射原理创建文件中类的实例对象,存入到spring的bean容器中。
  1. bean作用域
  • singleton:默认作用域,默认情况下是容器初始化时创建,但也可以设定运行时再初始化bean;spring容器可以负责单例bean的生命周期,知道bean何时创建、何时初始化以及何时销毁;单例对象保存在DefaultSingletonBeanRegistry#singletonObjects哈希表中。
  • prototype:多例,每次都会创建一个新的bean实例;对有状态的bean使用prototype作用域,对于无状态的bean使用singleton作用域;当容器创建bean后,bean实例交给客户端代码管理。
  • request:在同一次请求中,容器会返回该bean的同一实例,而对不同的请求会产生新的bean,而且该bean仅在当前请求内有效。
  • session:在一次请求的会话中,容器会返回该bean的同一实例,而对不同请求的会话会创建新的实例。
  • global session:在一个全局会话中,容器会返回该bean的同一实例,只在portlet上下文时有效。
  1. bean生命周期
  • 实例化bean;
  • 设置bean属性;
  • 检查Aware相关接口,如BeanNameAware、BeanFactoryAware、ApplicationContextAware;
  • 检查BeanPostProcessor接口进行前置处理;
  • 检查bean在spring配置文件中配置的init-method属性,自动调用配置的初始化方法;
  • 检查BeanPostProcessor接口进行后置处理;
  • 当bean不再需要时进入清理阶段,如果试下了DisposableBean接口,调用destroy方法;
  • 如果这个bean配置了destroy-method属性,调用配置的销毁方法。
  1. 依赖注入
  • 装配方式有基于注解的自动装配、基于XML配置的显示装配和基于Java配置的显示装配。基于注解的装配实现方式有优先按照类型的@Autowired注解和优先按照名称的@Resource注解。
  • 依赖注入的方式有构造器注入、setter方法注入。使用构造器参数实现强制依赖,setter方法实现可选依赖。
  • 单例模式可以解决循环依赖,通过提前暴露一个单例工厂方法,从而使其他bean能够引用该bean。多例方法式无法解决,只能抛出异常,因为spring容器不缓存多例bean,无法提前暴露一个创建中的bean。构造器方式也无法解决循环依赖。

三、AOP

  1. 面向切面编程,让与业务无关的关注点代码与业务代码分离,可以用于日志记录、事务管理、权限控制。
  2. 配置方式有XML方式、注解方式、Java类配置。Java类配置使用@Configuration注解配置类,使用@Bean注解配置方法。
  3. 静态代理在编译时直接生成代理类。代理类和被代理类是实现同样的接口,接口变动,代理类和被代理类都需要修改;代理一个接口的多个实现需要定义不同的代理类。
  4. JDK动态代理通过Proxy.newProxyInstance方法和InvocationHandler接口的invoke方法实现。JDK动态代理实现过程大致如下:创建代理类Proxy实现InvocationHandler接口,重写invoke方法;把被代理类作为构造函数参数传入代理类Proxy;调用Proxy.newProxyInstance(classloader,interfaces,handler)方法生成代理类,只能针对接口代理,通过反射生成对象。
  5. CGLIB动态代理生层对象类型为Enhancer,CGLIB代理是通过字节码底层继承代理类实现的,CGLIB创建的代理对象在运行时的性能要比JDK动态代理高;CGLIB创建对象时花费的时间更多。

四、Spring MVC执行流程

  1. 用户发送请求至前端控制器DispatcherServlet;
  2. 根据URL从HandlerMapping处理器映射器列表中找到具体的处理器,返回处理器对象以及相关的拦截器给DispatcherServlet;
  3. 通过处理器适配器HandlerAdapter调用处理器;
  4. 执行处理器方法后返回模型和视图对象ModelAndView;
  5. DispatcherServlet把ModelAndView传给视图解析器进行解析成视图View;
  6. 视图渲染后返回给用户。

五、事务管理

  1. 如果需要一组操作具有原子性,就需要用注解的方式开启事务,按照给定的事务规则来执行提交或回滚操作。
  2. 事务管理一般是在服务层,如果在dao层,提交次数会过多,回滚只能回滚到当前方法。
  3. 隔离级别有读未提交、读已提交、可重复读、序列化。
  4. 事务属性
  • 超时属性指定了一个事务执行的最长时间,如果超过该时间但事务还没有完成,自动回滚事务;
  • 只读属性对事务资源是否执行只读操作;
  • 回滚规则定义那些异常会导致事务回滚。
  1. 事务接口
  • TransactionStatus:事务运行状态;
  • TransactionDefinition:事务定义属性、隔离级别、传播行为、超时、只读、回滚规则;
  • PlatformTransactionManager:spring不直接管理事务,而是提供了多种事务管理器。