博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第四章:重新来认识你的老朋友Spring框架
阅读量:6114 次
发布时间:2019-06-21

本文共 6782 字,大约阅读时间需要 22 分钟。

欢迎查看,如果您正在为Java后端庞大的体系所困扰,如果您正在为各种繁出不穷的技术和各种框架所迷茫,那么本系列文章将带您窥探Java庞大的体系。本系列教程希望您能站在上帝的角度去观察(了解)Java体系。使Java的各种后端技术在你心中模块化;让你在工作中能将Java各个技术了然于心;能够即插即用。本章我们来一起了解你的老朋友Spring框架。

Spring这个词对于开发者想必不会陌生,可能你每天都在使用Spring,享受着Spring生态提供的服务,理所当然的用着SpringIOC和SpringAOP去实现老板交给你的功能 ,唔 它就是这样使用的(类声明为Bean组件,然后注入),没错 能完成老板任务,没毛病。如果向你提问什么是Spring,Spring有什么核心功能呢,你会想:这太简单了,Spring就是框架嘛,Spring核心功能就是IOC和AOP,So Easy!!可是你真的了解Spring吗?带着这个疑问让我们一起来重新了解一下Spring!

Spring的起源和根本使命

Spring是一个开源框架,最早由RodJohnson创建,是为了解决企业级应用开发的复杂性而创建的。很多框架都宣称在某些方面针对Java开发做出了简化,但是Spring的目标是致力于全方位简化Java开发,这也是Spring的根本使命"简化Java开发"

在这里插入图片描述

Spring如何简化Java开发

为了降低Java开发的复杂性,Spring采取了以下4种关键策略,请务必牢记下面4中策略于心,这样会帮助你更深的理解Spring。下面我们来逐一解读每一条策略,你就能明白Spring是如何简化Java开发的。

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

1.基于POJO的轻量级和最小侵入性编程

Spring竭力避免因自身的API而弄乱你的代码。Spring不会强迫你实现Spring规范的接口或继承Spring规范的类。相反,在一个基于Spring构建的应用中,应用中的类没有任何痕迹表明你使用了Spring。最坏的情况就是你在应用的类中发现了Spring的相关注解,但它依然是POJO,下面我们来看一个在Spring中的一个POJO例子。

/** * @Author:jimisun * @Description: * @Date:Created in 20:32 2018-09-26 * @Modified By: */public class HelloSpringBean {    public String sayHello() {        return "Hello Spring!!!";    }}

你可以看到,这就是一个POJO(简单的JAVA类),没有任何地方表明它是Spring组件,Spring非侵入式编程模型意味着这个类在Spring应用和非Spring应用中都可以发挥同样的作用。尽管看起来很简单;但Spring通过IOC(Inversion of Control)管理这个POJO,然后通过DI(Dependency Inject)来注入他们,这个POJO就变的魔力十足;那么DI是如何帮助应用对象彼此之间保持松耦合的呢?

2.通过依赖注入和面向接口实现松耦合

来我们一起来看一下一个简单的POJO

/** * @Author:jimisun * @Description: * @Date:Created in 07:44 2018-09-27 * @Modified By: */public class BeautifulGirl implements Gril {    private EatAction eat;    public BeautifulGirl() {        this.eat = new EatAction();    }    @Override    public void action() {        eat.action();    }}

在BeautifulGirl(可爱的小女孩)这个类中,在构造方法中创建一个EatAction(吃饭动作)。这样就极大限制了BeautifulGirl(可爱的小女孩)的能力;如果现在小女孩需要去玩耍呢?或者需要去睡觉呢?真是太抱歉了,BeautifulGirl(可爱的小女孩)只会吃东西这个动作。这是什么原因呢?这就是BeautifulGirl(可爱的小女孩)和EatAction(吃饭动作)这两个类紧紧耦合在了一起!紧密耦合同时会造成代码的难以测试,难以服用,难以理解,并且典型地表现出"打地鼠“式的Bug特性(修复一个Bug,将会出现一个或多个新Bug),所以我们可以知道耦合是必须的,但必须谨慎管理耦合。 但是怎么才算是谨慎处理耦合关系呢?

在这里插入图片描述

上图所示,DI(依赖注入)会将所依赖关系自动交给目标对象,而不是让对象本身创建所依赖对象。对象的依赖关系将由系统中负责协调个对象依赖关系的第三方组件(类似Spring)在创建对象的时候设定。现在我们明白了通过DI依赖注入可以将对象之间依赖关系轻松解耦,那么我们来看一下简单的实例吧。

/** * @Author:jimisun * @Description: * @Date:Created in 07:44 2018-09-27 * @Modified By: */public class BeautifulGirl implements Gril {    private Action action;    public BeautifulGirl(Action action) {        this.action = action;    }    @Override    public void action() {        action.action();    }}

从上面实例代码中可以看到BeautifulGirl本身并没有创建任何的动作,而是通过构造方法传入一个实现了Action(动作)接口的实现类即可,也就是说BeautifulGirl可以完成任意实现了Action接口的动作(睡觉啦...玩耍啦...旅行啦....)。

这里的要点是BeautifulGirl没有与任何特定的Action发生耦合。BeautifulGirl只需要的是一个实现Action接口就行,对象本身只是通过接口(而非具体实现或初始化过程)来表明依赖关系,那么这种依赖就能够在BeautifulGirl不知情的情况下替换不同的具体动作。好了我们现在明白了DI进行依关系解耦的原理了,下面我们看一下如何在Spring中应用DI。

/** * @Author:jimisun * @Description: * @Date:Created in 07:53 2018-09-27 * @Modified By: */public class Main {    public static void main(String[] args) {        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");        BeautifulGirl beautifulGirl = (BeautifulGirl) context.getBean("beautifulGirl");        beautifulGirl.action();        context.close();    }}

这样执行Main方法,从Context中获取BeautifulGirl实例执行action方法。当然Spring提供了基于Java的配置,可作为XML配置文件的代替方案

/** * @Author:jimisun * @Description: * @Date:Created in 08:40 2018-09-27 * @Modified By: */@Configurationpublic class SpringConfig {    @Bean    public SleepAction sleepAction() {        return new SleepAction();    }    @Bean    public BeautifulGirl beautifulGirl() {        return new BeautifulGirl(sleepAction());    }}

只不过Spring的上下文的实现应该使用AnnotationConfigApplicationContext进行加载配置

/** * @Author:jimisun * @Description: * @Date:Created in 07:53 2018-09-27 * @Modified By: */public class Main {    public static void main(String[] args) {        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);        SleepAction action = applicationContext.getBean(SleepAction.class);        action.action();    }}

3.基于切面和惯例进行声明式编程

现在我们已经明白DI能够将互相协作的软件保持松耦合,而面向切面编程(aspect-oriented-programming,AOP)可以将遍布应用各处的功能分离出来形成可从用的组件。

我们仍然使用上面的例子,BeautifulGirl随心所欲的执行各种动作真的没问题吗?如果可爱的小女孩执行的动作是去河边玩耍,吃一些危险的东西呢?那么我们势必需要一个家长(Parent类)进行监督小女孩的动作是否是安全的,下面我们来看一下Parent类。

/** * @Author:jimisun * @Description: * @Date:Created in 09:32 2018-09-27 * @Modified By: */public class Parent {    public void check() {        System.out.println("检查动作是否安全.......");    }}

非常简单!Parent(家长类)只有一个方法就是check,那么现在就让Parent对BeautifulGirl的执行动作进行检查吧。

/** * @Author:jimisun * @Description: * @Date:Created in 07:44 2018-09-27 * @Modified By: */public class BeautifulGirl implements Girl {    private Action action;    private Parent parent;    public BeautifulGirl(Action action, Parent parent) {        this.action = action;        this.parent = parent;    }    @Override    public void action() {        parent.check();        action.action();    }}

我们非常聪明,使用了DI将Parent类注入到了BeautifulGirl类中,在BeautifulGirl执行action动作之前执行 parent.check()方法,这样我们要的效果就达到了。等等....好像有什么不对的地方?

  • 管理Parent家长的check动作真的是美丽的小女孩的职责吗?
  • 将Parent家长注入到美丽的小女孩类中不是将代码复杂化了吗?
  • 我们需不需要一个不需要家长注入的美丽的小女孩呢?
  • 如果注入的Parent为NULL我们是否应该在美丽的小女孩中进行校验呢?

真的是太糟糕了,注入一个Parent(家长)将会产生那么多的问题,为什么呢?因为Parent类的业务于BeautifulGirl无关;BeautifulGirl将会承担Parent类的职责。

在一个项目中,很多系统服务都会分布到各个业务模块中,这使得业务模块的逻辑变得十分复杂,而使用AOP能够使这些服务模块化,并以声明式的方式将他们应用到他们所需要影响的组件中,使得这些组件将会具有更高的内聚性并且更加关注自身的业务逻辑,完全不需要了解系统服务所带来的复杂性。

下面我们使用SpringAOP对上面代码进行改造

 

 
/** * @Author:jimisun * @Description: * @Date:Created in 07:44 2018-09-27 * @Modified By: */public class BeautifulGirl implements Girl {    private Action action;        public BeautifulGirl(Action action) {        this.action = action;    }    @Override    public void girlAction() {        action.action();    }}

我们只需要在Spring配置文件中声明Parent为Spring Bean,然后将配置在SpringAOP中即可,我们可以发现BeautifulGirl类中没有发现任何关于Parent的信息,这就是AOP的魅力所在——以声明的方式将组件应用到他们所需要影响的组件中!

4.通过切面和模板减少样版式代码

在通过JavaAPI进行编程,我们经常会编写很多重复的代码例如JDBC访问数据库,JMS,JNDI等场景下会重复编写大量的样版式代码,而Spring皆在通过模板封装来消除模板式代码,例如Spring针对JDBC访问数据库进行封装的JdbcTemplate等,这里就是Spring使用封装的模板来减少JavaAPI样版式代码。

/** * @Author:jimisun * @Description: * @Date:Created in 11:13 2018-09-27 * @Modified By: */public class Main {    public static void main(String[] args) {        JdbcTemplate jdbcTemplate = new JdbcTemplate();        jdbcTemplate.execute("select * from user");    }}

非常感谢大家耐心能看到这里,在本文中我尽可能地详细阐述Spring使如何简化Java开发?遵循哪些策略?以及为什么遵循的好处。

Java开发之上帝之眼系列教程其他文章

本文资料来源:

勘误&感谢

  本系列文章资料来源很多出自于互联网和在下本身的见解,受限于个人技术能力水平和其他相关知识的限制,相关见解错误或者资料引用错误请各位帮助留言校正!引用资料多来自于互联网,在下在引用前会遵循各位前辈或者博主的引用说明表示感谢,但互联网资料多是转发再转发或存在遗漏请原作者内信联系指正。

转载地址:http://pdjka.baihongyu.com/

你可能感兴趣的文章
某大型网站迁移总结(完结)
查看>>
mysql的innodb中事务日志(redo log)ib_logfile
查看>>
部署SSL证书后,网页内容造成页面错误提示的处理办法
查看>>
MS SQLSERVER通用存储过程分页
查看>>
60.使用Azure AI 自定义视觉服务实现物品识别Demo
查看>>
Oracle 冷备份
查看>>
jq漂亮实用的select,select选中后,显示对应内容
查看>>
C 函数sscanf()的用法
查看>>
python模块之hashlib: md5和sha算法
查看>>
linux系统安装的引导镜像制作流程分享
查看>>
解决ros建***能登录不能访问内网远程桌面的问题
查看>>
pfsense锁住自己
查看>>
vsftpd 相关总结
查看>>
bash complete -C command
查看>>
解决zabbix 3.0中1151端口不能运行问题
查看>>
售前工程师的成长---一个老员工的经验之谈
查看>>
Get到的优秀博客网址
查看>>
dubbo
查看>>
【Git入门之四】操作项目
查看>>
老男孩教育每日一题-第107天-简述你对***的理解,常见的有哪几种?
查看>>