新年快乐。
Spring框架应该怎么学:学Spring框架设计思想和基本使用。
Spring官网:https://spring.io/
Spring文档地址:https://docs.spring.io/spring-framework/docs/5.2.10.RELEASE/spring-framework-reference/core.html#spring-core
Spring 是 JavaEE 领域的一款轻量级、非侵入式的开源框架,该框架由Rod Johnson于 2002 年提出并随后创建(最初版本是interface21)。其目的是为了简化Java企业级应用程序开发的复杂度(简单来讲是解耦合)。
Spring是一个开源容器框架,它集成各类型的工具,通过核心的BeanFactory实现了底层的类的实例化和生命周期的管理。在整个框架中,各类型的功能被抽象成一个个的 Bean,这样就可以实现各种功能的管理,包括动态加载和切面编程。
Spring两大特性:IOC控制反转、AOP面向切面编程。
IOC(Inversion of Control):控制反转。
外部
提供对象,然后对象创建控制权由自己
转移到外部
,这就是控制反转。DI(Dependency Injection):依赖注入,在IoC容器内将有依赖关系的bean进行关系绑定。(成员变量有两种注入方式:set、构造方法)
AOP:面向切面编程,AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务处理、权限等。
Spring生态
Spring Framework(Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基)。
Spring MVC( Web应用开发)。
SpringBoot(它为 Spring 以及第三方库提供一些开箱即用的配置,简化 Spring 应用的搭建及开发过程)。
SpringCloud(基于 Spring Boot 实现的微服务框架。它并不是某一门技术,而是一系列微服务解决方案或框架的有序集合。它将市面上成熟的、经过验证的微服务框架整合起来,并通过 Spring Boot 的思想进行再封装,屏蔽掉其中复杂的配置和实现原理,最终为开发人员提供了一套简单易懂、易部署和易维护的分布式系统开发工具包)。
Spring Data (数据访问模块,对JDBC和ORM提供了很好的支持。通过它,开发人员可以使用一种相对统一的方式,来访问位于不同类型数据库中的数据)。
Spring Security (前身 Acegi,是 Spring 中较成熟的子模块之一,它是一款可以定制化的身份验证和访问控制框架)。
…
Spring Framework系统架构图
Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基。
IOC:控制反转,将bean的创建权交给spring管理。
问题分析:
哪些对象需要管理?(service与dao)
如何将被管理的对象告知IOC容器?(配置文件或注解)
被管理的对象交给IOC容器,如何获取到IoC容器?(使用Spring提供的API)
IOC容器得到后,如何从容器中获取bean?(使用Spring提供的API)
使用Spring需要导入哪些依赖坐标?(spring-context)
IOC快速入门:
1、创建一个maven工程。
2、导入Spring依赖坐标。
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.10.RELEASEversion>
dependency>
3、定义Spring管理的类(接口和实现类)
(1) 编写BookDao接口和BookDaoImpl实现类
package com.baidou.dao;
public interface BookDao {
void save();
}
package com.baidou.dao;
public class BookDaoImpl implements BookDao {
@Override
public void save() {
System.out.println("bookDao save~");
}
}
(2) 编写BookService接口和BookServiceImpl实现类
package com.baidou.service;
public interface BookService {
void save();
}
package com.baidou.service;
import com.baidou.dao.BookDao;
import com.baidou.dao.BookDaoImpl;
public class BookServiceImpl implements BookService {
// 传统的依赖注入写法:直接在成员变量处创建对象、为成员变量提供set方法、通过构造器为成员变量初始化
private BookDao bookDao = new BookDaoImpl();
@Override
public void save() {
System.out.println("bookService save...");
bookDao.save();
}
}
4、创建spring配置文件,配置spring管理的bean对象。
定义applicationContext.xml配置文件,并对并BookServiceImpl进行配置。
<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="bookService" class="com.baidou.service.BookServiceImpl">bean>
beans>
注意事项:bean定义时,id属性在同一个spring配置文件(IOC容器中)不能重复出现。
5、初始化IOC容器(Spring容器),通过容器获取Bean对象。
package com.baidou;
import com.baidou.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Application {
public static void main(String[] args) {
// 1.创建IoC容器对象,加载spring核心配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//System.out.println(ctx);//org.springframework.context.support.ClassPathXmlApplicationContext@1d56ce6a 表示ioc容器对象已经成功创建
// 2. 从IOC容器中获取Bean对象 (例如我们配置的BookService对象)
BookService bookService = (BookService) ctx.getBean("bookService"); // 通过id获取bean
// 也可以通过name获取bean
// 也可以通过类型获取bean: ctx.getBean(BookService.class)
// 3.调用Bean对象(BookService对象)的方法
bookService.save();
}
}
DI:依赖注入,在spring容器中将bean的依赖关系绑定。(给bean设置成员变量)
DI使用分析:
DI快速入门:
1、为成员变量提供setter方法
package com.baidou.service;
import com.baidou.dao.BookDao;
import com.baidou.dao.BookDaoImpl;
public class BookServiceImpl implements BookService {
// private BookDao bookDao=new BookDaoImpl();
private BookDao bookDao;
// 提供set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void save() {
System.out.println("bookService save...");
bookDao.save();
}
}
2、在spring配置文件中,配置service与dao的依赖关系。
<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="bookService" class="com.baidou.service.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
bean>
<bean id="bookDao" class="com.baidou.dao.BookDaoImpl">bean>
beans>
注意:在spring中通过setter注入的属性的话,就必须为该属性提供对应的set方法。
3、测试
<bean id="bookService" class="com.baidou.service.BookServiceImpl">bean>
<bean id="bookDao" class="com.baidou.dao.BookDaoImpl">bean>
我们知道bean标签的id属性可以定义bean的名字,那么name属性就可以定义bean的别名。
bean的别名可以定义多个,多个别名之间用 逗号(,)、分号(; ) 、空格分隔。
<bean id="bookService" name="service bookServiceImpl" class="com.baidou.service.BookServiceImpl">bean>
<bean name="dao,bookDaoImpl" class="com.baidou.dao.BookDaoImpl">bean>
注意:无论通过id还是name获取bean,如果容器中找不到bean,就会抛出异常:NoSuchBeanDefinitionException。(没有这样的bean)
示例:别名的使用
通过bean标签的scope属性定义bean作用范围,常用的scope属性值有:
扩展:scope的取值不仅仅只有singleton和prototype,还有request、session、global session等 ,表示创建出的对象放置在web容器(tomcat)对应的位置。比如:request表示保存到request域中。
示例:
小结
bean的配置:
scope:作用范围(单实例还是多实例) 默认单实例。
name:别名。(不常用)
init-method和destory-method:生命周期。(了解即可)
传统创建对象的方式:
- new 类名() ; // 调用无参构造器。
- 工厂类.方法(); // 调用某个类的静态方法
- 某个对象.方法(); //调用某个对象的普通方法创建目标对象。例如 sqlSessionFactory.openSession();
- 反射
- 序列化
- …
Bean的实例化方式有四种:构造方法方式、静态工厂方式、实例工厂方式、实现FactoryBean
方式(扩展)。
bean本质上就是对象,可以通过构造方法方式实例化bean。(重点)
1、为实现类BookDaoImpl提供一个构造方法
public class BookDaoImpl implements BookDao {
// 显示定义一个无参构造方法
public BookDaoImpl() {
System.out.println("bookDao的构造方法执行了~");
}
@Override
public void save() {
System.out.println("bookDao save~");
}
}
2、配置bean:
<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="bookDao" class="com.baidou.dao.BookDaoImpl"/>
beans>
3、编写测试
public class Application {
public static void main(String[] args) {
// 创建IOC容器对象,并加载spring核心配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取容器中的bean对象
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// 调用bean的方法
bookDao.save();
}
}
注意:如果定义了有参构造器方法,没有提供无参构造方法,就会抛出异常:BeanInstantiationException(bean实例化异常)
通过示例静态工厂方式实例化bean。
1、定义接口和实现类
package com.baidou.dao;
public interface OrderDao {
public void save();
}
package com.baidou.dao;
public class OrderDaoImpl implements OrderDao {
public void save() {
System.out.println("orderDao save ...");
}
}
2、编写工厂类
package com.baidou.factory;
import com.baidou.dao.OrderDao;
import com.baidou.dao.OrderDaoImpl;
// 静态工厂创建对象
public class OrderDaoFactory {
public static OrderDao getOrderDao() {
return new OrderDaoImpl() ;
}
}
3、在applicationContext.xml中,配置bean:
<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="orderDao" class="com.baidou.factory.OrderDaoFactory" factory-method="getOrderDao"/>
beans>
4、编写测试
package com.baidou;
import com.baidou.dao.OrderDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Application {
public static void main(String[] args) {
// 创建IOC容器对象,并加载spring核心配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取容器中的bean对象
OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
// 调用bean的方法
orderDao.save();
}
}
通过实例工厂方式实例化bean。
1、定义接口和实现类
package com.baidou.dao;
public interface UserDao {
public void save();
}
package com.baidou.dao;
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("userDao save ...");
}
}
2、编写工厂类
package com.baidou.factory;
import com.baidou.dao.UserDao;
import com.baidou.dao.UserDaoImpl;
//实例工厂创建对象
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
3、在applicationContext.xml中,配置bean:
<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="userFactory" class="com.baidou.factory.UserDaoFactory"/>
<bean id="userDao" factory-bean="userFactory" factory-method="getUserDao">bean>
beans>
4、编写测试
public class Application {
public static void main(String[] args) {
// //创建实例工厂对象
// UserDaoFactory userDaoFactory = new UserDaoFactory();
// //通过实例工厂对象创建对象
// UserDao userDao = userDaoFactory.getUserDao();
// userDao.save();
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.save();
}
}
spring底层会用
1、定义UserDaoFactoryBean类,去实现FactoryBean
//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
// 重写接口中的两个方法
//代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
public Class<?> getObjectType() {
return UserDao.class;
}
}
2、配置bean:
<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="userDao" class="com.baidou.factory.UserDaoFactoryBean"/>
<beans/>
3、编写测试:
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.save();
}
}
小结:
bean实例化方式:构造器方式(无参构造)。
生命周期:就是从创建到消亡的完整过程。
bean生命周期:bean从创建到销毁的整体过程。
bean生命周期控制:bean从创建后到销毁前做一些事情。
1、提供声明周期方法(init和destory方法)
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("bookDao save ...");
}
//表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("destory...");
}
}
2、在spring核心配置文件中,配置生命周期控制方法:
<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="bookDao" class="com.baidou.dao.BookDaoImpl" init-method="init" destroy-method="destory"/>
beans>
3、编写测试
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook(); //优雅的关闭容器写法:先注册一下,当这些代码全部执行完毕后就销毁容器
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
// 若想执行destory销毁方法,需要关闭spring容器
//ctx.close(); //缺点:close()方法必须放在最后一行执行
}
}
/*
当创建spring容器的时候,默认它会将配置文件中的所有单实例对象都创建好,且放入spring容器中;
若配置init-method、destroy-method,就会去调用指定的方法。
*/
单实例的话,也可以在bean标签中配置lazy-init="true"
,表示用的时候创建bean。
多实例的话,用的时候才会去创建bean,bean的销毁由垃圾回收机制处理。
实现InitializingBean、DisposableBean接口,重写接口中的两个方法:destroy、afterPropertiesSet
package com.baidou.dao;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean {
public BookDaoImpl() {
System.out.println("bookDao 无参构造方法执行了");
}
public void save() {
System.out.println("bookDao save ...");
}
// 在bean对象销毁前要执行的方法
@Override
public void destroy() throws Exception {
System.out.println("destroy ...");
}
// 在bean设置完属性之后会执行的方法 (相当于init-method配置)
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("init ...");
}
}
<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="bookDao" class="com.baidou.dao.BookDaoImpl">bean>
beans>
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook(); //优雅的关闭容器方式:先注册一下,当这些代码全部执行完毕后就销毁容器
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
1、初始化容器
2、创建对象(内存分配)
3、执行构造方法
4、执行属性注入(set操作)
5、执行bean初始化方法:
6、使用bean执行业务操作
7、关闭/销毁容器之前执行bean销毁方法:
IOC容器关闭前才会触发bean的销毁。
关闭容器的两种方式:
1、手动关闭容器:通过ConfigurableApplicationContext
接口的close()
方法。
2、注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机:通过ConfigurableApplicationContext
接口的registerShutdownHook()
方法。
依赖注入有两种方式:setter方式、构造器方式。
setter方式:
- 在类中提供给成员变量提供setter方法。
- 在配置文件中通过
。 - ref:注入引用类型。
- value:注入简单类型。
package com.baidou.service;
import com.baidou.dao.BookDao;
public class BookServiceImpl implements BookService {
private BookDao bookDao;
// 为成员变量提供set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void save() {
System.out.println("bookService save...");
}
}
<bean id="bookService" class="com.baidou.service.BookServiceImpl">
<property name="bookDao" ref="bookDao">property>
bean>
<bean class="com.baidou.dao.BookDaoImpl" id="bookDao">bean>
package com.baidou.dao;
public class BookDaoImpl implements BookDao {
// 定义简单类型成员变量
private int connectionNumber;
// 提供set方法
public void setConnectionNumber(int connectionNumber) {
this.connectionNumber = connectionNumber;
}
public void save() {
System.out.println("bookDao save ...");
}
}
<bean class="com.baidou.dao.BookDaoImpl" id="bookDao">
<property name="connectionNumber" value="10"/>
bean>
构造器方式:
- 在类中提供给成员变量赋值的构造器。
- 在配置文件中通过
。 - ref:注入引用类型。
- value:注入简单类型。
package com.baidou.service;
import com.baidou.dao.BookDao;
public class BookServiceImpl implements BookService {
private BookDao bookDao;
// 提供无参构造器
public BookServiceImpl() {}
// 通过带参构造器
public BookServiceImpl(BookDao bookDao) {
this.bookDao = bookDao;
}
@Override
public void save() {
System.out.println("bookService save...");
}
}
<bean id="bookService" class="com.baidou.service.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
bean>
<bean class="com.baidou.dao.BookDaoImpl" id="bookDao">bean>
public class BookDaoImpl implements BookDao {
// 定义简单类型成员变量
private int connectionNumber;
private String databaseName;
// 提供无参构造器
public BookDaoImpl() {}
// 提供带参构造器
public BookDaoImpl(int connectionNumber, String databaseName) {
this.connectionNumber = connectionNumber;
this.databaseName = databaseName;
}
public void save() {
System.out.println("bookDao save ...");
}
}
<bean class="com.baidou.dao.BookDaoImpl" id="bookDao">
<constructor-arg name="connectionNumber" value="10"/>
<constructor-arg name="databaseName" value="redis"/>
bean>
1、通过constructor-arg标签的type属性设置按照形参类型注入:
<bean class="com.baidou.dao.BookDaoImpl" id="bookDao">
<constructor-arg type="int" value="10"/>
<constructor-arg type="java.lang.String" value="redis"/>
bean>
2、通过constructor-arg标签的index属性设置按照形参位置注入:
<bean class="com.baidou.dao.BookDaoImpl" id="bookDao">
<constructor-arg index="0" value="10"/>
<constructor-arg index="1" value="mysql"/>
bean>
依赖注入方式选择:
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配。(后面会用@autowire注解实现)
自动装配方式有:
在配置文件中,通过bean标签的autowire属性设置自动装配的类型:(给成员变量提供setter方法)
<bean id="bookDao" class="com.baidou.dao.BookDaoImpl"/>
<bean id="bookService" class="com.baidou.service.BookServiceImpl" autowire="byType"/>
依赖自动装配特征:
property标签通过setter方式注入,内部可以写
、 、
、 constructor-arg标签通过构造方式注入,constructor-arg标签内部也可以写
、 、
、
单列集合:array、set、list。
双列集合:map、props。
<property name="array">
<array>
<value>1value>
<value>2value>
<value>3value>
array>
property>
<property name="list">
<list>
<value>javavalue>
<value>phpvalue>
<value>pythonvalue>
<value>c++value>
list>
property>
<property name="set">
<set>
<value>javavalue>
<value>phpvalue>
<value>pythonvalue>
<value>javavalue>
set>
property>
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="zhejiang"/>
<entry key="city" value="hangzhou"/>
map>
property>
<property name="properties">
<props>
<prop key="country">chinaprop>
<prop key="province">zhejiangprop>
<prop key="city">hangzhouprop>
props>
property>