Spring的基本概念
Spring 框架本身没有强制使用任何特别的编程模式。从设计上看,Spring有很大自由度,像个容器,可以整合其它许多框架组件。Spring的核心功能DI/IOC,AOP,适用于任何JAVA应用。学习当中的设计思想,对Java编程会有帮助。
1. Spring优势
Spring的优势主要有6点:
- 有效组织中间层对象。能有效整合现有框架如Struts2,Hibernate,Mybatis,Shiro,Lucene等等。
- 实现了真正的AOP面向接口编程,组件之间高度解耦(decouple),AOP是一种良好的编程习惯。
- Spring秉承的设计思想,是让使用Spring创建的应用,都可能少地依赖Spring自己的API。Spring应用中的大多数业务对象,不依赖于Spring
- 易于单元测试
- 提高代码重用性,尽可能避免硬编码。Spring能将应用中的某些代码抽象出来,在其它程序中使用。
- 为数据存取提供一个一致框架,简化数据库底层访问方式
2. Spring框架模块
2.1 核心容器 (Core Container)
先看看官方文档怎么说。
The Core Container consists of the
spring-core
,spring-beans
,spring-context
,spring-context-support
, andspring-expression
(Spring Expression Language) modules.
5个核心jar包,或模块。
spring-core
和spring-beans
模块提供Spring框架核心容器的基础,包括控制反转和依赖注入,其中的BeanFactory
实现了工厂模式。
spring-context
模块建立在Core和Beans模块之上,它扩展(extends/inherit)了Beans模块,添加了国际化支持,事件传播(Event Propagation),资源加载、上下文信息(如Servlet容器),此外,还支持Java EE的EJB、JMX,远程访问。ApplicationContext
是该模块的重点。
spring-context-support
为常见的第三方类库集成到Spring提供了支持,如缓存(EhCache, Guava, JCache),mailing(JavaMail),scheduling(CommonJ,Quartz),模板(FreeMarker,JasperReports,Velocity).
spring-expression
模块提供强大的Expression Language,用于运行时查询或操作对象,该模块扩展了EL表达式
2.2 AOP和Instrumentation
spring-aop
模块提供了一个符合AOP联盟标准的面向切面编程的实现。这里可以定义拦截器和切点,
spring-aspects
提供AspectJ的集成支持
spring-instrument
模块提供class instrumentation support和类加载器实现。spring-instrument-tomcat
包含针对Tomcat 的instrumentation agent
2.3 Message
Spring4包含spring-messaging
模块,里面包含Message, MessageChannel, MessageHandler等核心抽象类,该模块一系列用于将消息映射到方法的注解,类似Spring MVC
2.4 Data Access/Integration
包括JDBC, ORM, OXM, JMS, 和 Transaction模块
spring-jdbc
提供JDBC抽象层
spring-tx
为类提供编程和声明式事务(programmatic and declarative transaction)管理,这些类需实现特定接口,对所有POJO适用.
spring-orm
模块提供了主流的对象关系映射(object-relational mapping)API,包括 JPA, JDO, and Hibernate
spring-oxm
模块提供了支持Object/XML mapping实现的抽象层,如JAXB, Castor, XMLBeans, JiBX and XStream
spring-jms
包含生成和消费消息的特性,java messaging service
2.5 Web
Web层包含
spring-web, spring-webmvc, spring-websocket, and spring-webmvc-portlet
spring-web
提供基础的web集成,如文件上传,使用servlet监听器初始化IoC容器,web上下文,当中还有HTTP client和Spring远程支持的web部分
spring-webmvc
,又叫Web-Servlet module
,包含 model-view-controller (MVC) ,REST Web Services实现。Spring MVC和其他Spring模块一起,将后端模型代码与Web形式表现清晰分离
spring-webmvc-portlet
,又叫Web-Portlet module
,提供了在Portlet环境下的MVC实现,与Spring MVC的功能一样
Spring middle-tier using a third-party web framework
Typical full-fledged Spring web application
3. Spring的核心
- 依赖注入(DI)
- 控制反转(IOC)
- 面向切面编程(AOP)
一个Java实例(调用者)需要调用另外一个Java实例(被调用者),调用者需要实现这个调用过程,通常是”new 构造方法”,但这样耦合度很高。当这个调用过程的责任(代码),或者控制权,交出去,交给容器来实现,这就是控制反转;从容器角度看,就是容器向调用者注入它想要调用的那个实例,这就是依赖注入。背后,其实是用了反射机制、动态代理
一句话,你需要的实例,“你不用来找我,我会去找你”。对象的依赖关系由容器管理,实现了对象的解耦
4. SpringIOC容器
SpringIoC容器是一个提供IoC支持的轻量级容器。Spring提供了两种容器:BeanFactory和ApplicationContext。此外,Spring提供了这两个类的几种实现类,它们也都称为Spring的容器。
4.1 BeanFactory
org.springframework.beans.factory.BeanFactory接口定义,属于基础类型的IOC容器。该接口定义了IOC容器的功能规范,下面的源码不是最新的4.2.6的
public interface BeanFactory {
//标志返回工厂,而非实例
String FACTORY_BEAN_PREFIX = "&";
//返回xml文件中,id为name的bean
Object getBean(String name) throws BeansException;
//返回xml文件中,id为name,类型为requiredType的bean
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
//返回xml文件中,类型为requiredType的bean
<T> T getBean(Class<T> requiredType) throws BeansException;
//返回xml文件中,id为name,可变参数args
Object getBean(String name, Object... args) throws BeansException;
//xml文件中是否存在id为name的bean
boolean containsBean(String name);
//作用域,xml文件中scope属性;是否单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//是否原型模式,每调用一次,创建一个新实例
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//名称为name的类与目标类targetType是否匹配
boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
//返回别名
String[] getAliases(String name);
}
BeanFactory负责初始化各种Bean,并调用其生命周期方法。
Spring提供了BeanFactory的许多实现方法,常用的是XmlBeanFactory
,3.1版本后,推荐使用 DefaultListableBeanFactory
和 XmlBeanDefinitionReader
,根据XML配置文件的定义来装配bean
4.2 ApplicationContext
org.springframework.context.ApplicationContext
定义接口,以BeanFactory为基础构建,继承了ListableBeanFactory, HierarchicalBeanFactory
两个BeanFactory的子类。
与BeanFactory相比,ApplicationContext出了创建、管理、配置bean外,还提供附加功能,如国际化。
此外,ApplicationContext初始化後,容器中的所有singleton Bean也都被实例化了。所以,大部分系统都选择用ApplicationContext**,只在系统资源少的情况下,考虑使用BeanFactory**
ApplicationContext的常用实现类有
- AnnotationConfigApplicationContext
- ClassPathXmlApplicationContext
- FileSystemXmlApplicationContext
- XmlWebApplicationContext
第一个显然是注解解析用,后面几个则根据xml配置文件解析了。
5. 依赖注入的3种实现方式
5.1.设置注入,setter方法
Service实现层,需要实例化的对象,设置setter方法,关键是set方法,将xml文件里读取的内容,转换成相应实例,再透过set方法注入调用的类
applicationContext.xml文件,注册bean,设置
优点:
- 直观自然灵活
- 若依赖关系复杂,构造方法注入则显得臃肿,setter则更为简洁
缺点:
- 尽管灵活,但容易破坏类的状态和行为。因此需要知道哪些组合是有效的,哪些是无效的,顺序也要注意。
5.2.构造方法注入
构造方法里传入需要注入的类
applicationContext.xml文件,注册bean,设置
优点:
- 符合设计原则,“构造期间即创建一个完整、合法的对象”
- 避免繁琐的setter方法,所有依赖关系集中在构造方法,更加易读
- 关联关系仅在构造方法中表达,只有组件创建者,需要关心组件内部的依赖关系。 依赖关系对调用者透明。对上层屏蔽不必要的信息,系统层次清晰。
缺点
- 构造方法出现的错误有时,难以排除
- 继承中,构造方法不会自动继承,需手动
- 如果应对的是可选属性,循环依赖关系,构造方法注入就有点力不从心了
5.3.接口注入
接口注入需要类,实现特定的接口或继承特定的类,如此一来,依赖关系没有多大改善,是侵入性的,基本被遗弃了。Avalon,EJB容器属于这类。Spring不支持这种类型的注入。
平常开发时,setter为主,构造方法为辅,便可以达到很好的效率。如今还有注解Autowired,那就更简便了。