一、前言
简单谈一谈对spring的理解。
若有错误,还望指正!如需转载,标明出处!谢谢。
二、Spring基础
1. 什么是Spring
一个开源的简化开发的框架。
2. Spring的优势
2.1 简化开发
Spring对常用的功能进行了封装和简化,简化了代码开发,提升了开发效率。
比如Spring JDBC是对JDBC的封装。通过简单的配置,可实现JDBC的功能,还不用考虑获取连接、关闭连接等情况。
2.2 管理对象
Spring提供了一个容器,帮我们管理对象,如创建对象、管理对象间的依赖关系。
如此,降低了对象间的耦合度,便于代码维护。
2.3 集成其他框架
Spring还提供了对其他框架的集成功能,当现有功能不够用的时候,可以将其他优秀框架集成进来。
比如任务调度 Quartz。
3. Spring容器
3.1 准备工作
使用Spring需要先导入jar包,用maven导入spring-webmvc。
在resources下创建spring.xml文件。此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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
</beans>
3.2 创建对象
Spring创建对象有多种方式,包括使用无参构造器创建、使用静态工厂方式创建、使用实例工厂方式等。无参构造器方式是需要重点掌握的,下面会详细说明步骤。另外的方式也会简要说明。
3.2.1 创建类(使用无参构造器)
在java的spr包下创建一个实体类Student。该类中包含一个无参的构造方法及一个普通的say方法。构造方法用于表示对象是否创建,say()用于展示该对象是否成功创建且可使用。
代码如下。
package spr;
public class Student {
public Student(){
System.out.println("Student()");
}
public void say(){
System.out.println("say()");
}
}
3.2.2 编写Spring配置
在spring.xml配置文件的beans根节点中,敲下如下代码。
<bean id="stu" class="spr.Student"></bean>
id是bean的唯一标识,要求唯一。
class为类的全限定名。
3.2.3 启动Spring并测试
此处使用junit进行测试。
启动Spring容器使用的是ApplicationContext接口,它的实现类为ClassPathXmlApplicationContext。
代码如下。
package mytest;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spr.Student;
public class MyTest {
@Test
public void t1(){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
Student stu = ac.getBean("stu",Student.class);
stu.say();
}
}
3.2.4 测试结果
如下为测试结果,可见容器是调用了Student类的无参构造器创建对象的,并且对象成功创建,并调用了say().
Student()
say()
3.2.5 使用静态工厂方式
以上是使用无参构造器的方式创建对象,还可以使用静态工厂的方式创建对象。
spring容器中有如下代码。
<bean id="c1" class="java.util.Calendar" factory-method="getInstance"></bean>
util下的Calendar的getInstance是静态方法,此处需要使用factory-method。
测试对象
@Test
public void t2(){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
Calendar c1 = ac.getBean("c1",Calendar.class);
System.out.println(c1);
}
测试结果
java.util.GregorianCalendar[time=1615282039257,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="GMT+08:00",offset=28800000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2021,MONTH=2,WEEK_OF_YEAR=11,WEEK_OF_MONTH=2,DAY_OF_MONTH=9,DAY_OF_YEAR=68,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=27,SECOND=19,MILLISECOND=257,ZONE_OFFSET=28800000,DST_OFFSET=0]
根据测试结果,可见使用对象成功创建!
3.2.6 使用实例工厂方式
使用实例工厂需要类中有一个方法能返回一个类的实例。代码如下。
public class Student {
public Student say(){
System.out.println("say()");
return new Student();
}
}
spring.xml:
通过spr.Student的say获取一个Student的实例stu2
<bean id="stu" class="spr.Student"></bean>
<bean id="stu2" factory-bean="stu" factory-method="say"></bean>
测试:
@Test
public void t3(){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
Student stu2 = ac.getBean("stu2",Student.class);
System.out.println(stu2);
}
测试结果:
say()
spr.Student@86be70a
3.3 作用域
默认情况下,容器对bean只会创建一个实例,即单例singleton。但是我们可以通过修改scope属性为prototype来改变他的作用域,使得它可以创建多个实例。scope的值还可以是request等,此处暂不详述。
当scope为prototype时,每次获取的对象都是一个新的对象。
容器启动时,会默认创建作用域为singleton的实例。
3.4 生命周期
初始化方法:
通过init-method来指定初始化方法,指定后的方法会在类初始化时调用。
销毁方法:
通过destroy-method来指定销毁方法,指定后的方法会在实例销毁时调用。
Spring容器关闭时,会销毁对象,销毁对象前会调用销毁方法。
3.5 延迟加载
通过lazy-init来指定是否延迟加载。为true表示延迟加载。
容器在启动时,会自动加载作用域为singleton的实例,通过设置lazy-init可以让容器先不自动加载,在调用该实例时再加载。
4. IOC
4.1 什么是IOC
IOC即控制反转,对象之间的依赖关系由Spring容器控制。
4.2 DI
DI即为依赖注入。
IOC为目标,DI为手段。
4.3 Set注入
现有两个类A和B,需要将A注入到B中,需要在B中写一个setA的方法,通过set的方式将A注入进来。代码如下。
A类:
package ioc;
public class A {
public A() {
System.out.println("A()");
}
}
B类:
package ioc;
public class B {
private A a;
public B(){
System.out.println("B()");
}
//set注入
public void setA(A a){
this.a = a;
System.out.println("setA()");
System.out.println(a);//测试A是否成功注入
}
}
spring.xml:
property元素表示用set方式注入,name指属性名,ref指属性值,注入式,会将name的首字母大写,并在前面加上set,此处即setA。
<bean id="aa" class="ioc.A"></bean>
<bean id="bb" class="ioc.B">
<property name="a" ref="aa"></property>
</bean>
启动容器:
自动加载两个单例类,完成注入
@Test
public void t1(){
ApplicationContext ac = new ClassPathXmlApplicationContext("ioc.xml");
}
结果:
成功将A注入,并打印出A。
A()
B()
setA()
ioc.A@1b68ddbd
4.4 构造器注入
同样是A和B两个类,只是B中不是setA而是有一个有参数的构造器,通过该构造器进行A的注入。代码如下:
A类:
package ioc;
public class A {
public A() {
System.out.println("A()");
}
}
B类:
package ioc;
public class B {
private A a;
public B(){
System.out.println("B()");
}
//constructor注入
public B(A a){
this.a = a;
System.out.println("B(A a)");
System.out.println(a);//打印A
}
}
springx.xml
constructor-arg元素表示是构造器注入,index属性指参数的下标,从0开始,ref指属性值。
<bean id="aa" class="ioc.A"></bean>
<bean id="bb" class="ioc.B">
<constructor-arg index="0" ref="aa"></constructor-arg>
</bean>
启动容器:
@Test
public void t1(){
ApplicationContext ac = new ClassPathXmlApplicationContext("ioc.xml");
}
结果:
A()
B(A a)
ioc.A@1e965684
4.5 自动装配
指的是Spring容器按照某种规则,自动建立对象之间的依赖关系。
容器默认情况下,不会自动装配。要使用自动装配,通过autowire属性配置。
容器实质上仍然需要调用set方式或构造器方式注入。只是这个步骤通过配置autowire属性让容器自己去做了,不需要我们去写。
4.5.1 byName
容器依据属性名来查找对应的bean,然后调用对应set方法完成注入。
a.如果找不到对应的bean,注入null。
b.不可能找到多个bean的情况。因为id唯一。
4.5.2 byType
容器依据属性类型来查找对应的bean,然后调用对应set方法完成注入。
a.如果找不到对应的bean,注入null。
b.如果找到多个对应的bean,报错。
4.5.3 constructor
容器依据属性类型来查找对应的bean,然后调用对应构造器方法完成注入。
与byType相似,都是根据属性的类型去查找bean。
a.如果找不到对应的bean,注入null。
b.如果找到多个对应的bean,报错。
结束语
因为篇幅的原因,此处就写这么多,数据注入、注解等在下一章记录。
平时总觉得spring也没有什么,当去静下心记录的时候就会感觉,哇,怎么还没完呢,好多!哈哈哈,这还是没有剖析源码,敬畏代码,敬畏技术。