Spring hello world
什么是Spring
Spring是一个开源的,轻量级Java开发框架; 其核心特性是可以用于开发任何 Java 应用程序,Spring 框架的目标是使 JavaEE应用程序的开发变得更加容易,核心概念是IOC和AOP;这也是学习Spring的重点所在;
Spring不是针对某个具体功能,具体层级的框架; 也就是说以前该有的系统分层,结构,设计模式都不需要改变,而是让Spring加入进来,让开发变得更简单; 记住Spring并不想取代某个已存在的框架,反而可以让各个框架的配合使用难度降低,它就像502胶水,可快速的在系统中集成其他优秀的框架
Spring也因其特性而得名,寓意为JavaEE开发的春天来了
为什么需要Spring
我们经常会看到Spring替代EJB,或Spring与EJB对比等等相关文章,那么两者之间到底有什么关系呢?
之前的课程中我们知道,EJB是JavaEE规范中的一个,主要用于开发分布式应用程序
从概念上来看:
- Spring是一个框了架,框架是帮你实现了一部分功能的半成品
- 而EJB是一个规范,用来规范(指导)开发者,如何去实现JavaEE程序
所以这个问题其实是在问Spring(框架)和JavaEE(规范)的对比,而因为两者不是同一种概念,所以无法直接对比,那到底在对比啥? 不能在卖关子了;
问题应该是:使用Spring开发和完全按照JavaEE规范开发应用程序的区别
这个问题应该由Spring的作者Rod Johnson来回答:
#Rod Johnson在2002年编写的《Expert One-to-One J2EE Design and Development》一书,Rod 在本书中对J2EE正统框架臃肿、低效、脱离现实的种种学院派做法提出了质疑,并以此书为指导思想,编写了interface21框架,也就是后来的Spring。
的确推出Spring推出就是民间开发者对官方规范的中不足的地方提出的质疑以及做出的强力回应,在早期阶段,开发者们经历了拥抱到抛弃,从最早的JavaEE这一官方协议推出后,开发者们非常拥戴,毕竟是官方嘛,后来慢慢发现这堆复杂,晦涩,学习成本极高的规范是多么的臃肿不堪,就像你为了打一只小鸟而搬出了战斗机;就在这时候Spring框架应运而生,因其轻量级,使用简单很快受到了大家的喜爱;
好在官方也意识到了问题,于是在EJB3.0做出了大量的改进,并借鉴了Spring中一些非常优秀的特性,但如日中天的Spring好像并没有受到太大的影响,大家一如既往的喜爱Spring;
EJB容器IOC容器
另一方面因为Spring具备ICO容器,可以帮助我们管理Bean,而EJB的需要放在EJB容器中才能使用其提供的功能; EJB主要用于提供分布式能力,而IOC容器是帮助我们更好的解耦
Spring的优点
- Spring 对JavaEE中的一些API(JDBC、JavaMail、远程调用等),提供了封装,使这些API使用难度降低;
- 一站式框架,可简单快速的集成其他框架;
- IOC,利用依赖注入,极大的降低各组件间的耦合,提高整体扩展性;
- AOP(面向切面)编程的支持,可以方便的对程序进行权限拦截,运行监控等;
- 声明式事务支持,通过配置就可以完成对事务的管理,无序进行手动编程;
- 容器化,Spring包含并管理应用对象的配置和生命周期,你可以配置每个bean如何被创建以及bean是一个单独的实例或者每次需要时都生成一个新的实例,以及它们是如何相互关联的。
IOC,DI
概念
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。
将原本由程序实现的一部分逻辑反过来交给系统来完成就称之为控制反转
其中最常见的方式叫做依赖注入(Dependency Injection,简称DI)通过控制反转,可以说,依赖被注入到对象中。
依赖注入是实现控制反转的一种手段;
为何需要IOC
举个例子:自己搭配组装机,需要考虑各种部件的兼容性,和自己的性能的要求,如CPU,内存,显卡等等;但有了专门的组装机服务器商(IOC容器),你只要告诉他你的基本需求,比如,要一台吃鸡电脑,剩下的就交给服务商去做了;
大多数应用程序,都是有很多不同对象彼此合作来完成业务逻辑,这导致在获取一个合作对象时,必须显示的去new一个对象,这将就导致代码高度耦合并且难以维护和调试。像下面这样
public class Controller { @Test public void doGet() throws Exception { //这里需要依赖Service层 UserService service = new UserService("参数1","参数2"); }
当需要更换其他业务逻辑实现类时就不得不修改源代码,并且若Service的实例化需要参数时,Controller层就不得不为其提供必要的参数,这反映了Controller与Service的耦合度是较高的
Spring体系结构
core,提供了框架基础组成部分,包括IoC和DI;
beans,提供了BeanFactory,是工厂模式的实现,提供普通对象和单例对象的获取
context,建立在core和bean的基础上,可将其他库集成到Spring中
SpEL(spring-expression Language)提供了表达式语言支持,其对JSP中的EL进行了扩展
AOP,提供了面向切面编程实现
Aspects 模块提供了与 AspectJ 的集成,是一个功能强大且成熟的AOP框架
Instrumentation 用于代理监控JVM运行的JAVA程序,对字节码修改以实现AOP
Messaging 模块为 STOMP 提供了支持,主要处理来自 WebSocket 客户端的 STOMP 信息
强调:
Spring是模块化的,完全可以根据需要来导入所需模块
使用入门
传统写法
先来看一个不使用Spring时,控制和业务逻辑层交互的案例,控制器:
public class Controller { @Test public void doGet() throws Exception { //这里需要依赖Service层 //v1 直接写 //UserService service = new UserService(); //v2 面向接口 某个实现类 //UserService service = new UserServiceImpl(); //要跟换其他实现类时 违反了OCP(开放封闭)原则 //UserService service = new UserServiceImpl2(); //v3 为避免修改源代码扩展 加入工厂 ServiceFactory factory = new ServiceFactory(); UserService service = factory.getService(); //调用业务方法 service.userLogin("jerry","admin"); } }
工厂:
public class ServiceFactory { public UserService getService() throws Exception { //此处id应配置在xml中 String id = "UserServiceImpl"; if (id.equals("UserServiceImpl")){ return new UserServiceImpl(); }else if(id.equals("UserServiceImpl2")){ return new UserServiceImpl2(); } throw new Exception("id:"+id + "not register"); } }
使用工厂模式可以进一步降低组件间的耦合度,但在完整的系统中有很多组件,需要很多个工厂,使程序变得复杂,臃肿;
Spring将自身设计为一个大型对象工厂,负责管理系统中设计到的所有对象,并利用DI处理对象的依赖关系,当对象A需要对象B时不再自己创建而是从Spring中获取
补充说明:OCP
叫做开放封闭原则,是应用程序开发中应该遵循的一个原则
open:对扩展开放
close:对修改源代码封闭
其目的是要在不修改源代码的情况下对已有功能进行扩展
使用Spring
1.创建Maven项目
2.添加依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.2.RELEASE</version> </dependency> <!-- Maven会自动下载所有Spring核心容器和aop的依赖-->
3.创建配置文件
通常名为:applicationContext.xml
当然你也可以修改放在resources
下
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--使用bean标签,创建Service对象,并交给容器来管理--> <bean id="UserService1" class="com.yyh.serviceimpl.UserServiceImpl"/> <bean id="UserService2" class="com.yyh.serviceimpl.UserServiceImpl2"/> </beans>
名称空间声明可到官网查找,或是直接在jar中查找,如:
4.从Spring中获取需要的对象
@Test public void doGetUseSpring() throws Exception { //创建应用上下文 指定配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //从Spring中获取所需对象 UserService userService = (UserService)context.getBean("UserService2"); //调用业务逻辑方法 userService.userLogin("jerry","admin"); }
不难看出此时的Spring就是一个对象工厂,但这仅仅Spring的基础功能
IOC容器
容器可以理解为存放对象的地方,当然不仅仅是存储,还有对象的管理,包括-创建-销毁-装配; 这样原本程序要做的事情交给了Spring,所以这属于IOC,称之为IOC容器;
Spring有两个接口ApplicationContext是BeanFactory的子接口。它们都可以作为Spring的容器;
两种容器的区别:
? BeanFactory作为顶级接口主要面向于Spring框架本身,仅提供了基础基本的容器功能如DI
? ApplicationContext,是BeanFactory的子接口,意味着功能比BeanFactory更多,诸如国际化,注解配置,XML配置等等
? BeanFactory采取的懒加载的方式,在获取对象时才会实例化
? ApplicationContext会在工厂初始化时立即实例化对象
? ApplicationContext的两个实现类区别:
ClassPath表示从类路径中获取配置文件
FileSystem表示从文件系统获取配置文件