Spring5
一、Spring概述
1.1 什么是Spring?
- Spring是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,它将面向接口的编程思想贯穿整个系统应用。
- 关键词
- 轻量、控制反转(IoC)、面向切面(AOP)、容器、框架、MVC
1.2 Spring组件
- Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式。组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。
-
核心容器:
- 核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory ,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
-
Spring 上下文:
- Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
-
Spring AOP
- 通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。
- Spring AOP 模块为基于Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
-
Spring DAO:
- JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。
- 异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
-
Spring ORM:
- Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
-
Spring Web 模块:
- Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。
- Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
-
Spring MVC 框架:
- MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText和 POI。
二、IoC——控制反转
- IoC其实是一种思想上的表现,核心概念就是将程序中创建对象的权利由程序猿变更给了用户
- KEY:对象从程序猿创建变成了用户创建
- 为了更好的理解什么是IoC,下面有三个例子,分别演示了3种不同的创建对象的方式
2.1 传统方式
-
UserDao接口
public interface UserDao { public void getUser(); }
-
UserDao实现
-
默认实现
public class UserDaoImpl implements UserDao { @Override public void getUser() { System.out.println("UserDaoImpl :: getUser()"); } }
-
MySQL实现
public class UserDaoMysqlImpl implements UserDao { @Override public void getUser() { System.out.println("UserDaoMysqlImpl :: getUser()"); } }
-
SQLServer实现
public class UserDaoSqlserverImpl implements UserDao { @Override public void getUser() { System.out.println("UserDaoSqlserverImpl :: getUser()"); } }
-
-
UserService接口
public interface UserService { public void getUser(); }
-
UserService实现
public class UserServiceImpl implements UserService { private UserDao user = new UserDaoImpl(); @Override public void getUser() { System.out.println("UserService :: getUser()"); user.getUser(); } }
-
模拟用户使用
@Test public void useUser() { UserService userService = new UserServiceImpl(); userService.getUser(); }
- 根据运行结果可以看到,这个用户是默认实现。假设我们不想用默认实现,想要用mysql实现怎么办呢?
- 需要修改UserService实现类中的代码,从
new UserDaoImpl()
改成new UserDaoMysqlImpl()
,这样就能使用mysql实现
- 需要修改UserService实现类中的代码,从
- 根据运行结果可以看到,这个用户是默认实现。假设我们不想用默认实现,想要用mysql实现怎么办呢?
-
弊端:
- 每次用户变化需求,程序猿就要修改一次UserService实现类中的代码。如果说用户需求变来变去或者说底层代码很复杂,那么这对于开发来说是极其不友好的
2.2 通过setter方法注入(IoC的雏形)
-
较传统方式,极大减少了因需求变化而改变的代码量
-
修改UserService实现类
public class UserServiceImpl implements UserService { private UserDao user; public void setUser(UserDao user) { this.user = user; } @Override public void getUser() { System.out.println("UserService :: getUser()"); user.getUser(); } }
-
模拟用户使用
@Test public void useUser() { UserServiceImpl userService = new UserServiceImpl(); UserDao user = new UserDaoImpl(); userService.setUser(user); userService.getUser(); }
- 通过set方法,我们只需要传递不同的UserDao实现类给UserService,就能使用不同的UserDao实现。这样一来就方便了很多
-
这就是IoC的雏形
2.3 通过Spring托管
-
导入spring依赖
<!--使用这个依赖是因为spring-webmvc包含了大多数spring的组件,省去一个一个导入的步骤--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.9.RELEASE</version> </dependency>
-
Spring容器核心配置文件——beans.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 id="mysql" class="com.pbx.dao.UserDaoMysqlImpl" /> <bean id="default" class="com.pbx.dao.UserDaoImpl" /> <bean id="sqlserver" class="com.pbx.dao.UserDaoSqlserverImpl" /> <bean id="user" class="com.pbx.service.UserServiceImpl"> <property name="user" ref="mysql"/> </bean> </beans>
-
模拟用户使用
@Test public void springTest() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserService user = (UserService) context.getBean("user"); user.getUser(); }
-
如果说我们需要调用不同的实现,只需要修改配置文件中的相关参数即可
2.4 小结
- 纵览全部三种不同的实现方式
- 传统方式
- 灵活性低,较为笨重,每次有新需求的时候都需要修改底层代码,工作量大
- setter方式注入
- 较为灵活,出现新需求时,无需修改底层代码,只需要根据需求的不同传递不同的参数即可。简化了业务处理逻辑。
- 假设我们服务的使用者是具有一定编程基础的人群,通过setter方式进行注入的方式看起来也不是不可以。毕竟作为用户来说,只需要传递不同类型的参数即可。
- 看起来还是不错的一种方案。但是若是业务处理时涉及到的其他组件时,这种方法依旧不好
- Spring托管
- Spring托管就完全避免了上述的弊端。
- 因为需求的改动,完全不需要涉及源码层次的修改。用户需要做的就是按照自身需求修改配置文件。
- 用户甚至不需要知道你底层是干什么的,只需要知道我这么改就可满足我的需求。而我们底层的实现中,又很好的遵守了一些规范,这样,每当需要做不同的事情时,我们底层的代码修改量就很少了
- 传统方式
- IoC的核心思想,就是将某些具体实现类的对象的创建权利从开发人员手中交给使用的人。
- 对象全部交给Spring托管,由Spring创建、管理和装配
- 本质:解耦
三、使用Spring管理对象
3.1 对象被创建的时间
-
创建实体类
public class User { private String name; private int id; private String nickname; }
-
托管实体类
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user" class="com.pbx.pojo.User"> <property name="id" value="1"/> </bean> </beans>
-
测试
@Test public void test() { System.out.println(1); ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); System.out.println(2); User user = (User) context.getBean("user"); System.out.println(3); user.toString(); }
-
结论
- 被Spring托管的对象,在ApplicationContext对象创建之后就已经被创建出来
- 且通过配置文件注入了相应的属性值,然后等待调用。
- 默认通过托管对象的无参构造器创建,但也可以通过有参构造器进行创建
3.2 创建对象的方式
-
Spring默认通过无参构造器创建对象,然后使用setter方法注入属性值。若没有无参构造器的话,Spring可以通过有参构造器创建对象
-
创建实体类
public class User { private int id; private String name; private String nickname; public User() { System.out.println("User::User()"); } public User(int id, String name, String nickname) { System.out.println("User::User(String name, int id, String nickname)"); this.id = id; this.name = name; this.nickname = nickname; } // 省略getter和setter方法 }
-
编写配置
<bean id="user1" class="com.pbx.pojo.User"> <property name="id" value="1"/> <property name="name" value="张三"/> <property name="nickname" value="帅哥"/> </bean> <!--通过有参构造器的参数下标绑定参数--> <bean id="user2" class="com.pbx.pojo.User"> <constructor-arg index="0" value="2" /> <constructor-arg index="1" value="李四" /> <constructor-arg index="2" value="小伙"/> </bean>
-
测试
@Test public void test2() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User user1 = (User) context.getBean("user1"); System.out.println(user1.toString()); User user2 = (User) context.getBean("user2"); System.out.println(user2.toString()); }
-
User1是通过默认方式(无参构造器)创建的,User2是通过有参构造器的方式创建的。二者都是被Spring托管的对象。使用有参构造器创建对象时,需要绑定参数,这里会在DI的时候详细说明
四、配置Spring
4.1 别名
alias标签可以给被Spring托管的对象设置个别名
<alias name="user1" alias="u1"/>
<bean id="user1" class="com.pbx.pojo.User">
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="nickname" value="帅哥"/>
</bean>
4.2 Bean配置
<bean id="user1" class="com.pbx.pojo.User" name="user">
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="nickname" value="帅哥"/>
</bean>
- name属性下可以配置别名,而且可以配置多个别名
4.3 import
- 用于和其他配置文件进行合并的。会自动删除重复信息