• Spring的bean容器
  • 介绍Spring的核心模块
  • 更为强大的Spring生态系统
  • Spring的新功能

一、简化java开发

为了降低Spring开发的复杂性,Spring采取了以下4钟关键策略:

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

1、激发POJO潜能(POJO即普通的java类)

2、依赖注入(dependency injection DI)

依赖注入这个词让人望而生畏,现在已经演变成一项复杂的编程技巧或设计模式理念。但事实证明依赖注入并不像它听上去那么复杂,在项目中应用DI,你会发现你的代码会变得异常简单而且更容易理解和测试。

① DI功能是如何实现的

程序都是由多个类组合而成的,这些类之间进行协作完成特定的业务逻辑。按照传统的做法,每个对象负责管理与自己相互协作的对象(即它所依赖的对象)的引用,这将会导致高度耦合和难以测试的代码。

② 耦合具有两面性。

一方面,紧耦合的代码难以测试、难以复用、难以理解,并且典型地表现出“打地鼠”式的bug特性(修复一个bug,将会出现一个或者更多的新bug)。另一方面,一定程序的耦合又是必须的,完全没有耦合的代码啥也做不了。为了完成有实际意义的功能,不同的类必须以适当的方式进行交互。总而言之,耦合是必须的,但应当被小心谨慎的管理。

通过DI,对象的依赖关系将由系统中负责协调各队的第三方组件在常见对象的时候进行设定。对象无需自行创建或管理他们的依赖关系,如下图,依赖关系将自动注入到需要他们的对象中去。

③ 依赖注入的方式

spring支持3种依赖注入的方式

  • 属性注入

属性注入即通过setter方法注入bean的属性值或依赖的对象

属性注入使用元素,使用name属性指定bean的属性名称,value属性或子节点属性值

属性注入是实际开发中最常见的注入方式

public void setName(String name)
{System.out.println("setName:"+name);this.name=name;
}
<bean id="helloWorld" class="spring.bean.HelloWorld"><property name="name" value="Spring"></property>
</bean>
  • 构造器注入

通过构造方法注入bean的属性值或者依赖的对象(引用),保证了bean实例在实例化后就可以使用

构造器注入在元素里声明属性,没有name属性

创建一个People对象

package com.container;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class People {private String name;private String sex;private int age;public People(String name, int age) {this.name = name;this.age = age;}public People(String name, String sex) {this.name = name;this.sex = sex;}@Overridepublic String toString() {return "people{" +"name='" + name + '\'' +", sex='" + sex + '\'' +", age=" + age +'}';}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-config.xml");People people1 = (com.container.People) applicationContext.getBean("people1");System.out.println(people1);People people2 = (com.container.People) applicationContext.getBean("people2");System.out.println(people2);}}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="people1" class="com.container.People"><constructor-arg value="江疏影" type="java.lang.String"></constructor-arg><constructor-arg value="20" type="int"></constructor-arg></bean><bean id="people2" class="com.container.People"><constructor-arg value="江疏影" type="java.lang.String"></constructor-arg><constructor-arg value="man" type="java.lang.String"></constructor-arg></bean>
</beans>

  • 工厂方法注入(知道就行,不推荐)

3、应用切面

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

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

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

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

下图展示了这种复杂性,左边的业务代码与系统服务结合的过于紧密。每个对象不但要知道它需要记日志、进行安全控制和参与事务,还要亲自执行这些服务。

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

如下图所示,我们可以把切面想象为覆盖在很多组件之上的一个外壳。应用是由那些实现各自业务功能的模块组成,借助AOP,可以使用各种功能层去包裹核心业务层,这些层以声明的方式灵活的应用在系统中,你的核心应用甚至不知道他们的存在,这是一个非常强大的理念,可以将安全、事务和日志关注点与核心业务逻辑相分离。

通过少量的XML配置,声明一个Spring切面。

4、使用模块消除样板式代码

二、Spring容器

Spring容器,顾名思义是用来容纳东西的,装的就是Bean。Spring容器负责创建、配置、管理Bean。spring容器有两个核心接口:BeanFactory和ApplicationContext接口,后者是前者的子接口。在基于spring的Java EE程序中,所有的组件都被当成Bean来处理,包括数据源对象、hibernate的sessionFactory、事务管理等,程序中的所有Java类都可以被当成spring容器中的bean。

在基于Spring的应用中,你的应用对象生存于Spring容器(container)中。如下图所示,Spring容器负责创建对象,装配它们,配置它们并管理它们的整个生命周期,从生存到死亡(在这里可能就是new到finalize())。

1、spring容器

spring容器的核心接口是BeanFactory,它有一个子接口就是ApplicationContext。ApplicationContext也被称为spring上下文。

调用者只需要使用getBean()方法即可获得指定bean的引用。对于大部分的Java程序而言,使用ApplicationContext作为spring容易更为方便。其常用的实现类有FileSystemXmlApplicationContext、ClassPathXmlApplicationContext和AnnotationConfigXmlApplicationContext。如果Java web中使用spring容器,则通常有XmlWebApplicationContext、AnnotationConfigWebApplicationContext两个容器。

创建spring容器的实例时,必须提供spring容器管理的bean的配置文件,也就是我们常说的spring.xml配置文件。因此在创建beanFactory时配置文件作为参数传入。xml配置文件一般以resource对象传入。resource是spring提供的资源访问接口,通过该接口spring更简单、透明的访问磁盘,网络系统和类路径上的相关资源。

对于独立的Java EE应用程序,可以通过如下方法来实例化BeanFactory。

//在当前项目类路径下搜索配置文件
ApplicationContext appContext = new ClassPathXmlApplicationContext("beans_7_3_3.xml");
//在文件系统搜索配置文件
appContext = new FileSystemXmlApplicationContext("D:\\spring-tool-workspace\\myspring\\src\\beans_7_3_3.xml");
//获取chinese的Bean,并且返回的类型为Chinese
Person chinese = appContext.getBean("chinese", Chinese.class);
chinese.useAxe();

2、使用ApplicationContext

大部分时间,都不会使用beanFactory实例作为spring容器,而是使用ApplicationContext作为spring容器,因此spring容器也被称为spring上下文。ApplicationContext增强了beanFactory的功能,提供了很多有用、方便开发的功能。

在web中可以利用如contextLoader的支持类,在web应用启动的时候自动创建ApplicationContext。

除了提供beanFactory所支持的全部功能外,application还额外的提供如下功能:

① ApplicationContext会默认初始化所有的singleton bean(单例bean),也可以通过配置取消。

② ApplicationContext继承了messageSource接口,因此提供国际化支持。

③ 资源访问,比如URL和文件。

④ 事件机制。

⑤ 同时加载多个配置文件。

⑥ 以声明式方式启动并创建spring容器。

ApplicationContext包括beanFactory的所有功能,并提供了一些额外的功能,优先使用ApplicationContext。对于在内存消耗的才使用beanFactory。

当系统创建ApplicationContext容器时,会默认初始化singleton bean,包括调用构造器创建该bean的实例,通过元素驱动spring调用setting方法注入所依赖的对象。这就意味着,系统前期创建ApplicationContext会有很大的开销,但是一旦初始化完成后面获取bean实例就会拥有较好的性能。为了阻止在使用ApplicationContext作为spring容器初始化singleton bean可以在元素添加lazy-init="true"属性。

3、ApplicationContext的国际化支持

ApplicationContext接口继承了MessageSource接口,因此具备国际化功能。

//MessageSource接口提供的国际化的两个方法
String getMessage(String code, Object [] args, Locale loc){
}
String getMessage(String code, Object[]args, String default, Locale loc){
}

spring国际化的支持,其实是建立在Java国际化的基础上的。其核心思路将程序中需要国际化的消息写入资源文件,而代码中仅仅使用国际化信息响应的key。

4、ApplicationContext的事件机制

ApplicationContext的事件机制是观察者设计模式的实现。通过ApplicationEvent和ApplicationListener接口实现,前者是被观察者,后者是观察者。

spring事件框架有两个核心的接口:

ApplicationEvent(事件):必须由ApplicationContext来发布。

ApplicationListener(监听器):实现了此接口就可以担任容器中的监听器bean。

实际上,spring的事件机制是由事件(实现ApplicationEvent接口的类)、事件源(也就是spring容器,并且有Java代码显示的触发)、监听器(ApplicationListener接口实现类)。这就像我们在页面点击一个button。button是事件源,单机的这个动作就是事件,处理函数就是监听器。

以下代码演示spring事件机制:

import org.springframework.context.ApplicationEvent;public class EmailEvent extends ApplicationEvent{private String address;private String text;public EmailEvent(Object source) {super(source);}public EmailEvent(Object source, String address, String text) {super(source);this.address = address;this.text = text;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getText() {return text;}public void setText(String text) {this.text = text;}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class EmailNotifier implements ApplicationListener {@Overridepublic void onApplicationEvent(ApplicationEvent event) {//处理email事件if(event instanceof EmailEvent){EmailEvent email = (EmailEvent) event;System.out.println(email.getAddress()+"  "+email.getText());}else {//输出spring容器的内置事件System.out.println("其它事件:"+event);}}public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans_7_4_4.xml");EmailEvent emailEvent = applicationContext.getBean("emailEvent",EmailEvent.class);applicationContext.publishEvent(emailEvent);}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="EmailNotifier"></bean><bean id="emailEvent" class="EmailEvent"><constructor-arg value="test"></constructor-arg><constructor-arg value="123@qq.com"></constructor-arg><constructor-arg value="this is a test"></constructor-arg></bean>
</beans>

从上面的代码可以看出,事件监听器不仅监听到了我们程序显示触发的事件,还监听了spring容器内置的事件。如果实际开发需要,我们可以在spring容器初始化或销毁时回调自定义方法,就可以通过上面的事件监听机制来完成。

spring提供了如下几个内置对象:

ContextRefreshedEvent、ContextStartedEvent、ContextClosedEvent、ContextStoppedEvent、RequestHandledEvent。

5、让bean获取spring容器

上面都是通过ApplicationContext创建spring容器,再调用spring容器的getBean()方法获取bean。这种情况下,程序总是持有spring容器的引用。但是在web应用中,我们可以用声明式的方法来创建spring容器:在web.xml文件中配置一个监听,让这个监听类帮我们来创建spring容器,前端MVC框架直接调用bean,使用依赖注入功能,无需访问spring容器本身。

在某些特殊情况下,bean需要实现某个功能(比如:bean需要输出国际化信息,或向spring容器发布事件),这些功能都需要借助spring容器来完成。就是说我们需要将spring容器作为一个bean来注入到其它bean中,只不过spring容器bean是一个容器级别的bean。

为了让bean获取它所在容器的引用,可以让bean实现beanFactoryAware接口。该接口只有一个方法setBeanFactory(BeanFactory beanFactory)方法,方法的beanFactory参数指向spring容器,会由spring容器注入。我们bean中定义一个setter方法后,通常都是由在配置文件中配置元素来驱动spring容器来注入依赖bean的,但是这里我们并没有这样做,这是因为一个bean如果实现了beanFactory接口,spring在创建该bean时,会自动注入spring容器本身。与beanFactoryAware接口类似的还有BeanNameAware、ResourceLoaderAware接口,这些接口都会提供类似的setter方法,这些方法会由spring容器来注入。

6、bean的生命周期

正确理解Spring bean的生命周期非常重要,因为你或许要利用Spring提供的扩展点来自定义bean的创建过程。下图展示了bean装载到Spring应用上下文中的一个典型的生命周期过程。

正如你所见,在bean准备就绪前,bean工厂执行了若干启动步骤。

现在你已经了解了如何创建和加载一个Spring容器。但是一个空的容器并没有太大的价值,在你把东西放进去之前,它什么也没有。为了从Spring的DI中受益,我们必须将应用对象装配进Spring容器中。我们将在第二章对bean装配进行更详细的探讨。

我们现在首先浏览一下Spring的体系结果,了解一下Spring框架的基本组成部分和最新版本的Spring所发布的新特性。

三、俯瞰Spring风景线

1、Spring模块

Spring发布版本中lib目录下有多个jar文件。

Spring核心容器

Spring的AOP模块

数据访问与集成

web与远程调用

测试

Spring  Boot(第二十一章介绍)

四、Spring的新功能

五、小结

Spring致力于简化企业级Java开发,促进代码的松散耦合,成功的关键在于依赖注入和AOP。

Spring实战@目录

转载于:https://my.oschina.net/u/4006148/blog/3089175

Spring实战 | 第一部分 Spring的核心(第一章 Spring之旅)相关推荐

  1. spring实战六之使用基于java配置的Spring

    之前接触的都是基于XML配置的Spring,Spring3.0开始可以几乎不使用XML而使用纯粹的java代码来配置Spring应用.使用基于java配置的Spring的步骤如下: 1. 创建基于ja ...

  2. 《Spring Boot极简教程》第8章 Spring Boot集成Groovy,Grails开发

    第8章 Spring Boot集成Groovy,Grails开发 本章介绍Spring Boot集成Groovy,Grails开发.我们将开发一个极简版的pms(项目管理系统). Groovy和Gra ...

  3. Spring实战第五版观后感之第一章

    spring所做的一切都是在简化开发,所以今天我们就来说说我所了解到的第一章的内容 一.什么是Spring? Spring的核心是提供了一个容器,通常称为Spring应用上下文,它们会创建和管理应用组 ...

  4. spring in action学习-第一章 spring之旅

    首先我先吐槽一下这本书的封面图,我能理解成一个包着头巾的男人举着个水壶昂首挺胸,最后给你个眼神....开玩笑的这幅插图是约旦西南部卡拉克省的居民,那里的山顶有座城堡,对死海和平原有极佳的视野,这幅图出 ...

  5. 框架设计--第一章 Spring的基本应用--习题答案

    摘要:微信搜索[三桥君] 课程介绍:"框架技术"是软件工程专业的核心课程,是本专业限选课,是Java 应用开发课程,是本专业学生就业的主要方向. 说明:框架设计其他章节的习题答案也 ...

  6. Spring实战 | 第一部分 Spring的核心(第四章 面向切面的Spring)

    第四章 面向切面编程 面向切面编程的基本原理 通过POJO创建切面 使用@AspectJ注解 为AspectJ切面注入依赖 AspectJ是一个面向切面的框架,它扩展了java语言.AspectJ定义 ...

  7. Spring 实战-第一章-基本概念

    依赖注入(Dependency Injection,DI) 通过第三方配置初始化对象,而不是把具体的实现写在对象中,这样程序入口与具体实现进行了解耦.比如动作定义为接口,具体做什么动作 由实现动作接口 ...

  8. 《Spring实战》第一章 — Spring之旅

    2019独角兽企业重金招聘Python工程师标准>>> 1.1 使用Spring简化Java开发 为了降低Java开发,Spring使用了一下4种关键策略: 基于POJO的轻量级和最 ...

  9. Spring Security 详解与实操第一节 认证体系与密码安全

    开篇词 Spring Security,为你的应用安全与职业之路保驾护航 你好,我是鉴湘,拉勾教育专栏<Spring Cloud 原理与实战><Spring Boot 实战开发> ...

最新文章

  1. C++中类的组合和继承关系
  2. 【杂谈】当前知识蒸馏与迁移学习有哪些可用的开源工具?
  3. repeater填充html,使用动态绑定到对象列表的ASP.NET Repeater创建HtmlTable
  4. Bumblebee微服务网关之负载策略
  5. linux python命令无反应_Python学习第164课--Linux命令行特殊符号的意义及命令的语法规则...
  6. anaconda moviepy_Anaconda和PyCharm的详细安装步骤~小白专用,手把手教学
  7. spring mvc后端代码实现弹出对话框_伟源|一图搞定Spring框架
  8. 中国海洋大学c语言期末题库,中国海洋大学C语言期末笔试2010年秋A试题.doc
  9. Java修改带回显吗_修改的是根据自定义标签进行处理回显
  10. 【招聘测评题】中的(行测)图形推理题基本逻辑总结(附例题)
  11. stm32+ESP8266实现最简单的手机控制LED灯
  12. word 插入目录及错误!未找到目录项
  13. vue v-modle实现组件之间的动态传值
  14. 下一个时代的黑产攻防,可能没有人类什么事情了
  15. Maven从入门到精通
  16. 如何基于Arduino开发板使用BH1750环境光传感器
  17. 2018 dota2 战队十杀分析
  18. Mac系统重装 “未能安装在您的电脑上 没有符合安装资格的软件包” 具体解决方案
  19. 选择电容要考虑哪些点?
  20. 常见的3轴/6轴传感器对比

热门文章

  1. 嵩天-Python语言程序设计程序题--第五周:函数和代码复用
  2. 记录配置虚拟环境pytorch2
  3. 没有中国市场仍是第一的三星反攻,折叠手机降价三千压制中国手机
  4. 解决安装Windows7后开启AHCI电脑无法启动
  5. 上链行动|数字经济3.0科创企业路演成功举办
  6. FastStone Capture监视器上拍摄和拍摄
  7. 正则表达式实践(看完就会)
  8. vs2012 打包winform程序需要安装的 软件 InstallShield2012SPRLimitedEdition.exe 下载
  9. 使用谷歌提供的html5shiv.js解决
  10. 3. 工作分配问题(回溯法)设有n件工作分配给n个人。。。