Spring简介
Spring由《Expoer One-on-one j2eedevelopment and Design》文章核心延申而来。
2003年推出Spring:Spring的两大核心 IOC、APO
现在推出的Spring data、Spring boot、Spring cloud、Spring framework。这些都是由Spring延申而来的。
Spring是一个轻量级控制反转(IOC)和面向切面(AOP)的容器框架。
-
spring的设计理念:使先有的技术更加容易使用(简化企业级开发)。本身是一个大杂烩,整合了先有的技术框架。
-
SSH:struct2 + spring + hibernate
-
SSM:springMVC + spring + mybatis
(spring是一个融合剂)
spring官网:https://spring.io/projects/spring-framework#overview
spring官方下载地址:https://maven.springframework.org/release/org/springframework/spring/
spring官方文档:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html
GitHub地址:https://github.com/spring-project/spring-framework
spring中文文档:https://www.docs4dev.com/docs/zh/spring-framework/4.3.21.RELEASE/reference/spring-introduction.html
spring优点:
- spring是一个免费的框架。
- spring是一个轻量级的、非入侵式的框架(引入spring后不会改变代码原来的情况)。
- 控制反转(IOC)、面向切面编程(AOP)
- 支持事务处理,对框架整合的支持
spring弊端:
- 配置十分繁琐。
搭建Spring环境
Manen依赖:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
Spring七大模块
Spring的学习路线
现代java开发就是基于spring开发。
- Spring boot
- 是一个快速开发的脚手架
- 基于spring boot可以快速开发单个的微服务。(就是一个小模块)
- spring boot开发中约定大于配置
- Spring Cloud
- spring cloud是及用户spring boot实现的。
IOC理论
之前的业务使用:
- Dao层接口
- DaoImpl实现类
- Service层接口
- ServiceImpl实现类
在我之前写的代码中,service层调用dao层是固定写死的。也就是一个业务方法中创建一个固定的dao类使用。这种写法是有缺陷的,用户需求改变会影响我们的代码。程序代码量大的话,修改一次的成本就非常大!
例如:
// 原来的代码
public interface UserDao {
void print();
}
public class UserDaoImpl implements UserDao{
@Override
public void print() {
System.out.println("使用了UserDao");
}
}
public interface UserService {
void userServicePring();
}
public class UserServiceImpl implements UserService{
private UserDaoImpl userDao;
@Override
public void userServicePring() {
userDao = new UserDaoImpl();
userDao.print();
}
}
public class MyTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl(userDao);
userService.userServicePring();
}
}
如果我们增加一个UserDaoUseOracleImpl(使用Oracle进行数据库连接,其中的方法与UserDao一模一样),那么我们就必须重新修改UserServiceImpl中的代码了,这时非常不好的。
public class UserDaoUseOracleImpl implements UserDao{
@Override
public void print() {
System.out.println("使用了UserDaoUseOracle");
}
}
public class UserServiceImpl implements UserService{
private UserDaoUseOracleImpl userDao;
@Override
public void userServicePring() {
userDao = new UserDaoUseOracleImpl();
userDao.print();
}
}
动态注入(IOC原型)
我们可以利用set实现动态值的注入,这样就不用修改service层的代码了。
public interface UserDao {
void print();
}
public class UserDaoImpl implements UserDao{
@Override
public void print() {
System.out.println("使用了UserDao");
}
}
public class UserDaoUseOracleImpl implements UserDao{
@Override
public void print() {
System.out.println("使用了UserDaoUseOracle");
}
}
public interface UserService {
void userServicePring();
}
public class UserServiceImpl implements UserService{
private UserDao userDao;
@Override
public void userServicePring() {
userDao.print();
}
public void setUserDao(UserDao userDao){
this.userDao = userDao
}
}
public class MyTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
userService.setUserDao(new UserDaoImpl());
userService.userServicePring();
userService.setUserDao(new UserDaoUseOracleImpl())
userService.userServicePring();
}
}
- 之前,程序是主动创建对象的,控制权在程序上。
- 使用set注入后,控制权在用户程序员手中。
这种思想,从本质上解决了问题,我们业务程序员不需要再管理对象的创建了(由用户程序员创建)。降低了系统的耦合性,可以更加专注的放在业务实现上。
Spring底层大量用到了这种注入的思想!使得用户程序员创建对象底层代码不需要变动,提高了动态性。
IOC本质:控制反转是一种思想,使用控制反转后对象的创建移交给第三方(控制反转本质就是获取依赖对象的方式反转了:原来是程序创建依赖对象,现在是用户创建依赖对象)
IOC有很多实现方式,DI(依赖注入)只是其中一种。
控制反转是一种通过描述(XML或注解)并通过第三方生成特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(DI)
例如之前写的小例子:Service类就类似一个IOC容器,通过set注入生成不同功能的service对象。
通过上述所示:Spring可以管理对象(组件)
Hello Spring
一个简单的spring demo:
- 创建一个Bean类
- 注意Bean必须拥有set、get方法(因为依赖注入是利用set方法注入的)
public class Hello {
private String name;
public Hello() {
}
public Hello(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Hello{" +
"name='" + name + '\'' +
'}';
}
}
- 配置Bean的xml配置文件(用来配置Bean对象)
- 一个bean相当于一个对象,id为逻辑对象名。这个对象放到spring容器中,通过spring容器管理。
- 把它配置给spring容器,在容器中根据该xml new出对应的对象。
<!-- 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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello1" class="com.qiu.pojo.Hello">
<property name="name" value="spring"/>
<!-- ref引用的是一个bean对象 -->
<property name="h" ref="hello2"/>
</bean>
<bean id="hello2" class="com.qiu.pojo.Hello">
</bean>
</beans>
- 使用ClassPathXmlApplicationContext类创建一个spring容器
- 该容器通过beans.xml配置产生,也就是该容器中拥有、管理的是该xml文件中声明的对象。
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Hello hello = (Hello) context.getBean("hello1");
System.out.println(hello.toString());
这就叫控制反转:传统的程序对象是由程序显式new出来的,使用spring后对象是通过配置xml文件使用spring容器get出来的。控制权交到了用户手里,通过修改xml文件就可以修改业务,不需要修改整个系统代码。
传统程序对象是程序本身的所以程序高度依赖于特定的对象,如果换了业务整个系统的对象代码都需要改变,这就是高耦合的体现!现在通过spring容器进行对象的管理,spring相当于程序与对象之间的一个桥梁,这样换对象对程序影响极小。这就是解耦合的体现!
IOC创建对象的方式
IOC容器中自动创建对象,对象的创建时机在加载xml文件的时候就已经做了。创建对象时调用的bean的无参构造来创建对象。
使用有参构造创建Bean
使用构造器标签constructor-arg(在给属性赋值的时候使用的是property标签,给属性赋值时调用的无参构造)也就是说选择一种:使用property就是调用无参,set进行赋值;使用constructor-arg就是调用有参构造创建对象。
class User{
private String name;
private Child child;
public User{}
public User(String name, Child child){
this.name = name;
this.child = child;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Child getChild() {
return child;
}
public void setChild(Child child) {
this.child = child;
}
}
- 使用下标进行有参构造赋值
<beans>
<bean id="child" class="com.qiu.pojo.Child"></bean>
<!-- 使用下标进行有参构造 -->
<bean id="user" class="com.qiu.pojo.User">
<constructor-arg index="0" value="useruser"/>
<constructor-arg index="1" ref="child"/>
</bean>
</beans>
- 按照类型进行有参构造的赋值
不建议使用!如果构造方法有多个参数值类型相同的参数那么就不能识别了!
<beans>
<bean id="child" class="com.qiu.pojo.Child"></bean>
<!-- 使用下标进行有参构造 -->
<bean id="user" class="com.qiu.pojo.User">
<constructor-arg type="java.lang.String" value="useruser"/>
<constructor-arg type="com.qiu.pojo.Child" ref="child"/>
</bean>
</beans>
- 通过参数名进行有参构造的赋值
<beans>
<bean id="child1" class="com.qiu.pojo.Child"></bean>
<!-- 使用下标进行有参构造 -->
<bean id="user" class="com.qiu.pojo.User">
<constructor-arg name="name" value="useruser"/>
<constructor-arg name="child" ref="child1"/>
</bean>
</beans>