重生之我在地球当程序员-Spring篇
本篇用来学习Spring,了解Spring是什么?怎么用?为什么用?Spring的重点就两个IOC容器和AOP面向切面编程。
Spring是什么?
Spring是一个分层的Java SE/EE full-stack(一站式)轻量级开源框架,
以 IoC(Inversion Of Control:控制反转) AOP(Aspect Oriented Programming:面向切面编程)为内核。
在java三层架构当中分别提供了相应技术:
表现层(web层):SpringMVC 框架,servlet
业务层(service层):Bean管理(IOC容器,在三层都有体现 声明式事务
持久层(dao层):JdbcTemplate模板对象以及提供了ORM模块整合其他优秀的持久层技术,用的不多,都用MyBatis框架替代。
总而言之:
Spring 框架是一个分层一站式框架、它就有轻量、开源、AOP、IOC的优点。
IoC机制以及IoC的使用
IoC就是将创建对象和维护对象交给Spring框架,不用开发人员手动去new一个对像,
简单来说 Spring框架扮演着中介的角色,用来连接房东和租户,避免了耦合性过高,
实现解耦合
IoC本质上就是一个大工厂,大容器。主要作用就是创建和管理对象的依赖关系,
削减计算机程序的耦合(解除我们代码中的依赖关系),提高程序的可扩展性和可维护性。
IoC的基础入门
构建项目所需要的依赖
<properties>
<!--定义Spring的版本,进行统一版本管理-->
<spring.version>5.3.18</spring.version>
</properties>
<!--导入spring的context依赖,context依赖core、beans、expression aop-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
持久层和服务层代码
//数据操作层代码(持久层)
public interface UserDao {
//声明操作方法
int addUser();
}
public class UserDaoImpl implements UserDao {
@Override
public int addUser() {
System.out.println("UserDao正在进行添加操作...");
return 0;
}
}
//服务层代码(业务层)
public interface UserService {
public void saveService();
}
public class UserServiceImpl implements UserService {
@Override
public void saveService() {
System.out.println("userSerivce save method running......");
}
}
创建配置文件管理对象
<?xml version="1.0" encoding="UTF-8"?>
<!--spring IOC容器的核心配置文件!-->
<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属性 创建对象的唯一标识,后期从IOC容器中获取对象的依据
class属性 创建对象所属类的全路径名
name属性 bean的名称一般不用和id功能类似,但可以包含特殊字符
-->
<bean id="userDao" class="com.cs.dao.impl.UserDaoImpl"></bean>
</beans>
配置文件介绍
bean标签: 用于配置对象交给Spring 来创建。
默认情况下他会调用类中无参数的构造器,如果没有无参数构造器则不能成功创建
重点:如果定义有参构造记得将无参构造,防止发生初始化失败的问题
基本属性:
id : Bean实例对象在Spring容器当中的唯一标识,使用该对象的时候根据id获取
class : Bean的全限定类名
name : 了解,给对象命名操作
lazy-init:懒汉式,用来设置bean实例化的时间,如果为true,那么当使用到该bean对象的
时候才会实例化。默认为false,当初始化容器的时候就实例化对象
autowire :自动装配模式,有5种:no、byName、byType、constructor、default。
例如有类A和B
no:默认是这个,不使用自动装配、老老实实地用<ref>标签去指明依赖B(了解)
byName:根据bean的名字,spring在IoC容器中根据B的名字查找bean,然后给A注入B,前提是A中有相关的setter方法。这种方法是根据setter方法对A中的B进行注入。
byType:根据bean的类型,spring在IoC容器中根据对象的类型查找bean,然后将对应类型的对象注入,如果该类型有多个实现将会报错。
constructor:不太重要
default:不太重要
bean 对象创建~
第一种,通过默认的无参构造方式创建,其本质就是把类交给Spring自带的工厂(BeanFactory)管理、由Spring自带的工厂模式帮我们维护和创建这个类。如果是有参的构造方法,也可以通过XML配置传入相应的初始化参数,这种也是开发中用的最多的。
<bean id = "user" class = "User">
<property name = "name" value = "龙傲天">
<property name = "age" value = "23">
</bean>
第二种,通过静态工厂创建,其本质就是把类交给我们自己的静态工厂管理,Spring只是帮我们调用了静态工厂创建实例的方法,而创建实例的这个过程是由我们自己的静态工厂实现的,在实际开发的过程中,很多时候我们需要使用到第三方jar包提供给我们的类,而这个类没有构造方法,而是通过第三方包提供的静态工厂创建的,这是时候,如果我们想把第三方jar里面的这个类交由spring来管理的话,就可以使用Spring提供的静态工厂创建实例的配置。
//静态工厂,生成User对象
public class UserFactory {
public static User createUser() {
System.out.println("静态工厂方式创建User对象");
return new User();
}
}
<!--
使用静态工厂的方式实例对象
id 依旧是bean对象的唯一标识,获取的唯一标识
class 静态工厂的全路径名
factory-method 生产对象的方法名称
-->
<bean id="user" class="com.cs.factory.UserFactory" factory-method="createUser"></bean>
第三种,通过实例工厂创建,其本质就是把创建实例的工厂类交由Spring管理,同时把调用工厂类的方法创建实例的这个过程也交由Spring管理,看创建实例的这个过程也是有我们自己配置的实例工厂内部实现的。在实际开发的过程中,如Spring整合Hibernate就是通过这种方式实现的。但对于没有与Spring整合过的工厂类,我们一般都是自己用代码来管理的。
//实例工厂,创建User对象
public class NewUserFactory {
public User createUser() {
System.out.println("实例工厂创建了User对象!");
return new User();
}
}
<!--创建实例工厂对象-->
<bean id="userFactory" class="com.cs.factory.NewUserFactory"></bean>
<!--调用实例工厂对象中的工厂方法,将得到的对象交给ioc容器管理,并赋予id-->
<bean id="user" factory-bean="userFactory" factory-method="createUser"></bean>
factory-bean:指定此bean的工厂。让工厂生产一个bean,并赋值给此bean。
factory-method:指定factory-bean工厂中的生产方法。
它会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败
Bean的作用域其实就是指Spring给我们创建出的对象的存活范围,在配置文件中通过bean的scope属性指定
<bean id="" class="" scope="定义取值">
scope:不同属性对应的取值如下:
取值范围 | 说明 |
---|---|
singleton | 默认值,单例的。只实例化一个,当Spring核心文件被加载时实例化Bean实例 |
prototype | 多例的,调用时进行实例化,不会随着容器的创建而创建,由垃圾回收定期回收 |
request | WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中 |
session | WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中 |
global session | WEB 项目中,应用在 Portlet 环境,如果没有 Portlet 环境那么globalSession 相当于 session |
依赖注入(DI)
依赖注入就是spring IOC 容器在创建对象的时候, 给属性赋值
常见的依赖注入有:
- 构造参数进行注入,使用有参构造的方式进行创建
<!--
创建Account对象,并通过构造函数的方式,完成依赖注入
要想通过构造方法完成依赖注入,那必须在类中提供有参构造方法!
constructor-arg标签,就是通过构造方法,对属性进行注入值的标签
name属性 属性的名称
value属性 属性的值,基本类型才能使用value赋值,比如字符串、数值等
ref属性 复杂对象的引用,将引用的对象,注入到对应的属性中
-->
<bean id="student" class="com.pojo.Student"></bean>
<bean id="account" class="com.offcn.pojo.Account">
<constructor-arg name="classname" value="放牛班"></constructor-arg>
<constructor-arg name="num" value="30"></constructor-arg>
<constructor-arg name="student" ref="student"></constructor-arg>
</bean>
对应的班级类必须有配置参数的有参构造
- setter注入的方式,用set方法的方式进行注入
<!--
创建Account对象,并通过setter方法完成依赖注入!
property标签,就是通过setter方法,完成注入值的标签
name属性 属性的名称
value属性 属性的值,基本类型才能使用value赋值,比如字符串、数值等
ref属性 复杂对象的引用,将引用的对象,注入到对应的属性中,引用的对象一定要在ioc容器中
-->
<bean id="user" class="com.pojo.User"></bean>
<bean id="account" class="com.pojo.Account">
<property name="row" value="18"></property>
<property name="user" ref="now"></property>
</bean>
- P名称空间p:属性名=“”
<bean id="now" class="java.util.Date"></bean>
<bean id="account" class="com.offcn.pojo.Account" p:name="小护士" p:age="20" p:birthday-ref="now"></bean>
在xml当中引入p名称空间
xmlns:p="http://www.springframework.org/schema/p"
- SPEL 表达式注入
<bean id="user" class="com.pojo.User">
<property name="hobby" value="阿古拉"></property>
</bean>
<bean id="date" class="java.util.Date"></bean>
<bean id="account" class="com.pojo.Account">
<property name="name" value="#{user.getHobby()}"></property>
<property name="age" value="#{10086}"></property>
<property name="birthday" value="#{date}"></property>
</bean>
(1) 底层是调用了set方法
(2) #{} spring EL 语法 #{id.方法} #{id.属性} #{普通属性} #{类}
(3) 不管是普通属性或者是对象属性, 都使用value 赋值。