重新认识spring(4)-1

矫情吗;* 2022-04-24 13:48 316阅读 0赞

spring的目的:

简化java开发。

为了降低java开发的复杂性,spring采用了4种关键策略:

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

依赖注入(DI)

按照传统的做法,每个对象负责管理与自己相互协作的对象(即它所依赖的对象)的引用,这将会导致高度耦合和难以测试的代
码。

  1. public class DamselRescuingKnight implements Knight {
  2. RescueDamselQuest rescueDamselQuest;
  3. public DamselRescuingKnight() {
  4. this.rescueDamselQuest = new RescueDamselQuest();//与 rescueDamselQuest紧密的耦合
  5. }
  6. public void embarkOnQuest() {
  7. }
  8. }

紧密耦合的代码难以测试、难以复用、难以理解,并且典型地表现出“打地鼠”式的bug特性(修复一个bug,将会出现一个或者更多新的bug)。

完全没有耦合的代码什么也做不了

通过DI,对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定。

依赖注入会将所依赖的关系自动交给目标对象,而不是让对象自己去获取依赖.

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1MTQwODQx_size_16_color_FFFFFF_t_70

  1. public class BraveKnight implements Knight {
  2. Quest quest;
  3. public BraveKnight(Quest quest) {
  4. this.quest = quest; //Query对象被注入进来
  5. }
  6. public void embarkOnQuest() {
  7. }
  8. }

如果一个对象只通过接口(而不是具体实现或初始化过程)来表明依赖关系,那么这种依赖就能够在对象本身毫不知情的情
况下,用不同的具体实现进行替换.实现松耦合。

装配(wiring)

创建应用组件之间协作的行为通常称为装配,

Spring有多种装配bean的方式,采用XML是很常见的一种装配方式:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean id="knight" class="sia.knights.BraveKnight">
  7. <constructor-arg ref="quest" />
  8. </bean>
  9. <bean id="quest" class="sia.knights.SlayDragonQuest">
  10. <constructor-arg value="#{T(System).out}" />
  11. </bean>
  12. </beans>

基于Java的装配:

  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. @Configuration
  4. public class knightConfig {
  5. @Bean
  6. public Knight knight() {
  7. return new BraveKnight(quest());
  8. }
  9. @Bean
  10. public Quest quest() {
  11. return new RescueDamselQuest();
  12. }
  13. }

使用xml,所以选择ClassPathXmlApplicationContext 作为应用上下文相对是比较合适的;

应用切面

DI能够让相互协作的软件组件保持松散耦合,而面向切面编程(aspect-oriented programming,AOP)允许你把遍布应用各处的功能分离出来形成可重用的组件。

面向切面编程往往被定义为促使软件系统实现关注点的分离一项技术。系统由许多不同的组件组成,每一个组件各负责一块特定功能。除了实现自身核心的功能之外,这些组件还经常承担着额外的职责。诸如日志、事务管理和安全这样的系统服务经常融入到自身具有核心业务逻辑的组件中去,这些系统服务通常被称为横切关注点,因为它们会跨越系统的多个组件。

如果将这些关注点分散到多个组件中去,你的代码将会带来双重的复杂性。

  • 实现系统关注点功能的代码将会重复出现在多个组件中。这意味着如果你要改变这些关注点的逻辑,必须修改各个模块中的相关实现。即使你把这些关注点抽象为一个独立的模块,其他模块只是调用它的方法,但方法的调用还是会重复出现在各个模块中。
  • 组件会因为那些与自身核心业务无关的代码而变得混乱。一个向地址簿增加地址条目的方法应该只关注如何添加地址,而不应该关注它是不是安全的或者是否需要支持事务。

AOP能够使这些服务模块化,并以声明的方式将它们应用到它们需要影响的组件中去。所造成的结果就是这些组件会具有更高的内聚性并且会更加关注自身的业务,完全不需要了解涉及系统服务所带来复杂性。总之,AOP能够确保POJO的简单性。

使用模板消除样板式代码

使用场景:1.jdbc, 2.JMS , JNDI 和REST服务

Spring旨在通过模板封装来消除样板式代码

Spring容器:

在基于Spring的应用中,你的应用对象生存于Spring容器(container)中。Spring容器负责创建他们,装配他们,配置他们并管理他们的整个生命周期,从生存到死亡。

两种不同类型的容器:1.bean工厂,2.应用上下文 (由org.springframework.context.ApplicationContext接口定义)基于BeanFactory构建(虽然我们可以在bean工厂和应用上下文之间任选一种,但bean工厂对大多数应用来说往往太低级了,因此,应用上下文要比bean工厂更受欢迎。我们会把精力集中在应用上下文的使用上,不再浪费时间讨论bean工厂。)

使用应用上下文:(常用)

  • AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文。
  • AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载Spring Web应用上下文。
  • ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源
  • FileSystemXmlapplicationcontext:从文件系统下的一个或多个XML配置文件中加载上下文定义。
  • XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下文定义。

bean的生命周期

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1MTQwODQx_size_16_color_FFFFFF_t_70 1

1.Spring对bean进行实例化;
2.Spring将值和bean的引用注入到bean对应的属性中;
3.如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBeanName()方法;
4.如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;
5.如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
6.如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization()方法;
7.如果bean实现了InitializingBean接口,Spring将调用它们的after-PropertiesSet()方法。类似地,如果bean使用init-method声明了初始化方法,该方法也会被调用;
8.如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization()方法;
9.此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
10.如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。

总结

Spring框架关注于通过DI、AOP和消除样板式代码来简化企业级Java开发。即使这是Spring所能做的全部事情,那Spring也值得一用。但是,Spring实际上的功能超乎你的想象。

1.Spring模块

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1MTQwODQx_size_16_color_FFFFFF_t_70 2

Spring核心容器:

容器是Spring框架最核心的部分,它管理着Spring应用中bean的创建、配置和管理。在该模块中,包括了Spring bean工厂,它为Spring提供了DI的功能。基于bean工厂,我们还会发现有多种Spring应用上下文的实现,每一种都提供了配置Spring的不同方式。除了bean工厂和应用上下文,该模块也提供了许多企业服务,例如E-mail、JNDI访问、EJB集成和调度。
所有的Spring模块都构建于核心容器之上。当你配置应用时,其实你隐式地使用了这些类。贯穿本书,我们都会涉及到核心模块.

Spring的AOP模块

在AOP模块中,Spring对面向切面编程提供了丰富的支持。这个模块是Spring应用系统中开发切面的基础。与DI一样,AOP可以帮助应用对象解耦。借助于AOP,可以将遍布系统的关注点(例如事务和安全)从它们所应用的对象中解耦出来。

数据访问与集成

使用JDBC编写代码通常会导致大量的样板式代码,例如获得数据库连接、创建语句、处理结果集到最后关闭数据库连接。Spring的JDBC和DAO(Data Access Object)模块抽象了这些样板式代码,使我们的数据库代码变得简单明了,还可以避免因为关闭数据库资源失败而引发的问题。该模块在多种数据库服务的错误信息之上构建了一个语义丰富的异常层,以后我们再也不需要解释那些隐晦专有的SQL错误信息了!

对于那些更喜欢ORM(Object-Relational Mapping)工具而不愿意直接使用JDBC的开发者,Spring提供了ORM模块。Spring的ORM模块建立在对DAO的支持之上,并为多个ORM框架提供了一种构建DAO的简便方式。Spring没有尝试去创建自己的ORM解决方案,而是对许多流行的ORM框架进行了集成,包括Hibernate、Java Persisternce API、Java Data Object和iBATIS SQL Maps。Spring的事务管理支持所有的ORM框架以及JDBC。

Web与远程调用

除了面向用户的Web应用,该模块还提供了多种构建与其他应用交互的远程调用方案。Spring远程调用功能集成了RMI(Remote MethodInvocation)、Hessian、Burlap、JAX-WS,同时Spring还自带了一个远程调用框架:HTTP invoker。Spring还提供了暴露和使用REST API的良好支持。

Instrumentation

Spring的Instrumentation模块提供了为JVM添加代理(agent)的功能。具体来讲,它为Tomcat提供了一个织入代理,能够为Tomcat传递类文件,就像这些文件是被类加载器加载的一样。
如果这听起来有点难以理解,不必对此过于担心。这个模块所提供的Instrumentation使用场景非常有限,在本书中,我们不会介绍该模块。

测试

2.Spring的新功能

Spring 3.1带来了多项有用的新特性和增强,其中有很多都是关于如何简化和改善配置的。除此之外,Spring 3.1还提供了声明式缓存的支持以及众多针对Spring MVC的功能增强。下面的列表展现了Spring 3.1重要的功能升级:

  1. 为了解决各种环境下(如开发、测试和生产)选择不同配置的问题,Spring 3.1引入了环境profile功能。借助于profile,就能根据应用部署在什么环境之中选择不同的数据源bean;
  2. 在Spring 3.0基于Java的配置之上,Spring 3.1添加了多个enable注解,这样就能使用这个注解启用Spring的特定功能;
  3. 添加了Spring对声明式缓存的支持,能够使用简单的注解声明缓存边界和规则,这与你以前声明事务边界很类似;
  4. 新添加的用于构造器注入的c命名空间,它类似于Spring 2.0所提供的面向属性的p命名空间,p命名空间用于属性注入,它们都是非常简洁易用的;
  5. Spring开始支持Servlet 3.0,包括在基于Java的配置中声明Servlet和Filter,而不再借助于web.xml;
  6. 改善Spring对JPA的支持,使得它能够在Spring中完整地配置JPA,不必再使用persistence.xml文件

Spring 3.1还包含了多项针对Spring MVC的功能增强:

  1. 自动绑定路径变量到模型属性中
  2. 提供了@RequestMappingproduces和consumes属性,用于匹配请求中的Accept和Content-Type头部信息;
  3. 提供了@RequestPart注解,用于将multipart请求中的某些部分绑定到处理器的方法参数中;
  4. 支持Flash属性(在redirect请求之后依然能够存活的属性)以及用于在请求间存放flash属性的RedirectAttributes类型。

Spring 3.2新特性:

Spring 3.1在很大程度上聚焦于配置改善以及其他的一些增强,包括Spring MVC的增强,而Spring 3.2是主要关注Spring MVC的一个发布版本。

Spring MVC 3.2带来了如下的功能提升:

  1. Spring 3.2的控制器(Controller)可以使用Servlet 3.0的异步请求,允许在一个独立的线程中处理请求,从而将Servlet线程解放出来处理更多的请求;
  2. 尽管从Spring 2.5开始,Spring MVC控制器就能以POJO的形式进行很便利地测试,但是Spring 3.2引入了Spring MVC测试框架,用于为控制器编写更为丰富的测试,断言它们作为控制器的行为行为是否正确,而且在使用的过程中并不需要Servlet容器;
  3. 除了提升控制器的测试功能,Spring 3.2还包含了基于RestTemplate的客户端的测试支持,在测试的过程中,不需要往真正的REST端点上发送请求;
  4. @ControllerAdvice注解能够将通用的@ExceptionHandler、@ InitBinder和@ModelAttributes方法收集到一个类中,并应用到所有控制器上;
  5. 在Spring 3.2之前,只能通过ContentNegotiatingViewResolver使用完整的内容协商(full content negotiation)功能。但是在Spring 3.2中,完整的内容协商功能可以在整个Spring MVC中使用,即便是依赖于消息转换器(message converter)使用和产生内容的控制器方法也能使用该功能;
  6. Spring MVC 3.2包含了一个新的@MatrixVariable注解,这个注解能够将请求中的矩阵变量(matrix variable)绑定到处理器的方法参数中;
  7. 基础的抽象类AbstractDispatcherServletInitializer能够非常便利地配置DispatcherServlet,而不必再使用web.xml。与之类似,当你希望通过基于Java的方式来配置Spring的时候,可以使用Abstract- AnnotationConfigDispatcherServletInitializer的子类;
  8. 新增了ResponseEntityExceptionHandler,可以用来替代Default- HandlerExceptionResolver。ResponseEntityExceptionHandler方法会返回ResponseEntity,而不是ModelAndView;
  9. RestTemplate和@RequestBody的参数可以支持范型;
  10. RestTemplate和@RequestMapping可以支持HTTP PATCH方法;
  11. 在拦截器匹配时,支持使用URL模式将其排除在拦截器的处理功能之外。
  12. 虽然Spring MVC是Spring 3.2改善的核心内容,但是它依然还增加了多项非MVC的功能改善。下面列出了Spring 3.2中几项最为有意思的新特性:

    • @Autowired、@Value和@Bean注解能够作为元注解,用于创建自定义的注入和bean声明注解;
    • @DateTimeFormat注解不再强依赖JodaTime。如果提供了JodaTime,就会使用它,否则的话,会使用SimpleDateFormat
    • Spring的声明式缓存提供了对JCache 0.5的支持;
    • 支持定义全局的格式来解析和渲染日期与时间;在集成测试中,能够配置和加载WebApplicationContext;在集成测试中,能够针对request和session作用域的bean进行测试。

    Spring 4.0新特性

    • Spring提供了对WebSocket编程的支持,包括支持JSR-356——Java API for WebSocket;
    • 鉴于WebSocket仅仅提供了一种低层次的API,急需高层次的抽象,因此Spring 4.0在WebSocket之上提供了一个高层次的面向消息的编程模型,该模型基于SockJS,并且包含了对STOMP协议的支持;
    • 新的消息(messaging)模块,很多的类型来源于Spring Integration项目。这个消息模块支持Spring的SockJS/STOMP功能,同时提供了基于模板的方式发布消息;
    • Spring是第一批(如果不说是第一个的话)支持Java 8特性的Java框架,比如它所支持的lambda表达式。别的暂且不说,这首先能够让使用特定的回调接口(如RowMapper和JdbcTemplate)更加简洁,代码更加易读;
    • Java 8同时得到支持的是JSR-310——Date与Time API,在处理日期和时间时,它为开发者提供了比java.util.Date或java.util.Calendar更丰富的API;
    • 为Groovy开发的应用程序提供了更加顺畅的编程体验,尤其是支持非常便利地完全采用Groovy开发Spring应用程序。随这些一起
    • 提供的是来自于Grails的BeanBuilder,借助它能够通过Groovy配置Spring应用;
    • 添加了条件化创建bean的功能,在这里只有开发人员定义的条件满足时,才会创建所声明的bean;
    • Spring 4.0包含了Spring RestTemplate的一个新的异步实现,它会立即返回并且允许在操作完成后执行回调;
    • 添加了对多项JEE规范的支持,包括JMS 2.0、JTA 1.2、JPA 2.1和Bean Validation 1.1

    依赖注入和AOP是Spring框架最核心的部分,因此只有理解了如何应用Spring最关键的功能,你才有能力使用Spring框架的其他功能。

发表评论

表情:
评论列表 (有 0 条评论,316人围观)

还没有评论,来说两句吧...

相关阅读