Spring实战读书笔记

第二章: 装配bean
本章内容:
声明bean
构造器注入和Setter方法注入
装配bean
控制bean的创建和销毁

它提供了三种主要的装配机制:
在XML中进行显式配置。
在Java中进行显式配置。
隐式的bean发现机制和自动装配。

Spring从两个角度来实现自动化装配:
组件扫描(component scanning):Spring会自动发现应用上下文 中所创建的bean。
自动装配(autowiring):Spring自动满足bean之间的依赖。

通过几个注解实现:
@Component
@ComponentScan
@Autowired

如果没有其他配置的话,@ComponentScan默认会扫描与配置类相 同的包。

组件扫描的bean命名:
默认类名的第一个字母变为小写。
或者传给@Component(“xxx”)这种显示指定

还有另外一种为bean命名的方式,这种方式不使用@Component注 解,而是使用Java依赖注入规范(Java Dependency Injection)中所提 供的@Named注解来为bean设置ID

Spring支持将@Named作为@Component注解的替代方案。两者之间 有一些细微的差异,但是在大多数场景中,它们是可以互相替换的

设置组件扫描的基础包
我们没有为@ComponentScan设置任何属性。这意味 着,按照默认规则,它会以配置类所在的包作为基础包(base package)来扫描组件。
需要做的就是在@ComponentScan的value属性中指明包的名称:
@ComponentScan(“xxx”)

更加清晰地表明你所设置的是基础包,basePackages属性进行配置:
basePackages属性使用的是复数形式。设置多个基础包,需要将basePackages属性设置为要扫描包的一个数组即可:

@Autowired(required=false)将required属性设置为false时,Spring会尝试执行自动装配,但 是如果没有匹配的bean的话,Spring将会让这个bean处于未装配的状态。

@Inject注解来源于Java依赖注入规范,该规范同时还为我们定义了 @Named注解。在自动装配中,Spring同时支持@Inject和 @Autowired。尽管@Inject和@Autowired之间有着一些细微的 差别,但是在大多数场景下,它们都是可以互相替换的

显示装配
当使用第三方的组件时候, 无法在其类上标注自动扫描的注解, 就需要使用显示装配

有两种可选方案:Java和XML

JavaConfig配置
创建JavaConfig类的关键在于为其添加@Configuration注 解,@Configuration注解表明这个类是一个配置类,该类应该包 含在Spring应用上下文中如何创建bean的细节

需要编写一个方法给这个方法添加@Bean注解

@Bean注解会告诉Spring这个方法将会返回一个对象
默认情况下,bean的ID与带有@Bean注解的方法名是一样的。。如果你想为其设置成一个不同 的名字的话可以通过name属性指定
@Bean(name=”xxx”) , 方法内部包含逻辑, 所以可以根据逻辑生成具体的bean

借助JavaConfig实现注入
在JavaConfig中装配bean的最简单方式就是引用创建bean的方法。
在调用方法注入时候因此方法上添加了@Bean注解, Spring将会拦截所有对它的调用,并确保直接返回该方法所创建的 bean,而不是每次都对其进行实际的调用

另一种方法就是将注入的bean作为当前方法的参数传入,spring会自动装配 一个相应的参数到配置方法之中。需要确保spring容器中存在.方法体就可以按照合适 的方式来使用它。好处是不会要求将bean都声明到同一个配置类之中。或者可以在任意地方声明, 包括xml中, 这里使用的构造器实现了DI 功能,但是我们完全可以采用其他风格的DI配置。比如通过Setter方法, 在方法逻辑内部注入

2.4 通过XML装配bean
先要配置好xml规范,
声明bean

构造器注入元素, 引用另一个bean的id, 注意参数顺序与构造器参数顺序需要一至
使用Spring 3.0所引入的c-命名空间, 一种简写, 不推荐
装配字面量
装配集合使用子标签, 或者依据情况而定

注入属性

注入字面量的方式同constructor

util-命名空间所提供的功能之一就是util:list元素, 将list提成一个bean, 然后引用

2.5 导入和混合配置
导入是针对配置类之间的, 如果一个配置类用到了别的配置类,而进行导入
使用@Import注解导入配置类
@ImportResource注解用于引入在xml中的配置, 指定一个xml文件后, 会再当前配置类中拥有xml中的bean
Xml引入javaconfig, 使用import属性
等等一些杂乱的配置
第3章 高级装配
本章内容:
Spring profile
条件化的bean声明
自动装配与歧义性
bean的作用域
Spring表达式语言

3.1 环境与profile
在Java配置中,可以使用@Profile注解指定某个bean属于哪一个 profile

@Profile注解应用在了类级别上。
方法级别上使用@Profile注解,与@Bean注解一同使用。这样的话,就能将这两个bean的声明放到同 一个配置类之中

在XML中配置profile
我们也可以通过元素的profile属性,在XML中配置 profile bean

激活profile
Spring在确定哪个profile处于激活状态时,需要依赖两个独立的属 性:
spring.profiles.active和 spring.profiles.default。
如果设置了 spring.profiles.active属性的话,那么它的值就会用来确定 哪个profile是激活的。但如果没有设置spring.profiles.active属性的话,
那Spring将会查找spring.profiles.default的值。
如果spring.profiles.active和spring.profiles.default 均没有设置的话,
那就没有激活的profile,因此只会创建那些没有定 义在profile中的bean。

条件化的bean
@Conditional注解, 需要使用时传入一个class
它可以用到带有@Bean注解的方 法上。如果给定的条件计算结果为true,
就会创建这个bean,否则 的话,这个bean会被忽略。
设置给@Conditional的类可以是任意实现了Condition接口的类 型。提供 matches()方法的实现即可。如果matches()方法返回true,那 么就会创建带有@Conditional注解的bean。如果matches()方法 返回false,将不会创建这些bean。方法的两个参数重要

处理自动装配的歧义性
例子:
为了阐述自动装配的歧义性,假设我们使用@Autowired注解标注了 setDessert()方法:
Dessert是一个接口,并且有三个类实现了这个接口, 分别为Cake、Cookies和IceCream:
因为这三个实现均使用了@Component注解,在组件扫描的时候,能 够发现它们并将其创建为Spring应用上下文里面的bean, 就都可以注入, 则出现歧义

Spring提供了多种可选方案来解决 这样的问题。你可以将可选bean中的某一个设为首选(primary)的 bean,或者使用限定符(qualifier)来帮助Spring将可选的bean的范围 缩小到只有一个bean。

标注首选
@Primary能够与@Component组合用在组件 扫描的bean上,也可以与@Bean组合用在Java配置的bean声明中。
Xml。 元素有一个primary属性用来指定首选的bean

限定符
@Qualifier注解是使用限定符的主要方式。它可以与@Autowired 和@Inject协同使用,在注入的时候指定想要注入进去的是哪个 bean。
为@Qualifier注解所设置的参数 就是想要注入的bean的ID
面对相同的一级id时, 可以取二级id

3.4 bean的作用域
Spring定义了多种作用域,可以基于这些作用域创建bean,包括:
单例(Singleton):在整个应用中,只创建bean的一个实例。
原型(Prototype):每次注入或者通过Spring应用上下文获取的 时候,都会创建一个新的bean实例。
会话(Session):在Web应用中,为每个会话创建一个bean实 例。
请求(Rquest):在Web应用中,为每个请求创建一个bean实 例。

如果你使用组件扫描来发现和声明bean,那么你可以在bean的 类上使用@Scope注解,将其声明为原型bean, 使用@Scope注解标注作用域

用@Scope和@Bean来指定所需的作用域:

以使用元素的 scope属性来设置作用域:

会话和请求的作用域相对较为复杂, 但是不怎么使用

3.5 运行时值注入
解决硬编码的问题

Spring提 供了两种在运行时求值的方式:
属性占位符(Property placeholder)。
Spring表达式语言(SpEL)

注入外部的值
注入在配置文件中配置好的属性
在Spring中,处理外部值的最简单方式就是声明属性源并通过Spring 的Environment来检索属性。
使用@PropertySource注解和Environment
这个属性文件会加载到Spring的Environment中,稍后可以从这里 检索属性。
通过Environment对象的getProperty来获取配置参数, 并且方法有重载
Environment还提供了一些方法来检查 哪些profile处于激活状态

Spring一直支持将属性定义到外部的属性的文件中,并使用占位符值 将其插入到Spring bean中。在Spring装配中,占位符的形式为使用“${ … }”包装的属性名称。

为了使用占位符,我们必须要配置一 个PropertyPlaceholderConfigurer bean 或PropertySourcesPlaceholderConfigurer bean

3.5.2 使用Spring表达式语言进行装配
SpEL拥有很多特性,包括:
使用bean的ID来引用bean;
调用方法和访问对象的属性;
对值进行算术、关系和逻辑运算;
正则表达式匹配;
集合操作。

需要了解的第一件事情就是SpEL表达式要放到“#{ … }”之中,
这 与属性占位符有些类似,属性占位符需要放到“${ … }”之中。

表示字面值: #{xx} 直接填入

引用bean、属性和方法
#{xx.xx}

除了引用bean的属性,我们还可以调用bean上的方法
#{xx.xx.sp()}

在表达式中使用类型
要依赖T()这个关 键的运算符
这里所示的T()运算符的结果会是一个Class对象,代表了 java.lang.Math
可以调用T()运算符所得到类型的静态方法。

SpEL运算符
集合, 正则等多个
第4章 面向切面的Spring
本章内容:
面向切面编程的基本原理
通过POJO创建切面
使用@AspectJ注解
为AspectJ切面注入依赖

AOP术语
通知(advice) 要执行的方法
Spring切面可以应用5种类型的通知:
前置通知(Before):在目标方法被调用之前调用通知功能;
后置通知(After):在目标方法完成之后调用通知,此时不会关 心方法的输出是什么;
返回通知(After-returning):在目标方法成功执行之后调用通 知;
异常通知(After-throwing):在目标方法抛出异常后调用通知;
环绕通知(Around):通知包裹了被通知的方法,在被通知的方 法调用之前和调用之后执行自定义的行为。

切点(pointcut)在那些地方的前后调用增强
连接点(join point)。应用的时机
切面(Aspect)代表一个整体的切入逻辑
引入(Introduction)让现有对象具有新的方法, 无需修改现有类
织入(Weaving)
织入是把切面应用到目标对象并创建新的代理对象的过程。
切面在指 定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点 可以进行织入:
编译期:切面在目标类编译时被织入。这种方式需要特殊的编译 器。AspectJ的织入编译器就是以这种方式织入切面的。
类加载期:切面在目标类加载到JVM时被织入。这种方式需要特 殊的类加载器(ClassLoader),它可以在目标类被引入应用 之前增强该目标类的字节码。AspectJ 5的加载时织入(load-time weaving,LTW)就支持以这种方式织入切面。
运行期:切面在应用运行的某个时刻被织入。一般情况下,在织 入切面时,AOP容器会为目标对象动态地创建一个代理对象。 Spring AOP就是以这种方式织入切面的。

4.1.2 Spring对AOP的支持
并不是所有的AOP框架都是相同的,它们在连接点模型上可能有强弱 之分。有些允许在字段修饰符级别应用通知,而另一些只支持与方法 调用相关的连接点。它们织入切面的方式和时机也有所不同

Spring提供了4种类型的AOP支持:
基于代理的经典Spring AOP;
纯POJO切面;
@AspectJ注解驱动的切面;
注入式AspectJ切面(适用于Spring各版本)。

如果你的AOP需求超过了简单的方法调用(如构造器或属性拦截), 那么你需要考虑使用AspectJ来实现切面。在这种情况下,上文所示 的第四种类型能够帮助你将值注入到AspectJ驱动的切面中。

Spring只支持方法级别的连接点
正如前面所探讨过的,通过使用各种AOP方案可以支持多种连接点模 型。因为Spring基于动态代理,所以Spring只支持方法连接点。这与 一些其他的AOP框架是不同的,例如AspectJ和JBoss,除了方法切 点,它们还提供了字段和构造器接入点。Spring缺少对字段连接点的 支持,无法让我们创建细粒度的通知,例如拦截对象字段的修改。而 且它不支持构造器连接点,我们就无法在bean创建时应用通知。
但是方法拦截可以满足绝大部分的需求。如果需要方法拦截之外的连 接点拦截功能,那么我们可以利用Aspect来补充Spring AOP的功能。

Spring借助AspectJ的切点表达式语言来定义Spring切面
AspectJ指示器 描述
arg() 限制连接点匹配参数为指定类型的执行方法
@args() 限制连接点匹配参数由指定注解标注的执行方法
execution() 用于匹配是连接点的执行方法
this() 限制连接点匹配AOP代理的bean引用为指定类型的类
target 限制连接点匹配目标对象为指定类型的类
@target() 限制连接点匹配特定的执行对象,这些对象对应的类要具有指定类 型的注解
within() 限制连接点匹配指定的类型
@within() 限制连接点匹配指定注解所标注的类型(当使用Spring AOP时,方 法定义在由指定的注解所标注的类里)
@annotation 限定匹配带有指定注解的连接点

使用execution()指示器中配合上述指示器完成复杂的切点逻辑

Spring还引入了一个新的bean()指示 器,它允许我们在切点表达式中使用bean的ID来标识bean, 。bean() 使用bean ID或bean名称作为参数来限制切点只匹配特定的bean。
 
Spring使用AspectJ注解来声明通知方法
注  解 通  知
@After 通知方法会在目标方法返回或抛出异常后调用
@AfterReturning 通知方法会在目标方法返回后调用
@AfterThrowing 通知方法会在目标方法抛出异常后调用
@Around 通知方法会将目标方法封装起来, 通过try等等代码代替其他所有注解
@Before 通知方法会在目标方法调用之前执行

@Pointcut注解。 为@Pointcut注解设置的值是一个切点表达式,

@AspectJ标注了切面的类像其他的Java类一样,它可以装配为Spring中的bean

在配置类的类级别上通过使 用@EnableAspectJAutoProxy注解启用自动代理功能

在切面的方法中可以传入参数, 需要在切点声明, 然后传入通知中,

方法包装仅仅是切面所能实现的功能之一。
让我们看 一下如何通过编写切面,为被通知的对象引入全新的功能。

4.3.4 通过注解引入新功能
如果切面能够为现有的方法增加额外的功能,为什 么不能为一个对象增加新的方法呢?实际上,利用被称为引入的AOP 概念,切面可以为Spring bean添加新方法

通过@DeclareParents注解
@DeclareParents注解由三部分组成:
value属性指定了哪种类型的bean要引入该接口。在本例中,也 就是所有实现Performance的类型。(标记符后面的加号表示 是Performance的所有子类型,而不是Performance本 身。)
defaultImpl属性指定了为引入功能提供实现的类。在这里, 我们指定的是DefaultEncoreable提供实现。
@DeclareParents注解所标注的静态属性指明了要引入了接 口。在这里,我们所引入的是Encoreable接口。

4.4 在XML中声明切面
没有源码时候, xml可以做到对现有代码没有任何侵入, 对于上述的功能都可以配置在xml中

4.5 注入AspectJ切面
虽然Spring AOP能够满足许多应用的切面需求,但是与AspectJ相比, Spring AOP 是一个功能比较弱的AOP解决方案。AspectJ提供了Spring AOP所不能支持的许多类型的切点。
如: 构造器切点

更好的方式是,我们可以借助Spring的依 赖注入把bean装配进AspectJ切面中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值