《Spring实战》第一章读书笔记

5 篇文章 0 订阅

    最近的开发中,感觉对Spring框架的掌握还不够熟练,重新翻出了《Spring实战》这本书,重新学习一遍,以此记录。

1.1.2 依赖注入

    任何一个有实际意义的应用都是由两个或多个类组成,这些类相互之间进行协作来完成特定的业务逻辑。通常,每个对象负责管理与自己相互协作的对象(即它所依赖的对象)的引用。这将导致高度耦合和难以测试的代码。

    因高度耦合而执行特定任务的knight类:

package com.springinaction.knights;
public class DamselrescuingKnight implements Knight{
private RescueDamselQuest quest;

public DamselRescuingKnight(){
    quest = new RescueDamselQuest();
}

public void embarkOnQuest() throws QuestException{
    quest.embark();
}
}

    DamselrescuingKnight 类在它的构造器中自行创建了RescueDamselQuest。这使得DamselrescuingKnight紧密地与RescueDamselQuest耦合到了一起,因此极大地限制了这个类的能力,只能执行对应的救援(RescueDamselQuest)任务,无法执行其他任务。

    优化后足够灵活且强大的BraveKnight类:

package com.springinaction.knights;
public class braveKnight implements Knight{
	private Quest quest;

	public BraveKnight(Quest quest){
		this.quest = quest;       //<--Quest被注入进来
	}
	
	public void embarkOnQuest() throws QuestException{
		quest.embark();
	}
}

    正如看到的那样,不同于之前的DamselrescuingKnight,BraveKnight没有自行创建任务(即没有在构造器中new一个新的具体对象),而是在构造时把任务(Quest)作为构造器参数传入。这是依赖注入的方式之一,即构造器注入

   更重要的是,它被传入的探险类型是Quest,也就是一个所有任务都必须实现的接口。所以,BraveKnight能够响应RescueDamselQuest、SlayDragon-Quest、MakeRoundTableRoundQuest等任意一种Quest接口的具体实现,且BraveKnight没有与任何特定的Quest实现发生耦合。

    创建应用组件之间协作的行为通常称为装配。spring有多种装备bean的方式,采用XML配置通常是最常见的装配方式

使用Spring配置文件将SlayDragonQuest注入到BraveKnight中:

<?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-3.0.xsd">

	<bean id="knight" class="com.springinaction.knights.BraveKnight">
		<constructor-arg ref="quest" />   //向BraveQuest的构造器注入quest bean
		
	</bean>

	<bean id="quest" class="com.springinaction.knights.SlayDragOnQuest" />   //创建SlayDragonQuest bean


</beans>

观察它如何工作:

    Spring通过应用上下文(Application Context)装载Bean的定义并把它们组装起来。Spring应用上下文全权负责对象的创建和组装。Spring自带了几种应用上下文的实现,它们之间主要的区别仅仅是如何加载它们的配置。

加载包含Knight的Spring上下文:

package com.springinaction.knights;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class KnightMain{
	public static void main(String[] args){
		ApplicationContext context = new ClassPathXmlApplicationContext("knights.xml"); //加载Spring上下文
		
		Knight knight = (Knight) context.getBean("knight");  //获取knight Bean
		
		knight.embarkOnQuest();   //使用knight
	}
}

这个类完全不知道knight接受哪种任务,而且也没有体现出来这是由BraveKnight来执行的。

1.1.3 应用切面

依赖注入让相互协作的软件组件保持松散耦合,而AOP编程允许把遍布应用各处的功能分离出来形成可重用的组件。

利用AOP,可以使用各种功能层去包裹核心业务层。这些层以声明的方式灵活应用到系统中,甚至核心应用根本不知道他们的存在。这是一个非常强大的理念,可以将安全、事务和日志关注点与你的核心业务逻辑相分离。

AOP应用:

每一个人都熟知骑士的任何事情,这是因为吟游诗人用诗歌记载了骑士的事迹并将其进行传颂。Minstrel(吟游诗人)类记载了骑士的所有事迹。

package com.springinaction.knights;

public class Minstrel{
	public void springBeforeQuest{
		//骑士执行任务之前调用
		System.out.println("Fa la la;The knight is so brave!");
	}
	
	public void singAfterQuest(){
		//骑士执行任务后调用
		System.out.println("Tee hee he;The brave knight did embark on a quest!");
	}

}

适当地调整BraveKnight可以使用Minstrel,BraveKnight必须调用Minstrel方法:

package com.springinaction.knights;

public class BraveKnight implements Knight{
	private Quest quest;
	private Minstrel minstrel;

	public BraveKnight(Quest quest,Minstrel minstrel){
		this.quest = quest;
		this.minstrel = minstrel;
	}

	public void embarkOnQuest() throws QuestException{
		minstrel.singBeforeQuest();
		quest.embark();
		minstrel.singAfterQuest();
	}
}

这样虽然可以达到预期效果,但管理吟游诗人不应该是骑士的职责工作,骑士只需要负责执行任务,吟游诗人需要自主记录传颂。

利用AOP,可以声明吟游诗人必须歌颂骑士的事迹,而骑士就不再直接访问吟游诗人的方法了。把Minstrel抽象为一个切面,然后在Spring配置文件中声明它即可。

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.springfrmework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	   http://www.springframework.org/schema/aop
	   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"

	<bean id="knight" class="com.springinaction.knights.BraveKnight">
		<constructor-arg ref="quest" />
	</bean>
	
	//声明minstrel Bean
	<bean id="minstrel" class="com.springinaction.knights.Minstrel" />
	
	<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>

在前置通知,后置通知这两种方式中都引用了名为embank的切入点。该切入点是在前边的<pointcut>元素中定义的,并配置expression属性来选择所应用的通知。

Spring的两种不同类型的容器实现:

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

应用上下文(application)由org.springframework.context.ApplicationContext接口定义)基于BeanFactory之上构建,并提供面向应用的服务。

Spring自带的三种最有可能碰到的应用上下文:

ClassPathXmlApplicationContext:从类路径下的XML配置文件中加载上下文定义,把应用上下文定义文件当作类资源。

FileSystemXmlapplicationcontext:读取文件系统下的XML配置文件并加载上下文定义。

XmlWebApplicationContext:读取Web应用下的XML配置文件并装载上下文定义。

    加载一个FileSystemXmlapplicationcontext:

ApplicationContext context = new FileSystemXmlApplictionContext("c:/foo.xml");

    类似地,加载一个ClassPathXmlApplicationContext:

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

两者区别在于FileSystemXmlApplicationContext在指定的文件系统路径下查找foo.xml文件。

而ClassPathXmlApplicationContext是在所有的类路径(包含jar文件)下查找foo.xml文件。

Spring中Bean的生命周期:

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()接口方法,将应用上下文的引用传入。

6、如果Bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessBeforeInitialization()接口方法。

7、如果Bean实现了Initialization接口,Spring将调用它们的afterPropertiesSet()接口方法。类似地,如果Bean使用init-method声明了初始化方法,该方法也会被调用。

8、如果Bean实现了BeanPostProcessor接口,Spring将调用它们的postPoressAfterInitialization()方法。

9、此时,Bean已经准备就绪,可以被使用了,它们将一直驻留在应用上下文中,知道该应用上下文被销毁。

10、如果Bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。

Spring模块:

1、核心Spring容器(Core Spring container)

2、Spring的AOP模块

3、数据访问与集成

4、Web和远程调用

5、测试


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值