Spring In Action 4 学习笔记(一)Spring概览

Spring的核心概念就是DI和AOP,是Spring实现所有复杂华丽框架的基石。

相对于EJB等重型框架,Spring更加轻量化,可以强化普通的POJO对象。

1、简化JAVA开发

为了尽可能简化Java的开发,Spring遵循如下4个策略:

  • Lightweight and minimally invasive development with POJOs

使用POJO类进行轻量化低侵入式的开发

  • Loose coupling through DI and interface orientation

通过依赖注入和接口降低耦合

  • Declarative programming through aspects and common conventions

通过切面和约定进行声明式编程

  • Eliminating boilerplate code with aspects and templates

通过切面和模板消除冗余代码

关键字:POJO类、低侵入、DI、AOP、Template

1.1、强化POJO类

使用Spring你完全不用在你的代码中掺杂Spring的API,也几乎不需要继承Spring的接口或父类。当然,可能是需要加如一些注解。像如下这段代码:

    package com.habuma.spring;
    public class HelloWorldBean {
        public StringsayHello() {
            return "HelloWorld";
        }
    }

就是一个普通的JAVA类,没有侵入Spring特性的代码,完全可应用在非Spring应用中。但Spring可以把它添加到自己的上下文中,即可作为Spring的Bean来使用,从而使其获取强大的力量。

1.2、依赖注入

DI可以使你的代码更简洁、易读、便于测试。

任何应用中的类之间都有依赖关系,它们必需相互协作以完成业务逻辑,导致程序耦合性强、难以测试。如下例子:

    package com.springinaction.knights;
    public classDamselRescuingKnight implements Knight {
        private RescueDamselQuest quest;
        public DamselRescuingKnight() {
            //该依赖产生强耦合
            this.quest = new RescueDamselQuest();
        }
        public void embarkOnQuest() {
            quest.embark();
        }
    }

DamselRescuingKnight对RescueDamselQuest的引用直接写在构造方法中,两者之间耦合性太强,DamselRescuingKnight想要更换一个Quest的实现的话都要写一个新的类来实现。

而且如果想要对DamselRescuingKnight 进行单元测试也不容易。

DI在对象创建时通过第三方绑定其依赖的对象,从而降低耦合。改造后的代码如下:

    package com.springinaction.knights;
    public class BraveKnight implements Knight {
        //引用接口
        private Quest quest;
        //依赖作为参数传入
        public BraveKnight(Quest quest) {
            this.quest = quest;
        }
        public void embarkOnQuest() {
            quest.embark();
        }
    }

对依赖对象的引用改为接口,依赖对象通过参数传入,称为构造方法注入。

对BraveKnight类的测试:

	package com.springinaction.knights;
	import static org.mockito.Mockito.*;
	import org.junit.Test;
	public class BraveKnightTest {
		@Test
		public void knightShouldEmbarkOnQuest() {
			Quest mockQuest = mock(Quest.class);
			BraveKnight knight = new BraveKnight(mockQuest);
			knight.embarkOnQuest();
			verify(mockQuest,times(1)).embark();
		}
	}

Knight对Quest的依赖可以使用参数来绑定,Spring中通过XML、Java Config、Autowired来实现绑定。

1.3、引入切面

应用中通常会承担一些本不属于自己职责的工作,如日志记录、事务处理、安全管理等,而这些功能往往需要贯穿整个应用的任何角落。这从两个方面提高了应用复杂度:

  • 这些代码遍布与应用中,当需要修改其实现方式时,对所有代码都有影响,即便做成共通方法,方法的调用方式也可能有变化,也不得不全面测试。
  • 各模块的职责不再单一,比如一个通讯录模块不应去关心安全性和事务问题。

看一个例子便于理解:

	package com.springinaction.knights;
	import java.io.PrintStream;
	public class Minstrel {
		private PrintStream stream;
		public Minstrel(PrintStream stream) {
			this.stream= stream;
		}
		public void singBeforeQuest() {
			stream.println("Fala la, the knight is so brave!");
		}
		public void singAfterQuest() {
			stream.println("Teehee hee, the brave knight did embark on a quest!");
		}
	}

	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 {
<span style="background-color: rgb(255, 255, 51);">			if(minstrel != null) {
				minstrel.singBeforeQuest();
			}</span>
			quest.embark();
<span style="background-color: rgb(255, 255, 51);">			if(minstrel != null) {
				minstrel.singAfterQuest();
			}</span>
		}
	}

BraveKnight的职责就是embarkOnQuest,不应该由BraveKnight来执行Minstrel的方法,而且BraveKnight也不应对Minstrel产生依赖。在业务类及此类功能模块增多时复杂度也会指数上升:

AOP的思想可以完美的解决这些问题,业务功能不必再考虑自己职责以外的工作,日志、事务、安全等被独立为单独的模块,通过Spring的切面管理覆盖到需要的功能模块上:

	<?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-3.2.xsd
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd">
		<bean id="knight" class="com.springinaction.knights.BraveKnight">
			<constructor-arg ref="quest" />
		</bean>
		<bean id="quest" class="com.springinaction.knights.SlayDragonQuest">
			<constructor-arg value="#{T(System).out}" />
		</bean>
		<bean id="minstrel" class="com.springinaction.knights.Minstrel">
			<constructor-arg value="#{T(System).out}" />
		</bean>
		<aop:config>
<span style="background-color: rgb(255, 255, 51);">			<aop:aspect ref="minstrel">
				<!--Define pointcut with AspectJ's pointcut EL -->
				<aop:pointcut id="embark"
					expression="execution(* *.embarkOnQuest(..))"/>
				<aop:before pointcut-ref="embark" method="singBeforeQuest"/>
				<aop:after pointcut-ref="embark" method="singAfterQuest"/>
			</aop:aspect></span>
		</aop:config>
	</beans>

通过该配置文件,定义切点,声明切面切入位置,切入代码由上下文来控制和调用,从而降低了模块间的耦合及应用复杂度,BraveKnight和Minstrel类中没有任何迹象体现AOP,它们仍然是POJO的,而BraveKnight中也没有对Minstrel的引用:

1.4、使用模板

虽然Java作为高级语言已经帮我们处理了很多底层操作:垃圾回收、内存申请等,但有时我们还是不得不写很多冗余代码,比如访问DB:

	public Employee getEmployeeById(long id) {
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			conn = dataSource.getConnection();
			stmt = conn.prepareStatement(
				"select id, firstname, lastname, salary from employee where id=?");
			stmt.setLong(1, id);
			rs = stmt.executeQuery();
			Employee employee = null;
			if (rs.next()) {
				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;
		} catch (SQLException e) {
			…...
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch(SQLException e) {}
			}
			if(stmt != null) {
				try {
					stmt.close();
				} catch(SQLException e) {}
			}
			if(conn != null) {
				try {
					conn.close();
				} catch(SQLException e) {}
			}
		}
		return null;
	}

一个简单的员工信息查询,主要代码被淹没在跟业务无关的代码中,而且这些冗余代码对不同的db访问操作都是相同的,catch到的异常在这里也不能做不了什么特殊处理。

Spring提供了模板来解决此类问题,如处理DB访问的JdbcTemplate,可以将DB访问相关的冗余代码移到模板中,使程序员和代码可以专注于业务逻辑的实现。

2、Bean容器

Spring中的Bean对象由container来创建、绑定,并管理它们的生命周期。Container属于Spring框架的核心模块,

Container有两种类型的实现:org.springframework.beans.factory.BeanFactory和org.springframework.context.ApplicationContext。Bean factories提供最基本的容器支持;Application contexts在bean factories的基础之上为应用提供了其它一些服务。一般都是用application contexts。

2.1、应用ApplicationContext

Spring实现了几种ApplicationContext接口,常见实现的如下:

  • AnnotationConfigApplicationContext—用于加载基于Java及注解的配置
  • AnnotationConfigWebApplicationContext—用于Spring Web应用,加载基于Java及注解的配置
  • ClassPathXmlApplicationContext—用于从classpath资源文件加载基于XML的配置
  • FileSystemXmlApplicationContext—用于从文件系统加载基于XML的配置文件
  • XmlWebApplicationContext—用于从web应用中加载基于XML的配置文件

应用示例:

	ApplicationContext context = new FileSystemXmlApplicationContext("c:/knight.xml");
	//knight.xml在$classpath目录下
	ApplicationContext context = new ClassPathXmlApplicationContext("knight.xml");

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

得到applicationcontext实例之后,就可以通过其getBean()方法获取定义的bean对象。

2.2、Spring Bean生命周期

系统开发中Spring Bean的生命周期很少用到,如果需要搭建自己的框架,在创建bean的过程中进行一些定制化的操作的话,会很有帮助。

  1. 实例化bean对象;
  2. 给bean的属性注入值或对其它bean的依赖;
  3. 如果bean实现了BeanNameAware接口,调用setBeanName()方法传入bean的ID;
  4. 如果bean实现了BeanFactoryAware接口,调用setBeanFactory()方法传入bean factory;
  5. 如果bean实现了ApplicationContextAware接口,调用setApplicationContext()方法传入 application context;
  6. 如果bean实现了BeanPostProcessor接口,调用postProcessBeforeInitialization()方法;
  7. 如果bean实现了InitializingBean接口,调用afterPropertiesSet()方法;
  8. 如果bean自定义了init方法,调用该方法;
  9. 如果bean实现了BeanPostProcessor接口,调用postProcessAfterInitialization()方法;
  10. Bean实例投入使用,直到application context被销毁;

容器关闭时:

  1. 如果bean实现了DisposableBean接口,调用postProcessAfterInitialization()方法;
  2. 如果bean自定义了detroy方法,调用该方法。

3、Spring领域纵览

在Spring核心框架之上,Spring还扩展到web services、REST、mobile、NoSQL等领域。

3.1、Spring核心模块

Spring4.0包含20个模块,每个模块三个jar文件:二进制包、源码、JavaDoc。项目中可以根据实际需要导入相应的包。这些模块按其功能可分为6类:

3.2、Spring portfolio

Spring提供了丰富的产品包,将Spring编程模型引入到了Java开发的几乎每个层面。

  • SPRING WEB FLOW

基于Spring MVC,为创建交互式、流程式Web应用提供支持,如向导、购物车等功能。 http://projects.spring.io/spring-webflow/

  • SPRING WEB SERVICES

Spring核心的web service是基于协议后置模型,服务协议取决于bean的接口。SpringWeb Services提供了协议前置模型,根据服务协议来实现具体的服务。
http://docs.spring.io/spring-ws/site/

  • SPRING SECURITY

基于AOP,为Spring应用提供安全机制。http://projects.spring.io/spring-security/

  • SPRING INTEGRATION

提供了几种常见集成模型的实现。http://projects.spring.io/spring-integration/

  • SPRING BATCH

提供对数据批处理的支持。http://projects.spring.io/spring-batch/

  • SPRING DATA

Spring Data简化了跟各种数据库(关系型、对象型、Graph DB)的协作。

  • SPRING SOCIAL

对于网络社交类的应用提供了支持,不过相对于社交,Spring Social更侧重于连接,可以通过REST APIs等方式跟其它应用建立关联。https://spring.io/guides/gs/accessing-facebook/https://spring.io/guides/gs/accessing-twitter/

  • SPRING MOBILE

手机、平板正成为更主流的客户端,SpringMobile是对Spring MVC在移动WEB应用领域的扩展。

  • SPRING FOR ANDROID

引入Spring框架来简化Android设备的本地应用开发,该项目初期提供了RestTemplate,可以通过REST APIs与Spring Social协作。http://projects.spring.io/spring-android/

  • SPRING BOOT

提供了快速创建Spring应用的途径,Spring Boot应用了自动配置技术,并提供了一些starter项目来减少Spring工程的build文件,不论是用Maven还是Gradle。

时间: 2024-08-08 21:19:54

Spring In Action 4 学习笔记(一)Spring概览的相关文章

Spring in Action 4th 学习笔记 之 AOP

先说说为什么需要AOP 最简单的一个例子就是日志记录,如果想记录一些方法的执行情况,最笨的办法就是修改每一个需要记录的方法.但这,真的很笨... 好的方法,应该是通过反射获取方法,然后去匹配,如果需要记录日志,那就调用日志方法即可. 这就是AOP 的Weaving,俗称编织.织入,就是将需要添加的功能编织到现有功能中,而不需要修改现有代码. 另一个例子,不那么大众的需求:我想给一个对象添加方法,怎么实现? 如果有学过js.Python等动态语言,你肯定知道它们支持给对象添加方法,直接添加即可.

Spring in Action 4th 学习笔记

约定: 一.@Xxx Class 表示被@Xxx注解的类.同理还有@Xxx注解的字段或方法. 例如:@Bean Method. 二.@Component Class 同时代指 @Controller.@Service.@Repository. All beans in a Spring application context are given an ID. -- 如果不指明,也会给定一个默认的ID:类名,首字母小写.[]上面这句,不适合XML方式,因为XML方式的默认ID是全路径再加上#{n}

mybatis学习笔记(14)-spring和mybatis整合

mybatis学习笔记(14)-spring和mybatis整合 mybatis学习笔记14-spring和mybatis整合 整合思路 整合环境 sqlSessionFactory 原始dao开发和spring整合后 mapper代理开发 遇到的问题 本文主要将如何将spring和mybatis整合,只是作简单的示例,没有使用Maven构建.并展示mybatis与spring整合后如何进行原始dao开发和mapper代理开发. 整合思路 需要spring通过单例方式管理SqlSessionFa

[Spring Data Repositories]学习笔记--定义自己的repository

有时,我们会需要用到自己定义的一些查询方法,可以按照下面几步进行. 1. 定义一个包含该方法的接口 Interface UserRepositoryCustom { public void someCustomMethod(User user); } 2. 定义实现 class UserRepositoryImpl implements UserRepositoryCustom { public void someCustomMethod(User user){ //Your custom im

[Spring Data Repositories]学习笔记--为repository添加通用的方法

如果想把一个方法加到所有的repository中,用前一篇提到的方法就不合适了. 英文原版,请看 http://docs.spring.io/spring-data/data-mongo/docs/1.5.2.RELEASE/reference/html/repositories.html#repositories.custom-behaviour-for-all-repositories 1. 定义自己的repository,要从基础的repository进行继承. public interf

[Spring Data Repositories]学习笔记--使用现有的repository

以下内容是在学习Spring-Data-mongoDB中的Spring Data Repositories时做的一些笔记.备忘! 感觉学习还是看官方的资料比较透彻一些. Spring Data Repositories目的:减少重复的持久化代码. 常用的几个repository interface, Repository <-- CurdRepository <-- PagingAndSortingRepository 最后一个主要是用来做分页和排序用的. Repository使用步骤 1.

spring学习笔记(一) Spring概述

博主Spring学习笔记整理大部分内容来自Spring实战(第四版)这本书.  强烈建议新手购入或者需要电子书的留言. 在学习Spring之前,我们要了解这么几个问题:什么是Spring?Spring的优势在哪里?怎么系统的学习Spring? 一.什么是Spring? Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发. 那有人就会问了,Spring是如何简化开发的? 在传统开发中,一个应用是需

Spring+SpringMVC+MyBatis集成学习笔记【一】

一,首先要清楚,SpringMVC其实就是Spring的一个组件       例如我们知道Spring中有类似于,AOP TX等等类似的组件,所以SpringMVC其实就是Spring的一个组件,是Spring框架的一部分,千万不要把SpringMVC当成是另一种框架!       所以在配置上,还是按照配置Spring的套路来,该配置监听,配置监听,该配置配置文件,配置配置文件,一切照旧 二,Spring在Web.xml中的配置       在Web.xml中配置Spring大致可以分为两点

Spring学习笔记1——spring搭建

1.新建一个java工程 2.添加spring相关的jar包并添加到引用 3.添加spring依赖的相关jar包并添加到引用 4.编写spring配置文件applicationcontext.xml 新建applicationContext.xml文件,然后编写头文件.关于spring头文件的写法可以参考spring提供的guide. 解压下载的spring文件,找到docs\spring-framework-reference\html\index.html并打开,然后找到 在打开的页面中会有