Spring in Action 第一部分学习笔记

Spring in Action是一本讲解Spring的经典书籍,全书分为三个部分,第一部分介绍Spring框架的核心知识。第二部分在此基础上深入介绍Spring应用程序的常用元素,最后一个部分展示Spring怎么与其它应用和服务进行集成。以下是笔者阅读第一部分记录的读书笔记,共勉。
第一章 Spring之旅
1.1 简化JAVA开发-Spring最根本使命
1.激发POJO的潜能:POJO普通java对象替换EJB
2.依赖注入:解耦,两种注入方式:构造器注入 属性注入
3.应用切面:将系统服务和业务逻辑分离开来,只关心核心业务实现
4.使用模板消除样板式代码:DRY原则应用,提供API消除代码冗余

1.2 容纳Bean的容器-Spring是一个容器框架,主要使用两种类型容器:Bean工厂和应用上下文
1.应用上下文:ApplicationContext包含beanFactory的全部功能,并提供面向应用的服务。
上下文主要分下面三种类型
~1.ClassPathXmlApplicationContext — 从类路径下的xml配置文件中加载上下文定义,classpath加载
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
~2.FileSystemXmlApplicaitonContext — 读取文件系统下的xml配置文件并加载上下文定义,绝对路径加载
ApplicaitonContext context  = new FileSystemXmlApplicaitonContext("c:/spring.xml")
~3.XmlWebApplicationContext — 读取Web应用下的XML配置文件

2.Bean的生命周期:一个bean在容器中从创建到销毁
通过构造器实例化bean-->注入bean中的属性-->设置beanId-->传入beanFactory实例-->传入应用上下文--> 

1.3 Spring 六大功能模块
 核心Spring容器,Spring的AOP木块,数据访问与集成,Web和远程调用,测试

1.4 Spring新功能
Spring 2.5:引入注解
Spring 3.0:支持更多注解,Spring MVC

小结:Spring致力于简化企业及Java开发,对代码进行解耦,而实现的关键在于依赖注入IOC和AOP。

第二章 装配Bean
2.1 声明Bean
1.创建Spring配置文件
Spring传统配置都是通过一个或多个XML文件实现,Spring xml配置文件根元素<beans>里面,可以声明多个命名空间,命名空间提供配置元素。 
2.声明一个简单的Bean :通过传统XML配置文件
<bean id="userService" class="com.springtest.ioc.userServcieImpl"/>
Spring是通过反射机制来创建bean的。
3.通过构造器注入
注入对象引用:
引用bean声明:<bean id="userDao" class="com.springtest.ioc.userDaoImpl"/>
<span style="font-family:Tahoma;"><bean id="userService" class="com.springtest.ioc.userServcieImpl">
<constructor-arg ref="userDao"></bean></span>
注意:可以通过<constructor-arg>ref属性引用Spring容器内声明的其它bean,基本数据类型和String double等类型可以通过value属性注入
4.Bean的作用域
五种作用域:singleton(单例),prototype(每次调用创建一个实例),request,session,global-session
通过<bean scope="prototype"/>scope属性设置作用域。默认是单例
5.初始化和销毁Bean:Bean的生命周期
实现方法一:通过<bean init-method="init()" destory-method="destory()">指定初始化和销户方法
实现方法二:让Bean实现Spring中提供的InitializingBean和DisposableBean的方法,在bean的生命周期内执行实现的方法。但是会与Spring API耦合,推荐使用方法一。
使用默认的init-method和destory-method
可以在XML配置文件<beans default-init-method="init()" default-init-method="destory">上下文中所有bean都会用这个初始化和销毁方法

2.2注入Bean的属性
1.注入简单值&&注入对象引用
Spring中可以使用property元素配置Bean的属性,与constructor-arg通过构造函数注入值不同,property通过调用属性的setter方法来注入值。使用这种方法注入的属性,必须定义setXXX()方法
<bean id="userService" class="com.springtest.ioc.userServcieImpl">
<property name = "属性名" vaule="注入值"></bean> value支持注入多种类型的数值
注入容器中的其它bean则需要通过ref属性。
2.注入内部bean:基于安全性考虑,缺点是不能复用
3.使用命名空间p装配属性:引入命名空间,简化配置
4.装配集合:注入集合类list,set,map,props
5.装配空值:<property>和constructor 不使用value和ref,直接引入<null/>

2.3使用表达式装配:SpEL
#{}标记表示里面内容是SpEL表达式

小结:Spring是一个容器框架,主要提供了两类容器,BeanFactory是最基础的容器,基于BeanFactory构建的applicationContext则提供了更多高级服务。依赖注入使得依赖对象通过容器注入到bean中,传统装配Bean的方法是通过XML文件,Spring容器则是通过读取这些配置文件,利用反射的原理创建Bean。依赖注入中若是注入属性需要一个默认构造器。若定义了一个构造器方法,还需要再定义一个空的构造器。

第三章 最小化Spring XML配置
3.1自动装配Bean属性:减少property和constructor-arg元素
配置方式,指定容器中bean的装配方式
<bean id="userService" class="com.springtest.ioc.userServcieImpl" autowire="装配策略">
1.四种自动装配策略
byName-为属性自动装配ID与该属性的名字相同的Bean
缺点:需要假设Bean的名字与其它的Bean的属性的名字一样。
byType-根据bean中的属性的类型去寻找匹配类型的bean
缺点:属性匹配到多个类型相同的bean会抛出异常
constructor-寻找匹配构造器入参类型的bean
缺点:同byType一样的局限性
autodetect-优先使用constructor进行装配,若不符合类型则使用byType自动装配
2.默认自动装配:在xml文件根元素<beans default-autowire="装配策略">添加default-autowire
默认配置是应用于同一个xml文件配置的bean,并是不指同一个上下文中bean都会采用这种策略,可以在一个上下文中定义多个配置文件,每一个配置文件都可以定义自己的默认自动装配策略,若某个bean内自己定义了自动装配策略,可以覆盖默认装配策略。
3.混合使用自动装配和显式装配:显式装配可覆盖自动装配,解决自动装配的缺点

3.2使用注解装配:介绍Spring3.0中的几个注解
使用注解自动装配与在XML中使用autowire属性自动装配原理上面相同,但是注解方式允许更细粒度的自动装配,在使用注解之前,需要在Spring配置中启用它。通过在xml文件中添加context命名空间,增加<context:annotation-config/>
1.@Autowired
可以标注的地方:属性的SetXXX()方法,构造器,需要自动装配bean引用的任何方法,另外还可以直接标注属性。
单一@Autowired注解的限制:
· 找不到匹配的Bean
A:@Autowired(required=false)来配置自动装配是可选的,即使没有找到匹配类型的bean也不会报错。
· 存在多个匹配类型的Bean
A:@Autowired @Qualifier("BeanId") 将byType转换为显式的ByName装配,缩小候选Bean的范围
拓展:@Resource和@Autowired区别
~@Resource:j2ee注解 javax.annotation.Resource  减少与Spring的耦合@Auotwired:Spring中的注解 org.springframework.beans.factory.annotation.Autowired
~@Resource按照byName注入,@Autowired按照byType注入

2.@Inject:和@Autowired相同可以注解属性,方法和构造器,不同在于没有required属性,要求依赖必须存在,否则就会抛出异常
对于存在多个匹配的bean,可以使用@Named("BeanId")标识可选择的Bean @Named注解是使用@Qualifier注解所标注的注解

3.3 自动检测Bean:消除XML中bean的定义,xml配置越来越少
为了配置Spring自动检测,使用<context:component-scan>代替<context:annotation-config>,前者除了完成与后者一样的工作,还支持Spring自动检测Bean和定义Bean。
1.自动检测标注Bean
<context:component-scan>会扫描以下注解
@Component-标识该类为Spring组件
@Controller-标识该类为Spring MVC controller
@Repository-标识将该类定义为数据仓库
@Service-标识将该类定义为服务
2.过滤组件扫描
<context:component-scan base-package="com.springinaction.springidol">
<context:include-filter type="assignable" expiression="com.springinaction.springidol.Instrument">
<context:exclude-filter type="annotation" expiression="com.springinaction.springidol.SkipIt">
</context:component-scan>
<context:include-filter>定义哪些类需要注册为Spring Bean,不需要给实现接口类都标注上@Component注解
<context:exclude-filter>告知哪些类不需要注册为Spring Bean
总共有5中过滤器类型, assignable-派生与expression的类 annotation-被expression指定注解标识的类
aspectj,custom,regex

3.4使用Spring基于Java的配置:优点在于方便编译期检查配置:
1.创建基于Java的配置
Spring的Java配置允许我们用纯粹的Java代码来配置Spring的应用,但是还是需要少量的XML来启用Java配置。基于Java配置文件为@Configuration标识的类。所以需要在xml添加注解启动配置。
2.声明一个简单的Bean
定义一个Java类,使用@Configuration进行注解,表示这是一个Java配置类。成员方法前注解@Bean,表示这个成员方法返回的对象将会注册到上下文中。方法名将作为该Bean的Id
3.使用Java配置进行注入:在创建Bean的逻辑内完成参数的注入

小结:简化XML配置的方法主要有两种:自动装配和注解,自动装配可以代替property和constructor-arg元素,注解则可以进一步简化Spring XML文件配置,代替bean元素。通过注解可以完全消除XML,只需要注解启动配置。

第4章 面向切面的Spring
4.1面向切面编程概念
分布于应用中多处的功能被称为横切关注点,面向切面编程需要将横切关注点与业务逻辑分离开来。横切关注点可以被模块化为特殊类,这些类被称为切面,通过切面,我们可以定义这个功能以何种方式在何处应用,无需修改受影响的类。
1.AOP术语:通知,切点,连接点
通知:定义切面是什么以及何时使用,时间和时间,切面可以应用5种类型的通知
~Before-在方法被调用之前调用通知
~After-在方法完成之后调用通知
~After-returning-在方法成功执行之后调用通知
~After-throwing-在方法抛出异常后调用通知
~Around-
连接点:是应用执行过程中能够插入切面的一个点。
切点:定义切面在何处使用,地点,通常使用明确的类和方法名称来指定这些切点
切面:通知和切点的结合
2.Spring对AOP的支持:四种AOP支持
~基于代理的经典AOP:笨重复杂
~@AspectJ注解驱动的切面
~纯POJO切面
~注入AspectJ切面-适合Spring各版本
Spring通知是Java编写
Spring在运行期通知对象
Spring只支持方法连接点

4.2 使用切点选择连接点:AspectJ的切点表达式语言定义切点
1.编写切点
切点实例1:execution(* com.springtest.aop.userService.sayHello(..))
execution指示器用于匹配是连接点的执行方法*代表返回任何类型 (..)标识切点选择任意方法
指示器之间可以通过操作符进行连接,限制切点范围
2.使用Spring的bean()指示器
execution(* com.springtest.aop.userService.sayHello(..)) and bean(beanId),限定切点为指定的Bean

4.3在XML中声明切面
AOP的配置元素
<aop:advisor>-定义AOP通知器
<aop:after>-定义AOP后置通知
<aop:after-returning>-定义AOP after-returing通知
<aop:after-throwing>-定义 after-throwing通知
<aop:around>-定义AOP环绕通知
<aop:aspect>-定义切面
<aop:aspectj-autoproxy>-启用@AspectJ注解驱动的切面
<aop:before>-定义AOP前置通知
<aop:config>-顶层的SOP配置元素
<aop:pointcut>-定义切点
1.声明前置和后置通知
大多数AOP配置元素必须在<aop:config>节点内使用,<aop:config>作为切面配置的顶层元素,下面紧跟<aop:aspect ref="声明指定bean的切面">,该bean实现了切面的功能,提供了在切面通知时调用的方法,在内部我们可以定义多个切面,切面里面可以声明多个切点。简单的切面实例配置如下:
<aop:config>
<aop:aspect ref="beanId">
<aop:before pointcut="execution(* com.springtest.aop.userService.sayHello(..))" method="function"/>方法执行之前执行fucntion
</aop:aspect>
</aop:config>
将命名切点分离出来,消除配置冗余,注意一下*号后面有一个空格
<aop:config>
<aop:aspect ref="beanId">
<aop:pointcut id="pointcutId" expression="execution(* com.springtest.aop.userService.sayHello(..))"/>
<aop:before pointcut-ref="pointcutId" method="function"/>方法执行之前执行fucntion
</aop:aspect>
</aop:config>
2.环绕通知:<aop:around>
3.为通知传递参数:定义切点指定方法入参类型,增加arg指示器标识具体入参,同时增加arg-name元素,将引用参数传递给定义的method
4.通过切面引入新功能
<aop:aspect>
<aop:declare-parents types-matching="student+"
implement-interface="people"
default-impl="xiaoming"/>
</aop:aspect>
<aop:declare-parents >声明此切面所通知的bean拥有新的父类型,上述例子中,类型匹配student接口的那些bean会实现people接口,使用default-impl显式指定people的实现。

4.3 通过注解实现切面
通过注解可以使一个Bean不需要额外的类或bean声明就可以将它转换成一个切面。例如:
package com.test.aop.service;
import org.aspectj.lang.annotation.AfterThrowing; 
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class People implements Listener {
 private Singer singer;
 @Pointcut("execution(* com.test.aop.service.MusicSigner.sing(..))")
 public void sing(){}
 @Override
 @AfterThrowing("sing()")
 public void getMoney() {
  System.out.println(singer.getName() + "!唱的不行,退钱!");
 }
 @Override
 @AfterReturning("sing()")
 public void guzhang() {
  System.out.println("为 " + singer.getName() + "鼓掌!");
 }

 @Override
 @Before("sing()")
 public void takeSeat() {
  System.out.println("这是" + singer.getName() + "的演唱会,我正在找座位!");
 }
 @Override
 public void setSinger(Singer singer) {
  this.singer = singer;
 }
}
这样就完成了通过注解声明一个切面,如果想要使用这个切面的功能,必须要XML配置文件内增加<aop:aspectj-autoproxy/>元素,该元素将在Spring上下文中创建一个Annotation-AwareAspectJAutoProxyCreator类自动代理Bean。<aop:aspect>元素和@AspectJ注解都可以把一个POJO变成一个切面,但是<aop:aspect>比注解的优势在于不需要对切面功能的源码进行操作,@AspectJ必须标注类和方法,需要源码支持。
1.注解使用环绕通知:@Around("sing()"),环绕通知功能中可以实现前置和后置通知
2.传递参数给所标注的通知:实现方法跟xml配置差不多,将传参在切面中声明
 @Pointcut("execution(* com.test.aop.service.MusicSigner.sing(String song)) && args(song)")
 public void sing(String song){}
 @Override
 @AfterThrowing("sing(song)")
 public void getMoney() {
  System.out.println(singer.getName() + "!唱的不行,退钱!");
 }
3.标注注入:@DeclareParents

4.5注入AspectJ切面:AspectJ提供了Spring AOP所不能支持的许多类型的切点

小结:通过Spring AOP,我们可以将分布于应用多处的功能模块化成类,减少代码冗余,让类关注自身的功能实现。通过切面可以设置前置通知,后置通知和环绕方法。通过不修改类的代码增加额外的功能,实现开闭原则。在Spring中可以通过xml配合和@AspectJ注解使用切面,同样也提供了功能更为强大的AspectJ。

第一部分到此结束,后续会再整理第二部分的读书笔记,埋头啃书去了!













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值