一、简化Java开发
Spring为了降低Java开发的复杂性,采用了以下四种策略
-
基于POJO的轻量级和最小侵入性编程;
-
通过依赖注入和面向接口实现松耦合;
-
基于切面和惯例进行声明式编程;
-
通过切面和模板减少样板式代码。
下面简单介绍一下这四种策略分别是什么:
Spring竭力避免因自身的API而弄乱你的应用代码。Spring不会强迫你实现Spring规范的接口或继承Spring规范的类,相反,在基于Spring构建的应用中,它的类通常没有任何痕迹表明你使用了Spring。最坏的场景是,一个类或许会使用Spring注解,但它依旧是POJO
2、依赖注入:
任何一个有实际意义的应用(肯定比Hello World示例更复杂)都会由两个或者更多的类组成,这些类相互之间进行协作来完成特定的业务逻辑。按照传统的做法,每个对象负责管理与自己相互协作的对象(即它所依赖的对象)的引用,这将会导致高度耦合和难以测试的代码。通过DI,对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定。对象无需自行创建或管理它们的依赖关系依赖关系将被自动注入到需要它们的对象当中去。
3、面向切面:
DI能够让相互协作的软件组件保持松散耦合,而面向切面编程(aspect-oriented programming,AOP)允许你把遍布应用各处的功能分离出来形成可重用的组件。面向切面编程往往被定义为促使软件系统实现关注点的分离一项技术。系统由许多不同的组件组成,每一个组件各负责一块特定功能。除了实现自身核心的功能之外,这些组件还经常承担着额外的职责。诸如日志、事务管理和安全这样的系统服务经常融入到自身具有核心业务逻辑的组件中去,这些系统服务通常被称为横切关注点,因为它们会跨越系统的多个组件。
4、使用模板消除样板式代码:
有过java开发经验的同学应该都知道在使用JDBC操作数据库时的步骤有多繁琐,下面我来看一下JDBC操作数据库的代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Demo {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/person";
String user = "root";
String pwd = "admin";
String sql = "select * from student";
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url,user,pwd);
st = conn.createStatement();
//执行查询语句,另外也可以用execute(),代表执行任何SQL语句
rs = st.executeQuery(sql);
while(rs.next()) {
System.out.println(rs.getObject(1) + " " +
rs.getObject(2) + " " + rs.getInt("birth"));
}
//分别捕获异常
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//判断资源是否存在
if(rs != null) {
rs.close();
//显示的设置为空,提示gc回收
rs = null;
}
if(st != null) {
st.close();
st = null;
}
if(conn != null) {
conn.close();
conn = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
估计很少有读者能将这段代码一行一行的看完,因为实在是太长了。
JDBC不是产生样板式代码的唯一场景。在许多编程场景中往往都会导致类似的样板式代码,JMS、JNDI和使用REST服务通常也涉及大量的重复代码。Spring旨在通过模板封装来消除样板式代码。Spring的JdbcTemplate使得执行数据库操作时,避免传统的JDBC样板代码成为了可能。
二、容纳Bean
在基于Spring的应用中,你的应用对象生存于Spring容器(container)中。如下图所示,Spring容器负责创建对象,装配它们,配置它们并管理它们的整个生命周期,从生存到死亡(在这里,可能就是new到finalize())。
Spring容器是Spring的核心,Spring自带了多个容器实现,可以归为两种不同的类型。bean工厂(由org.springframework.beans.factory.eanFactory接口定义)是最简单的容器,提供基本的DI支持。应用上下文(由org.springframework.context.ApplicationContext接口定义)基于BeanFactory构建,并提供应用框架级别的服务,例如从属性文件解析文本信息以及发布应用事件给感兴趣的事件监听者。通常我们使用的是应用上下文,因为bean工厂对大多数开发者来说功能比较薄弱。
1、使用应用上下文:
Spring自带了多种类型的应用上下文
- AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文。
- AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载Spring Web应用上下文。
- ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。
- FileSystemXmlapplicationcontext:从文件系统下的一个或多个XML配置文件中加载上下文定义。
- XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下文定义
2、bean的生命周期:
在传统的Java应用中,bean的生命周期很简单。使用Java关键字new进行bean实例化,然后该bean就可以使用了。一旦该bean不再被使用,则由Java自动进行垃圾回收。相比之下,Spring容器中的bean的生命周期就显得相对复杂多了
1、Spring对bean进行实例化;
2、Spring将值和bean的引用注入到bean对应的属性中;
3、如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法;
4、如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;
5、如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
6、如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization()方法;
7、如果bean实现了InitializingBean接口,Spring将调用它们的after-PropertiesSet()方法。类似地,如果bean使用init-method声明了初始化方法,该方法也会被调用;
8、如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization()方法;
9、此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
10、如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用
3、Spring的核心模块:
我们来逐一分析一下Sping的各个组成模块
Spring核心容器
容器是Spring框架最核心的部分,它管理着Spring应用中bean的创建、配置和管理。在该模块中,包括了Spring bean工厂,它为Spring提供了DI的功能。基于bean工厂,我们还会发现有多种Spring应用上下文的实现,每一种都提供了配置Spring的不同方式。
除了bean工厂和应用上下文,该模块也提供了许多企业服务,例如E-mail、JNDI访问、EJB集成和调度。所有的Spring模块都构建于核心容器之上。当你配置应用时,其实你隐式地使用了这些类。
Spring的AOP模块
在AOP模块中,Spring对面向切面编程提供了丰富的支持。这个模块是Spring应用系统中开发切面的基础。与DI一样,AOP可以帮助应用对象解耦。借助于AOP,可以将遍布系统的关注点(例如事务和安全)从它们所应用的对象中解耦出来。
数据访问和集成
使用JDBC编写代码通常会导致大量的样板式代码,例如获得数据库连接、创建语句、处理结果集到最后关闭数据库连接。Spring的JDBC和DAO(Data Access Object)模块抽象了这些样板式代码,使我们的数据库代码变得简单明了,还可以避免因为关闭数据库资源失败而引发的问题。该模块在多种数据库服务的错误信息之上构建了一个语义丰富的异常层,以后我们再也不需要解释那些隐晦专有的SQL错误信息了!
Web与远程调用
MVC(Model-View-Controller)模式是一种普遍被接受的构建Web应用的方法,它可以帮助用户将界面逻辑与应用逻辑分离。Java从来不缺少MVC框架,Apache的Struts、JSF、WebWork和Tapestry都是可选的最流行的MVC框架。
Spring装配bean
一、Spring装配的三种方式
1、在XML中进行显示配置
2、在Java中进行显示配置
3、隐式的bean的发现机制和自动装配
至于哪一种装配方式好,这里没有统一的答案,读者可以选择适合自己的方案进行bean的装配
二、自动化装配bean
1、Spring 从两个角度来实现自动化装配bean :
- 组件扫描:Spring会自动发现应用上下文中所创建的bean
- 自动装配:Spring自动满足bean之间的依赖
2、创建可被发现的bean:
接下来我将用一个CD播放器案例来说明整个自动化装配bean的过程,该项目是一个Maven项目,进行实验前需要引入相关Maven配置文件,对Maven还不了解的同学建议去学习相关资料,这里不再赘述
第一步:创建CompactDisc接口,接口中包含了一个play()方法
package soundsystem;
public interface CompactDisc {
void play();
}
CompactDisc的具体内容并不重要,重要的是你将其定义为一个接口。作为接口,它定义了CD播放器对一盘CD所能进行的操作。它将CD播放器的任意实现与CD本身的耦合降低到了最小的程度。
第二步:我们还需要一个CompactDisc的实现,SgtPeppers实现了CompactDisc接口
package soundsystem;
import org.springframework.stereotype.Component;
@Component //该类是一个组件类
public class SgtPeppers implements CompactDisc {
private String title = "曾经的你";
private String artist = "许巍";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
和CompactDisc接口一样,Sgtpeppers的具体内容并不重要。你需要注意的就是SgtPeppers类上使用了@Component注解。这个简单的注解表明该类会作为组件类,并告知Spring要为这个类创建bean。没有必要显式配置Sgtpeppers bean,因为这个类使用了@Component注解,所以Spring会为你把事情处理妥当。
第三步: