spring实战 第4版 学习

企业级 JavaBean(Enterprise JavaBean,EJB)

简单老式 Java 对象(Plain Old Java object,POJO)

Java 2 企业版(Java 2 Enterprise Edition, J2EE) (现在称之为JEE)

依赖注入(Dependency Injection,DI)

面向切面编程(Aspect-Oriented Programming,AOP)

 

Spring 组件  JavaBean 相当于POJO

 

Spring目的只有一个:简化 Java 开发

 

1)基于 POJO 的轻量级和最小侵入性编程;

2)通过依赖注入和面向接口实现松耦合;

3)基于切面和惯例进行声明式编程;

4)通过切面和模板减少样板式代码。

 

IOC和AOP

 

依赖注入(DI)

public BraveKnight(Quest quest) {

    this.quest = quest;

  }

依赖注入的方式之一,即构造器注入(constructor injection)

 

Quest 接口,所有探险任务都需要实现该接口

 

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

 

IOC是容器,依赖注入(DI)是方式,都是借助于“第三方”实现具有依赖关系的对象之间的松耦合

https://images0.cnblogs.com/blog/281227/201305/30131727-a8268fe6370049028078e6b8a1cbc88f.png

对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。控制权都在自己手上。

当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。

对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”。即获得依赖对象的过程被反转了”

 

如何将SlayDragonQuest 交给 BraveKnight 呢?又如何将 PrintStream 交给 SlayDragonQuest 呢?

 

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

XML 就是Spring 装配 bean 很常见的一种装配方式

knights.xml

<?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="knight" class="sia.knights.BraveKnight">
    <constructor-arg ref="quest" />
  </bean>

  <bean id="quest" class="sia.knights.SlayDragonQuest">
    <constructor-arg value="#{T(System).out}" />
  </bean>

</beans>

BraveKnight bean 来讲,它在构造时传入了对 SlayDragonQuest bean 的引用,将其作为构造器参数。

 

Spring 通过应用上下文(Application Context)装载 bean 的定义并把它们组装起来。

Spring 应用上下文 全权负责 对象的创建和组装。

 

使用 XML 文件,选择ClassPathXmlApplicationContext 上下文

KnightMain.java

public static void main(String[] args) throws Exception {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/knight.xml");
    Knight knight = context.getBean(Knight.class);
    knight.embarkOnQuest();
    context.close();
  }

基于 knights.xml 文件创建了 Spring 应用上下文。随后它调用该应用上下文获取一个 ID 为 knight 的 bean。

得到 Knight 对象的引用后,只需简单调用 embarkOnQuest() 方法就可以执行所赋予的探险任务了。

 

这个类完全不知道我们的英雄骑士接受哪种探险任务,而且完全没有意识到这是由 BraveKnight 来执行的。只有 knights.xml 文件知道哪个骑士执行哪种探险任务。

 

BraveKnight 对象A,  SlayDragonQuest对象B 继承Quest接口,knights.xml

装配哪个骑士和哪个探险任务,Context 调用xml文件,生成bean 执行任务。

 

面向切面编程(aspect-oriented programming,AOP)

DI 能够让相互协作的软件组件保持松散耦合、AOP允许你把遍布应用各处的功能分离出来形成可重用的组件。

实现关注点的分离

 

不同的系统组件除了自身核心业务逻辑的功能之外,还会有日志、事务管理和安全这样的系统服务,这些系统服务通常被称为横切关注点。因为它们会跨越系统的多个组件。

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

切面可以想象为覆盖在很多组件之上的一个外壳。

举例:使用吟游诗人这个服务类来记载骑士的所有事迹

Minstrel 类

public class Minstrel {
​
  private PrintStream stream;
  
  public Minstrel(PrintStream stream) {
    this.stream = stream;
  }
​
  public void singBeforeQuest() {
    stream.println("Fa la la, the knight is so brave!");
  }
​
  public void singAfterQuest() {
    stream.println("Tee hee hee, the brave knight " +
    		"did embark on a quest!");
  }
}

Minstrel 都会 通过构造器注入  PrintStream 类 来歌颂骑士的事迹。两个简单方法,探险任务前后。

 

将 BraveKnight 和 Minstrel 组合起来。

利用 AOP,你可以声明吟游诗人必须歌颂骑士的探险事迹,而骑士本身并不用直接访问 Minstrel 的方法。

在 knights.xml文件中,声明 Minstrel 为一个切面。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xsi:schemaLocation="http://www.springframework.org/schema/aop 
  http://www.springframework.org/schema/aop/spring-aop.xsd
  http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans.xsd">
​
  <bean id="knight" class="sia.knights.BraveKnight">
    <constructor-arg ref="quest" />
  </bean>
​
  <bean id="quest" class="sia.knights.SlayDragonQuest">
    <constructor-arg value="#{T(System).out}" />
  </bean>
​
  <bean id="minstrel" class="sia.knights.Minstrel">
    <constructor-arg value="#{T(System).out}" />
  </bean>
​
  <aop:config>
    <aop:aspect ref="minstrel">
      <aop:pointcut id="embark"
          expression="execution(* *.embarkOnQuest(..))"/>
        
      <aop:before pointcut-ref="embark" 
          method="singBeforeQuest"/>
​
      <aop:after pointcut-ref="embark" 
          method="singAfterQuest"/>
    </aop:aspect>
  </aop:config>
  
</beans>

前置通知(before advice)、后置通知(after advice) 两种方式

pointcut-ref 属性都引用了名字为 embark 的切入点

expression 属性来选择所应用的通知,AspectJ 的切点表达式语言

 

首先,Minstrel 仍然是一个 POJO,没有任何代码表明它要被作为一个切面使用。当我们按照上面那样进行配置后,在 Spring 的上下文中,Minstrel 实际上已经变成一个切面了。

其次,也是最重要的,Minstrel 可以被应用到 BraveKnight 中,而 BraveKnight 不需要显式地调用它。实际上,BraveKnight 完全不知道 Minstrel 的存在。

 

我们把 Minstrel 转变为一 个切面,首先要把它声明为一个 Spring bean。可以为其他 Spring bean 做到的事情都可以同样应用到 Spring 切面中,例如为它们注入依赖。

 

样板式代码的一个常见范例是使用 JDBC 访问数据库查询数据。还有JMS、JNDI 和使用 REST 服务

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

Spring 的  JdbcTemplate, 重写的 getEmployeeById() 方法

public Employee getEmployeeById(long id) {
  return jdbcTemplate.queryForObject(
    "select id, firstname, lastname, salary " +
    "from employee where id=?",
    new RowMapper<Employee>() {
      public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
        Employee employee = new Employee();
        employee.setId(rs.getLong("id"));
        employee.setFirstName(rs.getString("firstname"));
        employee.setLastName(rs.getString("lastname"));
        employee.setSalary(rs.getBigDecimal("salary"));
        return employee;
      }
    }, 
    id);
}

jdbcTemplate.queryForObject( "select...." , new RowMapper<Employee>(){...},  id ) 

一个 SQL 查询语句,一个 RowMapper 对象(把数据映射为一个域对象),零个或多个查询参数

 

在基于 XML 的配置文件中如何配置 bean 和切面,但这些文件是如何加载的呢?它们被加载到哪里去了?让我们再了解下 Spring 容器,这是应用中的所有 bean 所驻留的地方。

 

spring容器

应用对象生存于 Spring 容器(container) 中,Spring 容器 负责创建对象,装配它们,配置它们并管理它们的整个生命周期

Spring 自带了多个容器实现,可以归为两种不同的类型

bean 工厂(由 org.springframework.beans.factory.BeanFactory 接口定义)是最简单的容器,提供基本的 DI 支持。(太低级了)

应用上下文(由 org.springframework.context.ApplicationContext 接口定义)基于 BeanFactory 构建,并提供应用框架级别的服务,

例如从属性文件解析文本信息以及发布应用事件给感兴趣的事件监听者。

 

  • AnnotationConfigApplicationContext:从一个或多个基于 Java 的配置类中加载 Spring 应用上下文。

  • AnnotationConfigWebApplicationContext:从一个或多个基于 Java 的配置类中加载 Spring Web 应用上下文。

  • ClassPathXmlApplicationContext:从类路径下的一个或多个 XML 配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。

  • FileSystemXmlapplicationcontext:从文件系统下的一 个或多个 XML 配置文件中加载上下文定义。

  • XmlWebApplicationContext:从 Web 应用下的一个或多个 XML 配置文件中加载上下文定义。

 

FileSystemXmlApplicationContext:
在指定的文件系统路径下查找 knight.xml文件

ApplicationContext context = new FileSystemXmlApplicationContext("c:/knight.xml");



ClassPathXmlApplicationContext:
在所有的类路径(包含 JAR 文件)下查找 knight.xml 文件

ApplicationContext context = new ClassPathXmlApplicationContext("knight.xml");

AnnotationConfigApplicationContext:
从 Java 配置中加载应用上下文

ApplicationContext context = new AnnotationConfigApplicationContext(com.springinaction.knights.config.KnightConfig.class);

装载应用上下文,将 bean 加载到 bean 工厂

应用上下文准备就绪之后,我们就可以调用上下文的 getBean() 方法从 Spring 容器中获取 bean。

 

Spring 容器中的 bean 的生命周期

Spring 框架的核心

Spring 4.0 中,Spring 框架包括了 20 个不同的模块,JAR 文件

容器是 Spring 框架最核心的部分,它管理着 Spring 应用中 bean 的创建、配置和管理。在该模块中,包括了 Spring bean 工厂,它为 Spring 提供 了 DI 的功能。基于 bean 工厂,我们还会发现有多种 Spring 应用上下文的实现,每一种都提供了配置 Spring 的不同方式。

Spring 的 JDBC 和 DAO(Data Access Object)模块抽象了JDBC 编写代码这些样板式代码。

ORM(Object-Relational Mapping)工具、JMS(Java Message Service)、

Instrumentation 仪器仪表?   Portfolio作品集

 

Spring Boot    以 Spring 的视角, 致力于简化 Spring 本身。

消除大部分(在很多场 景中,甚至是全部)Spring 配置。它还提供了多个 Starter 项目,不管你使用 Maven 还是 Gradle,这都能减少 Spring 工程构建文件的大小。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值