Spring实战(1):基础、配置和注入

第一章

基础

降低Java开发的复杂性,Spring采取的策略:

  • 基于POJO的轻量级和最小侵入性编程
  • 通过依赖注入和面向接口实现松耦合
  • 基于切面和惯例进行声明式编程
  • 通过切面和模板减少样板式代码

耦合具有两面性:

  1. 紧密的耦合代码难以测试、难以复用、难以理解,并且典型地表兄出“打地鼠”式的bug特性
  2. 一定程度的耦合又是必须的——完全没有耦合的代码什么也做不了

DI

Spring通过Application Context装载bean的定义并把它们组装起来。Spring应用上下文全权负责对象的创建和组装。

AOP

AOP往往被定义为促使软件系统实现关注点的分离的一项技术。AOP能够使这些服务区模块化,并以声明 的方式将他们的应用到他们需要影响的组件中去。所造成的结果就是这些组件会具有更高的内聚性并且会更加关注自身的业务,完全不需要了解涉及系统服务所带来的复杂性。

<aop:aspect>元素引用该bean,前置调用为<aop:before>,后置调用为<aop:after>

Spring容器

spring自带多个容器的实现,可以分为两种不同的类型bean工厂(由org.springframework. beans. factory.eanFactory接口定义)是最简单的容器,提供基本的DI支持。应用上下文 (由org.springframework.context.ApplicationContext接口定义)基于BeanFactory构建,并提供应用框架级别的服务

Spring自带了多种类型的应用上下文。下面罗列的几个是你最有可能

  • AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文。
  • AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载Spring Web应用上下文。
  • ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。
  • FileSystemXmlapplicationcontext:从文件系统下的一个或多个XML配置文件中加载上下文定义。
  • XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下文定义。

Spring Bean的生命周期:

Spring生命周期

Spring模块

第二章

Spring提供了三种主要的装配机制:

  • 在XML中进行显式配置。
  • 在Java中进行显式配置。
  • 隐式的bean发现机制和自动装配

自动化配置

Spring从两个角度来实现自动化装配:

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

使用了@Component注解。这个简单的注解表明该类会作为组件类,并告知Spring要为这个类创建bean

@ComponentScan注解启用了组件扫描,这个注解能够在Spring中启用组件扫描,默认会扫描与配置类相同的包

使用XML来启用组件扫描的话,那么可以使用Spring context命名空间的<context:component-scan>元素

Spring应用上下文中所有的bean都会给定一个ID,Spring会根据类名为其指定一个ID。具体来讲就是将类名的第一个字母变为小写。如果想为这个bean设置不同的ID,你所要做的就是将期望的ID作为值传递给@Component注解。

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

有一个原因会促使我们明确地设置基础包,那就是我们想要将配置类放在单独的包中,使其与其他的应用代码区分开来,为了指定不同的基础包,需要做的就是在@ComponentScan的value属性中指明包的名称.

除了将包设置为简单的String类型之外,@ComponentScan还提供了另外一种方法,那就是将其指定为包中所包含的类或接口

为了声明要进行自动装配,可以借助Spring的@Autowired注解。如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常。为了避免异常的出现,你可以将@Autowired的required属性设置为false

将required属性设置为false时,Spring会尝试执行自动装配,但是如果没有匹配的bean的话,Spring将会让这个bean处于未装配的状态。但是,把required属性设置为false时,你需要谨慎对待。如果在你的代码中没有进null检查的话,这个处于未装配状态的属性有可能会出现NullPointerException

@Autowired是Spring的特有注解,可以替换为@Inject

通过java代码转配bean

JavaConfig是配置代码,这意味着它不应该包含任何业务逻辑,JavaConfig也不应该侵入到业务逻辑代码之中。尽管不是必须的,但通常会将JavaConfig放到单独的包中,使它与其他的应用程序逻辑分离开来,这样对于它的意图就不会产生困惑了。

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

要在JavaConfig中声明bean,我们需要编写一个方法,这个方法会创建所需类型的实例,然后给这个方法添加@Bean注解.默认情况下,bean的ID与带有@Bean注解的方法名是一样的,但是可以使用name属性指定一个不同的名字。

在JavaConfig中装配bean的最简单方式就是引用创建bean的方法。

但是,在软件领域中,我们完全可以将同一个实例注入到任意数量的其他bean之中。默认情况下,Spring中的bean都是单例的。

带有@Bean注解的方法可以采用任何必要的Java功能来产生bean实例

通过XML装配bean

最简单的Spring XML配置:

<?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:c="http://www.springframework.org/schema/c"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  
  <!--其余代码-->
  
</beans>

要在基于XML的Spring配置中声明一个bean,我们要使用spring-beans模式中的另外一个素:<bean><bean>元素类似于JavaConfig中的@Bean注解

作为替代的方案,你也可以使用Spring的c-命名空间。c-命名空间是在Spring 3.0中引入的,它是在XML中更为简洁地描述构造器参数的方式。要使用它的话,必须要在XML的顶部声明其模式

XML不允许某个元素的多个属性具有相同的名字。

<list>元素是<constructor-arg>的子元素,这表明一个包含值的列表将会传递到构造器中。其中,<value>元素用来指定列表中的每个元素。可以使用<ref>元素替代<value>,实现bean引用列表的装配。

Spring为<constructor-arg>元素提供了c-命名空间作为替代方案,与之类似,Spring提供了更加简洁的p-命名空间,作为<property>元素的替代方案

util-命名空间所提供的功能之一就是<util:list>元素,它会创建一个列表的bean。 输入图片说明Spring util-命名空间中的元素

在使用了XML的配置之后,如果要让spring同时加载它和其他基于Java的配置可以使用@ImportResource注解

在XML中,我们可以使用import元素来拆分XML配置

Spring中装配bean的三种主要方式:自动化配置、基于Java的显式配置以及基于XML的显式配置。

第三章

环境与profile

使用EmbeddedDatabaseBuilder会搭建一个嵌入式的Hypersonic数据库,它的模式(schema)定义在schema.sql中,测试数据则是通过test-data.sql加载的。

通过JNDI获取DataSource能够让容器决定该如何创建这个DataSource,甚至包括切换为容器管理的连接池。

Spring引入了bean profile的功能。要使用profile,你首先要将所有不同的bean定义整理到一个或多个profile之中,在将应用部署到每个环境时,要确保对应的profile处于激活(active)的状态。在Java配置中,可以使用@Profile注解指定某个bean属于哪一个profile。

尽管每个DataSource bean都被声明在一个profile中,并且只有当规定的profile激活时,相应的bean才会被创 建,但是可能会有其他的bean并没有声明在一个给定的profile范围内。没有指定profile的bean始终都会被创建,与激活哪个profile没有关系。

我们也可以通过<beans>元素的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。

有多种方式来设置这两个属性:

  • 作为DispatcherServlet的初始化参数;
  • 作为Web应用的上下文参数;
  • 作为JNDI条目;
  • 作为环境变量;
  • 作为JVM的系统属性;
  • 在集成测试类上,使用@ActiveProfiles注解设置。

Spring提供了@ActiveProfiles注解,我们可以使用它来指定运行测试时要激活哪个profile。

条件话Bean

Spring 4引入了一个新的@Conditional注解,它可以用到带有@Bean注解的方法上。如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean会被忽略。

通过ConditionContext,我们可以做到如下几点:

  • 借助getRegistry()返回的BeanDefinitionRegistry检查bean定义; 借助getBeanFactory()返回的

  • ConfigurableListableBeanFactory检查bean是否存在,甚至探查bean的属性;

    借助getEnvironment()返回的Environment检查环境变量是否存在以及它的值是什么;

  • 读取并探查getResourceLoader()返回的ResourceLoader所加载的资源;

  • 借助getClassLoader()返回的ClassLoader加载并检查类是否存在。

从Spring 4开始,@Profile注解进行了重构,使其基于@Conditional和Condition实现

@Profile本身也使用了@Conditional注解,并且引用ProfileCondition作为Condition实现

处理自动装配的歧义性

可以将可选bean中的某一个设为首选(primary)的bean,或者使用限定符(qualifier)来帮助Spring将可选的bean的范围缩小到只有一个bean。

可以将可选bean中的某一个设为首选(primary)的bean,或者使用限定符(qualifier)来帮助Spring将可选的bean的范围缩小到只有一个bean。

@Primary能够与@Component组合用在组件扫描的bean上,也可以与@Bean组合用在Java配置的bean声明中。

设置首选bean的局限性在于@Primary无法将可选方案的范围限定到唯一一个无歧义性的选项中。它只能标示一个优先的可选方案。当首选bean的数量超过一个时,我们并没有其他的方法进一步缩小可选范围。与之相反,Spring的限定符能够在所有可选的bean上进行缩小范围的操作,最终能够达到只有一个bean满足所规定的限制条件。如果将所有的限定符都用上后依然存在歧义性,那么你可以继续使用更多的限定符来缩小选择范围。@Qualifier注解是使用限定符的主要方式。

Java不允许在同一个条目上重复出现相同类型的多个注解

Bean的作用域

在默认情况下,Spring应用上下文中所有bean都是作为以单例(singleton)的形式创建的。

Spring定义了多种作用域,可以基于这些作用域创建bean,包括:

  • 单例(Singleton):在整个应用中,只创建bean的一个实例。
  • 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
  • 会话(Session):在Web应用中,为每个会话创建一个bean实例。
  • 请求(Rquest):在Web应用中,为每个请求创建一个bean实例。

如果你想在Java配置中将Notepad声明为原型bean,那么可以组合使用@Scope和@Bean来指定所需的作用域:

@Bean
@Scope(configurableBeanFactory.SCOPE_PROTOTYPE)

我们将value设置成了WebApplicationContext中的SCOPE_SESSION常量(它的值是session)。这会告诉Spring为Web应用中的每个会话创建一个ShoppingCart。这会创建多个bean的实例,但是对于给定的会话只会创建一个实例,在当前会话相关的操作中,这个bean实际上相当于单例的

@Component
@Scope(value=WebApplicationContext.SCOPE_SESSION,
      proxyMode=ScopedProxyMode.INTERFACES)

@Scope同时还有一个proxyMode属性,它被设置成了ScopedProxyMode.INTERFACES。这个属性解决了将会话或请求作用域的bean注入到单例bean中所遇到的问题

运行时值注入

有时候硬编码是可以的,但有的时候,我们可能会希望避免硬编码值,而是想让这些值在运行时再确定。为了实现这些功能,Spring提供了两种在运行时求值的方式:

  • 属性占位符(Property placeholder)。
  • Spring表达式语言(SpEL)。

转载于:https://my.oschina.net/wjpwroking/blog/801802

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值