手记

服务器小白自学Spring的通俗笔记 - 第一章

原创内容,版权所有,转载请注明出处。

这个系列的开篇传送门: https://www.imooc.com/article/80510
在看这一篇之前,对于接口的理解还不是很透彻的小伙伴,可以先看这一篇: https://www.imooc.com/article/19697

对于我这种对服务器一无所知的小白来说,找一本合适的书应该是第一个要解决的问题,我的目的是通过学习Spring,来开发提供移动端使用的服务器,为移动端提供Restful API。又看了看目录,感觉《Spring实战(第四版)》比较符合我的预期,那么好吧,就选这本书。

很多书都有个问题,在我看来,前几章的内容简直把想要学习的热情转变为望而生畏,根本不是什么循序渐进。。哎,可能我基础太差,一点都不友好,只能硬着头皮看下去了。

在学习Spring这个框架前,书上提到了两个似乎很重要的概念,**一个是依赖注入(DI),一个是面向切面(AOP),**这两个概念就像两击重拳把我打蒙。网上解释可以说是五花八门,让我更加凌乱。我静下来,花了几个小时,似乎明白了点什么,也不知道对不对。

####我认为的依赖注入(DI),通俗起来就一句大白话:我是一个类,我需要和另一个类一起才能工作,请把另一个类通过参数的形式传递给我,通过我的构造方法传递给我也可以,通过我的其他公共方法传递给我也可以。

嗯,应该就是这个解释。那么这个依赖注入到底能干什么?为什么非要用?让我用一个栗子来说一下。讲到这里,我有些饿了,好想吃烧烤。各位都很爱吃烧烤吧,我呢,最爱吃烤鸡皮,鸡皮放在烤盘上,吱吱作响,刷上酱油,烤得外焦里嫩,夹起来,沾一点烧烤辣椒粉,入口,太美妙了。于是我们就有两个类了,鸡皮类(ChickenSkin)烤盘类(BarbecueBakingTray),接下来让我们来烤鸡皮吧。

####准备鸡皮

/**
ChickenSkin.java

鸡皮类,只有一个放在火上的方法。
*/
public class ChickenSkin {

	public void onFire() {
		System.out.println("鸡皮在吱吱作响...");
	}
	
}

####准备烤盘

/**
 * 烤盘类

 * BarbecueBakingTray.java
 */
public class BarbecueBakingTray {
	
	// 声明一下我要烤鸡皮
	private ChickenSkin chickenSkin;
	
	// 拿出烤盘
	public BarbecueBakingTray() {
		
		// 烤盘产生鸡皮 -- (你没看错,我也没打错字)
		chickenSkin = new ChickenSkin();
	}
	
	// 开始烤
	public void startBBQ() {
		chickenSkin.onFire();
	}
}

####烤盘和鸡皮都就绪了,让我们开始烧烤吧

public class Demo {

	public static void main(String[] args) {
		
		// 拿出烤盘
		BarbecueBakingTray barbecueBakingTray = new BarbecueBakingTray();
		
		// 开始烧烤
		barbecueBakingTray.startBBQ();
		
	}
	
}

然后你会在控制台上看见以下文字输出:
#####“鸡皮在吱吱作响…”

我通常会写出这样的代码,没问题嘛,感觉不错,该做的都做了,鸡皮也好了,可以开始吃了。可是吃着吃着,我感觉哪不对劲。我们来看一看BarbecueBakingTray这个类里的构造方法,发现鸡皮居然是从这个方法里产生出来了,这给我一种比较恶心的感觉,鸡皮就这样凭空出现在烤盘上,这不合逻辑啊,这不禁让我不敢去想这个鸡皮的出处。一阵恶心,我放下了鸡皮,愤怒地把烤盘里的鸡皮丢在了地上,不行,我需要吃一点烤蔬菜解解我的恶心感。于是我拿出了韭菜和土豆片,再一次准备烧烤。这一次,我不允许土豆和韭菜凭空出现在我的烤盘上了。

那么现在,烤盘不能自己产生食物了,我放什么就烧烤什么,烤盘依赖食物,嗯,这似乎就是依赖注入(DI)了。一个烤盘上,我既要烧烤土豆,又要烧烤韭菜,也许一会还想再吃一些鸡皮,这三个都是食物,都可以用来烧烤,我只有一个烤盘,想要烤得随心所欲,我改进了我的烧烤方法。

####我先描述了这些食物的共性

/**
 * 鸡皮类
 * @author seokho
 * BarbecueFood.java
 */
public interface BarbecueFood {
	// 所有食物都可以拿来烤
	void onFire();
	
}

####然后我准备了三样食物,他们都符合这个共性 (提醒一下,这几个类写在一起,但是他们都在不同的包里)

/**
 * 鸡皮类
 * @author seokho
 * ChickenSkin.java
 */
public class ChickenSkin implements BarbecueFood {

	@Override
	public void onFire() {
		// TODO Auto-generated method stub
		System.out.println("鸡皮在吱吱作响...");
	}
}

/**
 * 韭菜类
 * @author seokho
 * Chives.java
 */
public class Chives implements BarbecueFood {

	@Override
	public void onFire() {
		// TODO Auto-generated method stub
		System.out.println("韭菜噼啪作响...");
	}
}

/**
 * 土豆类
 * @author seokho
 * Potato.java
 */
public class Potato implements BarbecueFood {

	@Override
	public void onFire() {
		// TODO Auto-generated method stub
		System.out.println("土豆正在变糊...");
	}
}

####然后我准备好了我的烧烤盘

/**
 * 烤盘类
 * @author seokho
 *
 */
public class BarbecueBakingTray {
	
	private BarbecueFood barbecueFood;
	
	// 放入可以烧烤的食物
	public void putFoodOn(BarbecueFood barbecueFood) {
		this.barbecueFood = barbecueFood;
	}
	
	// 开始烧烤
	public void startBBQ() {
		barbecueFood.onFire();
	}
}

####一切就绪,我们从新开始烧烤吧

public class Demo {

public static void main(String[] args) {
	
		// 准备鸡皮
		BarbecueFood chickenSkin = new ChickenSkin();
		
		// 准备韭菜
		BarbecueFood chives = new Chives();
		
		// 准备土豆
		BarbecueFood potato = new Potato();
		
		// 准备烤盘
		BarbecueBakingTray barbecueBakingTray = new BarbecueBakingTray();
		
		
		// 开始烤鸡皮
		barbecueBakingTray.putFoodOn(chickenSkin);
		barbecueBakingTray.startBBQ();
		
		// 开始烤韭菜
		barbecueBakingTray.putFoodOn(chives);
		barbecueBakingTray.startBBQ();
				
		// 开始烤土豆
		barbecueBakingTray.putFoodOn(potato);
		barbecueBakingTray.startBBQ();
		
	}

}

然后你会在你的控制台看见以下文字输出:
#####鸡皮在吱吱作响…
#####韭菜噼啪作响…
#####土豆正在变糊…

好了,同一个烤盘,可以烤不同的食物。在烤盘类的 putFoodOn 方法里,传入的参数是一个接口,而实现了这个接口的类都可以作为参数进行传递,这就是依赖注入, 实现了烧烤食物共性的鸡皮类(ChickenSkin),韭菜类(Chives),土豆类(Potato),都可以通过烤盘类(BarbecueBakingTray)的putFoodOn方法注入到烤盘里。 好处嘛,我觉得是可以自由替换传入的参数而不需要更改这个类,就好像我可以放入任何可以烧烤的食物,而不需要更换烧烤盘,最大的好处就是解耦

####依赖注入这个概念大概理解了,我需要再次记住,依赖注入(DI),通俗起来就一句大白话:我是一个类,我需要和另一个类一起才能工作,请把另一个类通过参数的形式传递给我,通过我的构造方法传递给我也可以,通过我的其他公共方法传递给我也可以。

另一个重要概念面向切面(AOP),这里先不给出代码,因为我还没有学到那里,但是请允许我再一次举个栗子,来说明这个概念。

吃烧烤,也是要有讲究的,最重要的环节,我认为就是为食物刷酱油和放香料,这样烤出来的食物色泽金黄,美味可口。但是我发现一个问题,每次烤鸡皮,烤土豆,烤韭菜的时候,我都要刷酱油和放香料,实在有点累人,或许我应该叫上我的朋友铁蛋,把这个任务交给他,于是铁蛋一听说有免费烧烤吃,屁颠屁颠就来了,我就告诉铁蛋,只要你看见食物快要熟了,就刷酱油一次,放孜然一小把,花椒面一小把。铁蛋点点头,于是我就只管烤,铁蛋非常有默契的为我们的食物进行味道上的润色,合作非常愉快。

在这里,铁蛋的角色就相当于事务管理,在我执行烧烤的过程中,一旦满足食物快要熟了的条件,或者其他条件,铁蛋就会为食物加调料,这就好比,程序无论在任何地方,一旦出错,就会生成错误报告。

我们不可能为每一个类都添加一个错误报告的生成方法,或者引用错误报告生成类,这不合逻辑。我们需要让错误报告类自己能够收集错误,这就是面向切面。

为什么说不合理呢?比如说我在烧烤土豆,要加调料,我把铁蛋叫来,铁蛋刷好了调料,就回家了。几分钟后,我开始烧烤鸡皮,又把铁蛋叫来,铁蛋刷好了调料,回家了。这样下去,铁蛋会累死。所以我让铁蛋伴随我整个烧烤过程,告诉了他什么时候该怎么做,让他自己处理为食物添加调料的工作。以上就是我对面向切面(AOP)的理解。

好了,这个系列的笔记我会按照我的学习进度进行实时更新,下一篇见。

0人推荐
随时随地看视频
慕课网APP