Spring Action 笔记(一) 初识Spring
前言
决定写博客,是受了《软技能-代码之外的生存之道》的启发,深知写博客利人利已的好处。
本人之前主要使用的语言并不是java,而是c#,也不是因为想转java而来学习Spring。我认为学习一种框架,不光知道如何使用框架,更重要的是理解框架背后的思想,而这个思想是不受语言限制的。在读了《Spring Action》第一章后,收获很多,也理解了之前一直模糊的一些思想,可以说收获很大,我会坚持这个博客系列,将我所收获的分享出来。下面切入正题。
Spring使命
简化java开发是Spring框架的终极目标,看似简单的几个字,实现起来并不简单,Spring一举颠覆java之前的众多框架,划出一道清新亮丽的风景线。Spring从以下几个方面做了努力使代码更简洁:
- 激发POJO的潜能,不侵入代码。
- 通过依赖注入和面向接口实现松耦合
- 基于切面和惯例进行声明式编程
- 通过切面和模板减少样板式代码
激发POJO的潜能,不侵入代码。
之前很多框架都要求使用者继承框架接口或类,使得开发者需要更多的代码来适配框架。Spring可以让开发者只关注业务本身,POJO(Plain Ordinary Java Object)是一个简单的java类,无需为适配框架来写过多的不需要的代码。之下是两个例子:
程序1:EJB2.1 强迫实现你根本不需要的方法
public class HelloWorldBean implements SessionBean {
public void ejbActivate(){} // 业务无关的代码
public void ejbPassivate(){}
public void ejbRemove(){}
public void setSessionContext(SessionContext ctx){}
public void ejbCreate(){}
public String sayHello() {
return "Hello World";
}
}
程序2:Spring简洁的代码
public class HelloWorldBean {
public String sayHello() {
return "Hello World";
}
}
通过依赖注入和面向接口实现松耦合
要理解理解依赖注入,首先搞清楚面向接口编程和面向实现编程的区别。
下面是一个简单的例子,面向接口编程的汽车类(CarA)依赖的是具有跑(Run)功能的*(IWheel),只要符合接口的任何厂商的*都能装入汽车A,以后想更换*,不需要重新来修改汽车架构。而面向实现编程的汽车B(CarB)依赖特定的*实现(WhellA),若以后出来更先进的*,汽车B也只能相望,除非重新改造自己。所以面向接口编程使得类之间是松耦合的。
程序3:面向接口编程和面向实现编程比较
// 面向接口编程
public class CarA{
Iwheel whell;
public Run(){
whell.Run();
}
}
// 面向实现编程
public class CarB{
WhellA whell;
public Run(){
whell.Run();
}
}
那么依赖注入和面向接口编程是什么关系呢。上例中的汽车A的*从何而来?如果是汽车内部new出来,还是依赖了具体实现类,以后换个*仍然要修改汽车类,下面的例子,汽车A依赖的*由构造函数注入进来,这样把具体使用哪种*交给汽车的装配者,汽车框架的制造者不关心*选用何种,从何而来,只知道*能实现自己想要的Run功能就够了。这样汽车装配者可以根据自己的喜好装出各种汽车(跑车、普通汽车、越野车),所以依赖注入是面向接口编程的一种实现方式。依赖注入除了构造函数注入,还会有其他的注入方式,会在后面的博客中一一解释,这里只需了解依赖注入的思想就够了。
// 面向接口编程
public class Car{
Iwheel whell;
public Car(Iwhell whellA){ // 构造函数依赖注入
this.whell= whellA;
}
public Run(){
whell.Run();
}
}
基于切面和惯例进行声明式编程
依赖注入让相互协作的软件组件保持松散耦合,而AOP编程允许你把遍布应用各处的功能分离出来形成可重用的组件。哪些功能是遍布应用各处的?比如日志功能,权限功能等,这些功能被称为切面功能,因为他们横切各个业务模块。
相信很多人都看到过一个业务模块被淹没在日志、权限控制、事务这些跟业务逻辑无关的代码中的情况,即使这些功能已经很好的封装,但调用代码还是嵌在了业务逻辑代码中。AOP不但很好地将公共功能封装成组件,还使这些公共功能不会嵌在业务逻辑代码中,使得POJO更简单。如何使得切面功能代码不侵入业务代码中却能实现切面功能呢,Spring采用的是配置的方式,在需要的地方配置需要的切面功能。 比较下面两份代码,你可以很明显的看到切面编程使得POJO非常简洁,只关注业务逻辑,不关心切入功能,使得切面功能和业务模块耦合的更松散。
// 没有使用AOP,依赖日志接口,日志代码侵入业务逻辑
public class Car{
Iwheel whell;
ILog log;
public Run(){
log.info("before Run");
whell.Run();
log.info("after Run");
}
}
// 使用AOP,POJO根本不知道有日志,日志是否需要和使用何种日志交给使用者,POJO只关心业务逻辑
public class Car{
Iwheel whell;
public Run(){
whell.Run();
}
}
通过切面和模板减少样板式代码
相信大家有过这种经历,在编写某些代码的时候,感觉跟别的代码很相似,比如数据库代码,或者远程调用,或socket。先连接,后处理业务,然后关闭,还要catch exception等一系列重复性的代码,看下面这个例子,业务代码被样板代码淹没了。
Connection con = null;
try {
con = DriverManager.getConnection(dbUrl1, dbUserName, dbPassword);
var stmt = con.prepareStatement("select * from users"); // 真正的业务代码只有这一行
var rs = stmt.executeQuery();
System.out.println("获取数据库连接成功!");
System.out.println("进行数据库操作!");
} catch (SQLException e) {
e.printStackTrace();
System.out.println("获取数据库连接失败!");
}finally{
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
Spring旨在通过模板封装来消除样板式代码,使用jdbcTemplate,样板代码消除了,只需要关心业务逻辑。jdbcTemplate.queryForObject(
"select * from users", // 查询语句
new RowMapper<User>{} // 结果映射
)
Bean容器
在spring中,POJO只关心自己的业务逻辑,不关心依赖的创建,实现。那有谁复杂依赖的创建,谁负责依赖的生命周期呢,那就是Bean容器。Bean容器装载所有的Bean(POJO类实例),通过注入bean来组装复杂bean。
Bean在容器中有一系列的生命周期节点,Bean开发者可以定义节点的钩子函数来定制Bean,比如销毁的时候,同时释放一些资源。
- Bean的建立, 由BeanFactory读取Bean定义文件,并生成各个实例
- Setter注入,执行Bean的属性依赖注入
- BeanNameAware的setBeanName(), 如果实现该接口,则执行其setBeanName方法
- BeanFactoryAware的setBeanFactory(),如果实现该接口,则执行其setBeanFactory方法
- BeanPostProcessor的processBeforeInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processBeforeInitialization()方法
- InitializingBean的afterPropertiesSet(),如果实现了该接口,则执行其afterPropertiesSet()方法
- Bean定义文件中定义init-method
- BeanPostProcessors的processAfterInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processAfterInitialization()方法
- DisposableBean的destroy(),在容器关闭时,如果Bean类实现了该接口,则执行它的destroy()方法
- Bean定义文件中定义destroy-method,在容器关闭时,可以在Bean定义文件中使用“destory-method”定义的
Spring模块
Spring框架由几个不同的模块组成,为开发企业级应用提供了所需的一切,下面是模块的概览图,会在后面的博客中详细介绍各个模块,这里只需要了解Spring的模块组成和各模块的功能就够了。
总结
以上是spring action第一章的总结,主要理解Spring的目标以及通过哪些手段来实现这些目标。相信你对Spring已经有了大概了解。后续博客将对Spring进行全面详细介绍。
上一篇: .net使用Cache框架的实例介绍
下一篇: jQuery遍历节点方法小结
推荐阅读
-
Spring概述学习笔记
-
第一个Spring Demo
-
MVC使用Spring.Net应用IOC(依赖倒置)学习笔记3
-
Spring Cloud zuul自定义统一异常处理实现方法
-
Spring Cloud学习教程之Zuul统一异常处理与回退
-
[Spring cloud 一步步实现广告系统] 16. 增量索引实现以及投送数据到MQ(kafka)
-
Spring Boot整合mybatis(一)实例代码
-
详解Spring Cloud Feign 熔断配置的一些小坑
-
MVC模式和Spring MVC初识
-
前端笔记之微信小程序(一)初识微信小程序&WXSS与CSS|WXML与HTML的差异&像素和DPR