1.spring基础知识讲解
引言:以下记录一些自己在使用时pringle框架时的一些自己心得合成体会时,如有侵权,请联系本博主。
1. spring基本都使用
spring是一个开源的轻量级框架,其目的是用于简化企业级应用程序开发,降低侵入性;
spring提供的IOC和AOP功能,可以将组件的耦合度降至最低,便于系统日后的维护和升级。
在spring中,任何的java类和JavaBean都被当成Bean处理,这些Bean通过容器管理和使用。
1.1 最基本的spring的使用
spring容器有BeanFactory和ApplicationContext两种类型,ApplicationContext接口继承自BeanFactory接口,拥有更多的
企业级方法,推荐使用该类型。 ClassPathXmlApplicationContext是ApplicationContext的一个实现类。
(1) spring容器实例化:创建spring的IOC容器对象
@Test //测试使用无参构造器创建对象 public void test1(){ //启动spring容器 ApplicationContext ac=new ClassPathXmlApplicationContext("config/basic.xml"); //调用容器的方法来获取对象 //方法的返回值类型是object,所以要强转,或者调用重载的方法(多传一个参数), //反射,这是一个class对象,告诉它返回类型. ExampleBean eb=ac.getBean("eb",ExampleBean.class); System.out.println(eb); }
说明:参数值config/basic.xml是spring配置文件的位置
(2) bean的实例化:在创建spring的IOC容器对象的时候,它会调用basic.xml中配置的bean(HelloWorld)的构造器进行初始化,
同时会调用属性的set方法对属性进行赋值();
<!-- 使用无参构造器创建对象 :告诉容器你要创建哪个对象--> <!-- id 属性:bean的名称,要求唯一。 class属性:bean的完整的类名(要求包含包名)。 --> <bean id="eb" class="basic.ExampleBean"/> <!-- 这里写的是包含ExampleBean类的那个包名 -->
java类ExampleBean如下:
package basic; public class ExampleBean { public ExampleBean() { System.out.println("ExampleBean's 无参构造"); } }
除了使用构造器来实例化对象(主要方式),还可以使用以下两种方式来实例化对象(了解):

<!-- 使用静态工厂的方法创建对象 --> <!-- factory-method属性:指定一个静态方法 注:spring容器会调用指定静态方法来创建对象 --> <bean id="cal" class="java.util.Calendar" factory-method="getInstance"/> <!-- 使用实例工厂方法创建对象 --> <!-- factory-bean属性:某个bean的id。 factory-method属性:指定一个实例方法。 --> <bean id="date1" factory-bean="cal" factory-method="getTime"/>
1.2 bean的作用域、生命周期以及延迟实例化

<!-- 配置作用域 --> <!-- scope属性:默认值是singleton(单例,即容器针对一个bean的配置,只会创建一个实例)。 如果值是prototype(原型,会创建多个实例)--> <bean id="stu1" class="basic.Student" scope="prototype"/> <!-- 配置生命周期相关的两个方法 --> <!-- init-method属性:初始化方法名 destroy-method属性:销毁方法的名称,只有作用域为单例的bean,销毁方法才会执行--> <bean id="mb1" class="basic.MessageBean" init-method="init" destroy-method="destroy" /><!-- 告诉容器要销毁哪个方法 --> <!-- 配置延迟加载 --> <!-- 默认情况下,当spring容器启动之后,会将所有作用域为当例(singleton)先创建好 --> <bean id="lz1" class="basic.LazyBean" lazy-init="true"/> <!-- 将以上几种配置合成 --> <bean id="mb2" class="basic.MessageBean1" init-method="init" destroy-method="destroy" scope="singleton" lazy-init="false"/>

@Test public void test1(){ ApplicationContext ac=new ClassPathXmlApplicationContext("config/basic2.xml"); Student stu1=ac.getBean("stu1",Student.class); Student stu2=ac.getBean("stu1",Student.class); //默认情况下,对于一个bean的配置,容器只会创建一个对象(即作用域为singleton). System.out.println(stu1==stu2); } @Test //测试生命周期 public void test2(){ //启动spring容器 //ApplicationContext这个接口没有定义关闭容器的方法,所以需要用其子接口。 //AbstractApplicationContext这是ApplicationContext子接口,里面有关闭的方法。 AbstractApplicationContext ac=new ClassPathXmlApplicationContext("config/basic2.xml"); //通过容器获得对象 MessageBean mb1=ac.getBean("mb1",MessageBean.class); //调用对象的方 法 mb1.sendMsg(); //首先要先关闭容器,才销毁 ac.close(); } @Test //测试 延迟加载 public void test3(){ ApplicationContext ac=new ClassPathXmlApplicationContext("config/basic2.xml"); // 默认情况下,当spring容器启动之后,会将所有作用域为当例(singleton)先创建好 } @Test //多种配置合成在一起 public void test4(){ AbstractApplicationContext ac=new ClassPathXmlApplicationContext("config/basic2.xml"); MessageBean1 mb2=ac.getBean("mb2",MessageBean1.class); mb2.sendMsg(); ac.close(); }

package basic; public class Student { public Student() { System.out.println("Student 无参构造"); } } public class LazyBean { public LazyBean() { System.out.println("实例化:LazyBean()"); } } public class MessageBean { public MessageBean() { System.out.println("实例化:MessageBean()"); } public void init(){ System.out.println("初始化:init()");//表示获取一些资源 } public void sendMsg(){ System.out.println("调用方法:sendMsg()"); } public void destroy(){ System.out.println("销毁:destroy()"); } } public class MessageBean1 { public MessageBean1() { System.out.println("实例化:MessageBean1()"); } public void init(){ System.out.println("初始化:init()"); } public void sendMsg(){ System.out.println("调用方法:sendMsg()"); } public void destroy(){ System.out.println("销毁方法:destroy()"); } }
2. IOC (Inversion of Control,控制反转)
IOC是指程序中对象的获取方式发生了反转,由最初的new方式创建,转变为由第三方框架(spring)创建,
注入(DI),它降低了对象之间的耦合度。spring容器是采用了DI方式实现方法了IOC空字符串,IOC是spring框架的基础和核心。
2.1 DI
DI:依赖注入(Dependency Injection)的基本原理就是将一起工作具有关系运算符的对象添加,通过
构造方法参数或方法参数传入建立关联,因此容器的工作就是创建bean时注入那些依赖关系。
IOC是一种思想,而DI是实现IOC的主要技术途径。
DI主要有两种注入方式:Setter注入和构造器注入。
(1) Setter注入
通过调用无参构造器或无参static工厂方法实例化bean以后,调用该bean的setter()方法,即可实现setter方式的注入.
property属性表示采用set方式注入,既然是注入,那肯定是发生在两个组件(对象)之间。
方法一:直接注入值(value)
<bean id="computer" class="com.bean.Computer"> <property name="mainboard" value="技嘉"/> </bean>
public class Computer{ private String mainboard; // 主板 public String getMainboard(){ return mainboard; } public void setMainboard(String mainboard){ this.mainboard = mainboard; } }
方法二:引用的方式(ref),ref主要用户引用对象
<!-- 告诉spring采用无参构造器的方法创建对象B对象 --> <bean id="b1" class="ioc.B"/> <bean id="c1" class="ioc.C"/> <!-- 配置依赖注入(采用set方法) --> <!-- property属性:表示采用set方法来注入。name属性用来指定属性名(首先首字母B大写,然后在前面加set),ref属性指定属性值 --> <bean id="a1" class="ioc.A"> <!-- setB --> <property name="service" ref="c1"></property> </bean>
测试set方式注入:

@Test //测试set方法注入 public void test5(){ AbstractApplicationContext ac=new ClassPathXmlApplicationContext("config/ioc.xml"); A a1=ac.getBean("a1",A.class); a1.execute(); }

package ioc; import ioc.Service; public interface Service { public void f1(); } public class B implements Service{ public B(){ System.out.println("B()"); } public void f1(){ System.out.println("B's f1()"); } } public class C implements Service{ public C(){ System.out.println("C()"); } public void f1(){ System.out.println("C's f1()"); } } public class A { private Service service; //容器调用对象提供的set方法来建立依赖关系 //1.类应该提供有对应的set方法 //2.在配置文件中,使用property元素来配置依赖关系 public void setService(Service service) { System.out.println("setService()"); this.service = service; } public A(){ System.out.println("A()"); } public void execute(){ service.f1(); } }

//执行结果 B() C() A() setService() C's f1()
(2) 构造器注入(使用相对较少)
基于构造器的注入是通过调用带参数的构造器来实现,容器在bean被实例化的时候,根据参数类型执行相应的构造器。
构造器注入,可以强制给bean注入某些参数,比set注入更严格。
构造器的注入一般格式为:
方法一:直接注入值(value)
按构造参数索引指定注入
<bean id=''phone" class="com.bean.MobilePhone"> <constructor-arg index="0"> value="ARM"/> //当然这里也可以采用ref去引用另外的bean,但是采用ref的时候主要用于引用对象 <constructor-arg index="1"> value="2G"/> </bean>
public class MobilePhone{ private String cpu; private String ram; //构造方法 public MobilePhone(String cpu,String ram){ this.cpu = cpu; this.ram = ram; } }
方法二:采用引用的方式(ref)

<!-- 配置依赖注入(采用构造器方式注入) --> <!-- index属性:指定参数的位置(从0开始). --> <bean id="wt1" class="ioc.Waiter" /> <bean id="rest1" class="ioc.Restaurant" > <!-- 将ref传到构造方法的第一个参数上 --> <constructor-arg index="0" ref="wt1"></constructor-arg> </bean>

@Test //测试构造器注入 public void test6(){ AbstractApplicationContext ac=new ClassPathXmlApplicationContext("config/ioc.xml"); Restaurant rest1=ac.getBean("rest1",Restaurant.class); System.out.println(rest1); }

1 package ioc; 2 3 import ioc.Waiter; 4 5 public class Waiter { 6 7 public Waiter() { 8 System.out.println("Waiter()"); 9 } 10 11 } 12 13 public class Restaurant { 14 private Waiter wt; 15 16 public Restaurant(){ 17 System.out.println("Restaurant()"); 18 } 19 public Restaurant(Waiter wt) { 20 System.out.println("Restaurant(wt)"); 21 this.wt = wt; 22 } 23 24 @Override 25 public String toString() { 26 return "Restaurant [wt=" + wt + "]"; 27 } 28 29 }

//执行结果 Waiter() Restaurant(wt) Restaurant [wt=ioc.Waiter@5f282abb]
2.2 自动装配
<bean id="wt1" class="ioc.Waiter"/> <!-- 自动装配 :默认情况下,容器禁止自动装配。--> <!-- (1)byName:以属性名(wt)作为bean的id,查找配置文件,找到之后,会使用set方法来注入。 注: 找不到会注入null值, 不会找到多个符合条件的bean。 (2)byType:以属性类型(Waiter)作为bean的类型,查找配置文件(ioc.Waiter),找到之后,会使用set方法来注入。 注:找不到会注入null值,如果找到多个符合条件的bean,会出错。 (3)constructor:与byType类似,只不过会使用构造器来注入。 --> <bean id="rest" class="ioc.Restaurant" autowire="byType"/>

@Test //测试自动装配 public void test1(){ ApplicationContext ac=new ClassPathXmlApplicationContext("ioc.xml"); Restaurant rest=ac.getBean("rest",Restaurant.class ); System.out.println(rest); }

1 package ioc; 2 3 public class Restaurant { 4 private Waiter wt; 5 public Restaurant(){ 6 System.out.println("构造:Restaurant()"); 7 } 8 9 public void setWt(Waiter wt) { 10 System.out.println("setWt()"); 11 this.wt = wt; 12 } 13 14 @Override 15 public String toString() { 16 return "Restaurant [wt=" + wt + "]"; 17 } 18 } 19 20 public class Waiter { 21 public Waiter() { 22 System.out.println("构造:Waiter()"); 23 } 24 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现