Spring 根本使命:

  • 简化java开发

Spring 关键策略:

  • 基于POJO的轻量级和最小侵入性编程
  • 通过依赖注入和面向接口编程实现松耦合
  • 通过面向切面和惯例实现声明式编程
  • 通过面向切面和模板减少样板式代码

依赖注入(dependency injection)

应用对象之间的解耦。
DI是依赖反转(IoC,Inversion of Control)在Spring中的实现方式

  • 依赖反转:一个对象的合作(依赖)对象的引用或依赖关系的管理由具体对象来完成,则会导致代码的高耦合和难测试性,应该把这些依赖关系的注入交给框架或者IoC容器来完成。当对象被创建时,由一个调控系统内的所有对象的外界实体将其所依赖的对象的引用传递给它,即依赖被注入到对象中。反转是关于一个对象如何获取它所依赖的对象的引用,指责任的反转,由自己管理变成容器管理。

解决代码过度耦合。软件组件保持松散耦合。

通过接口来实现依赖关系,注入不同的实现类。

装配:创建应用组件之间协作的行为。

应用切面(Applying aspects)

横切关注点与影响对象之间的解耦。
Aspect-oriented programming 面向切面编程
提取遍布系统的关注点(日志,安全等),不混在应用组件的核心业务中。
动态和非侵入性的方式增强服务的功能。

模板

使用模板消除样板式代码。(类似提取出模板代码,然后只要传入参数给模板就好了)

spring容器(container)

容器负责创建,装配,配置,管理对象的生命周期。
容器使用DI管理构成应用的组件,创建相互协作的组件之间的关联。
容器实现类型:

  • Bean 工厂(Bean factories,org.springframework.beans.factory.BeanFactory),基本容器,提供基本的DI支持。
  • 应用上下文(Application contexts org.springframework.context.ApplicationContext),基于BeanFactory构建。可以从类路径,文件系统,web应用下读取相应的XML文件并装载上下文定义。

Bean生命周期

在不同生命阶段都可以对Bean进行个性化定制。
相应步骤我们可以做什么?参考Q9中在不同阶段做了哪些自定义。


spring 组成模块

装配Bean

创建应用对象之间协作关系(依赖关系)的行为被称为装配(wiring)(DI的本质)
装配方式:

  • XML中显式配置
  • Java中显式配置
  • 隐式的Bean发现机制和自动装配(尽可能多的使用,显式配置越少越好)

装配配置思路:

  • 自动装配,对于被标记的bean,spring会自动装配到容器中,并装配到相应的依赖bean中。
    • 所以需要在相应需要装配的bean上打上对应的标记(打上@Component,)
    • 再创建配置文件告诉spring去哪个区域内查找需要被装配的bean(配置类@Configuration + @ComponentScan,xml + component-scan,)
    • 同时把这个配置上下文文件加载到spring中(@ContextConfiguration)
    • 最后再标记需要被装配的依赖bean(@Autowired)
  • Java显示配置,告诉spring应用上下文中如何创建bean,相当于就是帮Spring实现了new 方法。
    • 创建一个配置类(@Configuration)
    • 在配置类中添加需要加载的bean(@Bean)
    • 同时把这个配置上下文文件加载到spring中(@ContextConfiguration)

自动化装配Bean

  • 组件扫描:自动发现应用上下文中所创建的bean
  • 自动装配:自动满足bean之间的依赖,找到多个满足依赖关系的bean时会抛异常
  • 显示装配:
    • Java配置
    • XML配置

  • 声明Bean(使用元素在spring配置文件中进行声明,spring会创建一个对象,对应bean_id的Bean,spring调用构造器来实例化Bean,来传入参数(基本类型或者bean)选择使用相应的构造器)(@Configuration + @Bean替代 的配置文件)

  • 默认情况下,所有spring Bean都是单例,通过给Bean声明作用域来覆盖spring的单例配置(如允许Bean的定义可以被实例化任意次,每次调用都创建一个实例)spring的单例Bean只能保证每个应用上下文中只有一个Bean的实例,通过定义多个声明可以实例化同一个Bean。

  • 初始化和销毁Bean (两种方式在spring bean生命周期中都属于相应的步骤)

    • init-method 初始化时操作 destroy-method 销毁时操作
    • Bean实现Spring的InitializingBean和DisposableBean来实现初始化和销毁时操作,spring自动检测实现接口的Bean,无需额外操作,但是Bean与spring API产生耦合。建议在开发一个明确在Spring容器内使用的框架Bean时使用?
  • 注入Bean属性(spring通过调用set方法来配置属性)
    • 使用命名空间 p 装配
  • 装配集合

最小化spring xml配置(消除xml配置)

  • 自动装配
    • 注解装配
      • @Autowired
      • @Qualifier 修饰bean
      • @Value 装配string或基本类型,配合SpEl使用
  • 自动检测
    • 指定package,扫描指定的包找出能够自动注册为Bean的类。可以使用annotation + 自动检测Bean和定义Bean
  • 高级装配
    • 激活特定的profile来创建特定的bean
    • 使用@Conditional 满足某些条件的情况下才装配bean

面向切面的Spring

分布于应用中多处的功能称为横切关注点,这些功能需要应用到系统多个模块中,如日志、安全和事务管理等,但是不该由对象模块主动调用,横切关注点应该和模块的业务逻辑分开,这正是面向切面编程需要解决的。

面向切面编程:独立定义一个通用功能(切面),声明该功能以何种方式在何处应有,无需修改受影响的类。相应类只需要关心自身功能代码就可。

使用AOP,切面可以在不修改spring bean的条件下为其添加新功能(@DeclareParents)。

  • AOP组成

    • 通知(Advice):定义了切面是什么以及何时使用,Spring提供5种种通知类型,区分通知的时间。定义切面什么时候何时使用,需要做什么。
    • 连接点(join point):应用中能够插入通知的点
    • 切点(pointcut):应用中需要插入进行通知的点,定义了在何处进行通知。
    • 切面(aspect):通知和切点的结合,定义什么在何时和何处完成什么功能。
    • 引入(introduction):使用通知给现有类添加新方法或属性。
    • 织入(weaving):将切面应用到目标对象来创建新的代理对象的过程。
  • Spring提供的AOP支持

    • 基于代理的AOP
    • @AspectJ注解驱动的切面(AspectJ切点表达式)
    • 纯POJO切面
    • 注入式AspectJ切面
  • Spring AOP构建在动态代理基础上,在运行时通知对象,使用代理类封装目标类,拦截被通知的方法的调用,执行额外的切面逻辑,再将调用转发给目标类。
  • 因为Spring基于动态代理实现,所以Spring只支持方法连接点。如有高级的使用场景(构造器或属性拦截),则考虑使用AspectJ来实现切面。
  • Spring切点编写:
    • Spring AOP使用AspectJ的切点表达式来定义切点
    • 编写切点:


    • XML中声明切面
    • 使用注解创建切面。