什么是Spring
Spring是一个开源的,轻量级Java开发框架; 其核心特性是可以用于开发任何 Java 应用程序,Spring 框架的目标是使 JavaEE应用程序的开发变得更加容易,核心概念是IOC和AOP;这也是学习Spring的重点所在;
Spring不是针对某个具体功能,具体层级的框架; 也就是说以前该有的系统分层,结构,设计模式都不需要改变,而是让Spring加入进来,让开发变得更简单; 记住Spring并不想取代某个已存在的框架,反而可以让各个框架的配合使用难度降低,它可以快速的在系统中集成其他优秀的框架。
为什么需要Spring
我们经常会看到Spring替代EJB,或Spring与EJB对比,那么两者之间到底有什么关系呢?
EJB是JavaEE规范中的一个,主要用于开发分布式应用程序
Spring是一个框架,框架是帮你实现了一部分功能的半成品
EJB是一个规范,用来规范(指导)开发者,如何去实现JavaEE程序
所以这个问题其实是在问Spring(框架)和JavaEE(规范)的对比,而因为两者不是同一种概念,所以无法直接对比,那到底在对比啥?
对比的是:使用Spring开发和完全按照JavaEE规范开发应用程序的区别
推出Spring推出就是民间开发者对官方规范的中不足的地方提出的质疑以及做出的强力回应,在早期阶段,开发者们从最早的JavaEE这一官方协议推出后,开发者们非常拥戴,后来慢慢发现这堆复杂,晦涩,学习成本极高的规范是多么的臃肿不堪,就在这时候Spring框架应运而生,因其轻量级,使用简单很快受到了大家的喜爱;
EJB容器和IOC容器
另一方面因为Spring具备ICO容器,可以帮助我们管理Bean,而EJB的需要放在EJB容器中才能使用其提供的功能; EJB主要用于提供分布式能力,而IOC容器是帮助我们更好的解耦;
Spring的优点
1、Spring 对JavaEE中的一些API(JDBC、JavaMail、远程调用等),提供了封装,使这些API使用难度降低;
2、一站式框架,可简单快速的集成其他框架;
3、IOC,利用依赖注入,极大的降低各组件间的耦合,提高整体扩展性;
4、AOP(面向切面)编程的支持,可以方便的对程序进行权限拦截,运行监控等;
5、声明式事务支持,通过配置就可以完成对事务的管理,无序进行手动编程;
6、容器化,Spring包含并管理应用对象的配置和生命周期,你可以配置每个bean如何被创建以及bean是一个单独的实例或者每次需要时都生成一个新的实例,以及它们是如何相互关联的。
IOC和DI
概念
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来降低计算机代码之间的耦合度。将原本由程序实现的一部分逻辑反过来交给系统来完成就称之为控制反转。
其中最常见的方式叫做依赖注入(Dependency Injection,简称DI)通过控制反转,可以说,依赖被注入到对象中。依赖注入是实现控制反转的一种手段;、
为何需要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中
expression又为SpEL(spring-expression Language),提供了表达式语言支持,其对JSP中的EL进行了扩展
AOP,提供了面向切面编程实现
Aspects 模块提供了与 AspectJ 的集成,是一个功能强大且成熟的AOP框架
Instrument 用于代理监控JVM运行的JAVA程序,对字节码修改以实现AOP
Messaging 模块为 STOMP 提供了支持,主要处理来自 WebSocket 客户端的 STOMP 信息
强调:
Spring是模块化的,完全可以根据需要来导入所需模块
使用入门
传统写法
面向接口:
UserService接口:
public interface UserService {
void login(String name);
}
UserServiceImpl 实现类
public class UserServiceImpl implements UserService {
@Override
public void login(String name) {
if ("lbb".equals(name)){
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
}
}
UserController
public class UserController {
public void login() {
//要实现controller需要调用service
//第一种直接new
UserService userService = new UserServiceImpl();
userService.login("lbb");
}
public static void main(String[] args) {
new UserController().login();
}
}
上面是一个简单的传统写法,controller层调用service层,在controller层new一个service,这样如果加入了一个新的service实现类,后面在使用的时候就要修改代码,这样就违反了开放封闭原则(OCP)。
补充说明:OCP
叫做开放封闭原则,是应用程序开发中应该遵循的一个原则
open:对扩展开放
close:对修改源代码封闭
其目的是要在不修改源代码的情况下对已有功能进行扩展
所以对于上述代码,我们可以做优化,也就是创建一个工厂:
public class UserServiceFactory {
public UserService getUservice(){
return new UserServiceImpl();
}
}
UserController 就可以通过工厂获取:
public class UserController {
public void login() {
//要实现controller需要调用service
//第一种直接new
// UserService userService = new UserServiceImpl();
//通过工厂来获取
UserService userService = new UserServiceFactory().getUservice();
userService.login("lbb");
}
public static void main(String[] args) {
new UserController().login();
}
}
上面这种方式UserController 不需要再更改,但是你要添加类,需要在工厂类里面更改,所以依然需要改进,我们可以改进工厂,来实现开放封闭原则:
在resources下创建一个my.properties
文件:
implClass = service.UserServiceImpl
将要执行的实现类写在里面,通过工厂获取类名,再通过反射获取类,这样搞只需要修改这个配置文件,而不需要修改类:
UserServiceFactory
public class UserServiceFactory {
public UserService getUservice(){
try {
//读取配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("D:\\Java_file\\mybatisBase\\src\\main\\resources\\my.properties"));
//读取类
String implClass = properties.getProperty("implClass");
//反射获取对象
Class<?> aClass = Class.forName(implClass);
return (UserService) aClass.newInstance();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
上面是一个经典的思想,如果有多个类的话,需要多个工厂,这时候你会发现工厂做的事都是一样的,不一样的就是配置文件路径,返回对象类型,这些我们可以做繁星来封装,而spring就为我们做了这些事。
使用Spring
配置maven添加依赖:
<!-- Maven会自动下载所有Spring核心容器和aop的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
创建配置文件:
在resources
下创建一个名为:applicationContext.xml
的配置文件:
<?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="UserService" class="service.UserServiceImpl"/>
</beans>
上面bean中class是包名加类名,id是我们定义的,我们后面会使用id来获取类对象。
从Spring中获取需要的对象
public class UserController {
public void login() {
//要实现controller需要调用service
// 从Spring中获取需要的对象
//读取配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//根据配置文件bean标签id获取对应对象
UserService userService = (UserService) context.getBean("UserService");
userService.login("lbb");
}
public static void main(String[] args) {
new UserController().login();
}
}
由上面,不难看出此时的Spring就是一个对象工厂,但这仅仅Spring的基础功能
下一篇:spring详解之bean管理