Spring in Action.4th
-
Spring的两个核心:依赖注入(dependency injection,DI)和面向切面编程(aspect-oriented programming,AOP)
-
为了降低Java开发的复杂性,Spring采取了以下4种关键策略:
- 基于POJO的轻量级和最小侵入性编程;
- 通过依赖注入和面向接口实现松耦合;
- 基于切面和惯例进行声明式编程;
- 通过切面和模板减少样板式代码。
-
耦合性具有两面性:一方面,紧密耦合的代码难以测试、难以复用、难以理解;另一方面,一定程度的耦合又是必须的,完全没有耦合的代码什么也做不了。
-
通过DI,对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定。对象无需自行创建或管理它们的依赖关系。→松耦合
-
Spring通过应用上下文(Application Context)装载bean的定义并把它们组装起来。
-
DI能够让相互协作的软件组件保持松散耦合,而面向切面编程允许你把遍布应用各处的功能分离出来形成可重用的组件。
-
AOP能够使这些服务(日志、安全、事务...)模块化,并以声明的方式将它们应用到它们需要影响的组件中去。把横切关注点和与核心业务逻辑相分离。
-
在基于Spring的应用中,你的应用对象生存于Spring容器中,Spring容器负责创建对象,装配它们,配置它们并管理它们的整个生命周期。
-
Spring自带的容器实现可归为两种不同的类型:①bean工厂;②应用上下文(用的最多)。
-
应用上下文:
- AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文。
- AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载Spring Web应用上下文。
- ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。
- FileSystemXmlApplicationContext:从文件系统下的一个或多个XML配置文件中加载上下文定义。
- XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下文定义。
ApplicationContext context = new ClassPathXmlApplicationContext('xxx.xml');
-
bean的生命周期:
- Spring对bean进行实例化;
- Spring将值和bean的引用注入到bean对应的属性中;
- 如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBeanName()方法;
- 如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;
- 如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessBeforeInitialization()方法;
- 如果bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet()方法。类似地,如果bean使用init-method声明了初始化方法,该方法也会被调用;
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessAfterInitialization()方法;
- 此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
- 如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用了destroy-method声明了销毁方法,该方法也会被调用。
-
Spring提供三种主要的装配机制,可以互相搭配:
- 在XML中进行显式配置;
- 在Java中进行显示配置;
- 隐式的bean发现机制和自动装配。
-
Spring从两个角度来实现自动化装配:
- 组件扫描:Spring会自动发现应用上下文中所创建的bean。
// CD接口 public interface CompactDisc { void play(); } // CD的实现类 @Component("id名,不写就是类名的第一个字母变小写") public class SgtPeppers implements CompactDisc { private String title = "Sgt. Pepper's Lonely Hearts Club Band"; private String artist = "The Beatles"; public void play() { System.out.println("Playing " + title + " by " + artist; } } // XML配置 <context:component-scan base-package="基础包名" />
- 自动装配:Spring自动满足bean之间的依赖。
// 播放器的实现类 @Component public class CDPlayer implements MediaPlayer { private CompactDisc cd; @Autowired // 可以用在任何方法上。用在构造器上,则是构造器注入;用在setter上,则是属性注入。 public CDPlayer(CompactDisc cd) { this.cd = cd; } public void play() { cd.play(); } }
-
通过XML装配bean
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context"> <bean id="compactDisc" class="com.duan.SgtPeppers" /> <!-- 调用默认构造器 --> <bean id="cdPlayer" class="com.duan.CDPlayer"> <!-- 构造器注入 --> <constructor-arg ref="compactDisc" /> <!-- 注入引用 --> <constructor-arg value="字面量值" /> <!-- 注入字面量值 --> <constructor-arg><null/></constructor-arg> <!-- 注入null值 --> <constructor-arg> <!-- 注入集合:list或set用来装配List、Set和数组 --> <list> <value>值1</value> <ref bean="bean的id" /> </list> </constructor-arg> <!-- 属性注入 --> <property name="属性名" ref="bean的id" /> <property name="属性名" value="字面量值" /> </bean> <!-- 使用c和p命名空间,要在顶部声明其模式 --> <bean id="cdPlayer" class="com.duan.CDPlayer" c:cd-ref="compactDisc" p:cd-ref="compactDisc /> <!-- 注入字面量:c:参数名="字面量值",p:属性名="字面量值" --> </beans>