深入浅出 Spring(一) | Spring简介、IOC理论推导、快速上手 Spring
1. spring
1.1 简介
Spring : 春天 —>给软件行业带来了春天
2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。
2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。
很难想象Rod Johnson的学历 , 他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术
SSH:Struct2 + Spring + Hibernate!
SSM:SpringMVC + Spring + Mybatis!
官网 : http://spring.io/
Reference Doc. 为官方文档
官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/
GitHub : https://github.com/spring-projects
Spring 的 maven 依赖,在 maven 仓库中下载: 导入 Spring MVC 这个包会帮助我们导入其他很多依赖包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>6.1.12</version>
</dependency>
还有一个 Spring JDBC,
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>6.1.12</version>
</dependency>
1.2 优点
- Spring是一个开源的免费的框架(容器)!
- Spring是一个轻量级的、非入侵式的框架!
- 控制反转(IOC),面向切面编程(AOP)!
- 支持事务的处理,对框架整合的支持!
总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP
1.3 组成
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 .
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
- 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
- Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
- Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
- Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
- Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
- Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
- Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
工厂模式总结
1.4 拓展
现代化的Java开发!说白就是基于Spring的开发!
Spring Boot与Spring Cloud
- Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务;
- Spring Cloud是基于Spring Boot实现的;
- Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;
- Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
- SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。
因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC!承上启下的作用!
弊端: 发展了太久之后,违背了原来的理念!配置十分繁琐,人称:“配置地狱!”
2、IOC理论推导
1.5 IoC基础
新建一个空白的 maven 项目 spring-study 作为父工程,删除 src 文件,并导入 spring mvc 和 spring jdbc 的包
创建一个 spring01-ioc1 作为子项目
1.5.1 分析实现
我们先用我们原来的方式写一段代码 .
1、先写一个UserDao接口
package com.lqh.dao;public interface UserDao {void getUser();
}
2、再去写Dao的实现类
package com.lqh.dao;public class UserDaoImpl implements UserDao {@Overridepublic void getUser() {System.out.println("获取用户数据");}
}
3、然后去写UserService的接口
package com.lqh.service;public interface UserService {public void getUser();
}
4、最后写Service的实现类
package com.lqh.service;import com.lqh.dao.UserDao;
import com.lqh.dao.UserDaoImpl;public class UserServiceImpl implements UserService {private UserDao userDao = new UserDaoImpl();@Overridepublic void getUser() {userDao.getUser();}
}
5、测试一下
@Test
public void test01() {//用户实际调用的是业务层,dao层他们不需要接触!UserService userService = new UserServiceImpl();userService.getUser();
}
这是我们原来的方式 , 开始大家也都是这么去写的对吧 . 那我们现在修改一下 .
把Userdao的实现类增加一个 .
package com.lqh.dao;public class UserDaoMySqlImpl implements UserDao {@Overridepublic void getUser() {System.out.println("MySql获取用户数据");}
}
紧接着我们要去使用 MySql 的话 , 我们就需要去 service 实现类里面修改对应的实现
package com.lqh.service;import com.lqh.dao.UserDao;
import com.lqh.dao.UserDaoImpl;
import com.lqh.dao.UserDaoMySqlImpl;public class UserServiceImpl implements UserService {private UserDao userDao = new UserDaoMySqlImpl();@Overridepublic void getUser() {userDao.getUser();}
}
调用测试
@Test
public void test01() {//用户实际调用的是业务层,dao层他们不需要接触!UserService userService = new UserServiceImpl();userService.getUser();
}
在假设, 我们再增加一个Userdao的实现类,以操作 Oracle 数据库
public class UserDaoOracleImpl implements UserDao {@Overridepublic void getUser() {System.out.println("Oracle获取用户数据");}
}
那么我们要使用Oracle , 又需要去service实现类里面修改对应的实现 . 假设我们的这种需求非常大 , 这种方式就根本不适用了, 甚至反人类对吧 , 每次变动 , 都需要修改大量代码 . 这种设计的耦合性太高了, 牵一发而动全身 .
那我们如何去解决呢 ?
我们可以在需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用 set , 我们去代码里修改下
UserServiceImpl,
public class UserServiceImpl implements UserService {private UserDao userDao;// 利用set进行实现动态值的注入public void setUserDao(UserDao userDao) {this.userDao = userDao;}@Overridepublic void getUser() {userDao.getUser();}
}
现在去我们的测试类里 , 进行测试 ;
@Test
public void test(){UserServiceImpl service = new UserServiceImpl();service.setUserDao( new UserDaoMySqlImpl() );service.getUser();//那我们现在又想用Oracle去实现呢service.setUserDao( new UserDaoOracleImpl() );service.getUser();
}
大家发现了区别没有 ? 可能很多人说没啥区别. 但是注意, 他们已经发生了根本性的变化 , 很多地方都不一样了. 仔细去思考一下 , 以前所有东西都是由程序去进行控制创建 , 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建, 怎么实现了. 它只负责提供一个接口 .
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!
我们使用一个Set接口实现,已经发生了革命性的变化!
private UserDao userDao;//利用set进行动态实现值的注入!
public void setUserDao(UserDao userDao) {this.userDao = userDao;
}
- 之前,程序是主动创建对象!控制权在程序猿手上!
- 使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象!
这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !
如果现在想要访问 sqlServer 数据库,在 dao 层下
package com.lqh.dao;public class UserSqlseverImpl implements UserDao{@Overridepublic void getUser() {System.out.println("Sqlsever 获取用户数据");}
}
只需要在执行测试的时候,如下即可,没有改动 service 层源码!!!,只是增加了一个类,程序架构没有去改动,即没有改动原有的代码,这是控制反转 IOC 的原型
service.setUserDao( new UserSqlseverImpl() );
service.getUser();
以前撰写的代码主动权在业务层(service 层)左图,现在主动权在用户右图
1.5.2 IOC本质
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
- 对于图1,A, B, C, D 具有耦合性,我们希望能有个中间件直接调用所有组件,诞生了图2中间那个 IOC 容器,IOC 容器去连接对象 A, B, C, D …
- 图 3,所有对象不再具有耦合性,我们想调用谁就调用谁
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
官方的图:
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
2:快速上手 Spring
上一期中我们理解了IOC的基本思想,我们现在来看下Spring的应用:
新建子项目:spring-02-hellospring
2.1 HelloSpring
2.1.1 导入Jar包
注 : spring 需要导入 commons-logging 进行日志记录 . 我们利用 maven , 他会自动下载对应的依赖项 .
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.10.RELEASE</version>
</dependency>
2.1.2 编写代码
1、编写一个Hello实体类
package com.lqh.pojo;public class Hello {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void show(){System.out.println("Hello,"+ name );}
}
2、编写我们的 spring 文件, 这里命名为 beans.xml,并放置在资源文件 resources 下
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--bean就是java对象 , 由Spring创建和管理--><!-- 使用 Spring 来创建对象,在 Spring 中,这些都称为Bean--><bean id="hello" class="com.lqh.pojo.Hello"><property name="name" value="Spring"/></bean></beans>
3、我们可以去进行测试了.
@Test
public void test(){//解析beans.xml文件 , 生成管理相应的Bean对象ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//getBean : 参数即为spring配置文件中bean的id .Hello hello = (Hello) context.getBean("hello");hello.show();
}
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--bean就是java对象 , 由Spring创建和管理--><!--使用 Spring 来创建对象,在 Spring 中,这些都称为Bean--><!--传统实例方式:类型 变量名 = new 类名()比如:Hello hello = new hello()bean 标签:id = 变量名,class = new 的对象property 相当于给对象中的属性设置了一个值,--><bean id="hello" class="com.lqh.pojo.Hello"><property name="name" value="Spring"/></bean></beans>
如果在运行过程中出现如下错误,是 jdk 版本与 spring 版本冲突,需要将 spring 版本降至 5.x 即可
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.22</version>
</dependency>
实际上就是通过 set 注入实现的,如果我们将实体类 Hello 中的 set 方法注释掉,再运行测试类,则会报错
2.1.3 思考
- Hello 对象是谁创建的 ? 【hello 对象是由Spring创建的
- Hello 对象的属性是怎么设置的 ? hello 对象的属性是由Spring容器设置的
这个过程就叫控制反转 :
- 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
- 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
依赖注入 : 就是利用set方法来进行注入的.
IOC是一种编程思想,由主动的编程变成被动的接收
可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .
到了现在,不用在程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IOC,一句话搞定:对象由Spring来创建,管理,装配!
2.1.4 修改案例一
前面 spring01-ioc1 中 的代码涉及 4 个实现类,现在我们通过 Spring 来实现
我们在案例一 spring01-ioc1 中, 新增一个Spring配置文件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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="MysqlImpl" class="com.kuang.dao.impl.UserDaoMySqlImpl"/><bean id="OracleImpl" class="com.kuang.dao.impl.UserDaoOracleImpl"/><bean id="ServiceImpl" class="com.kuang.service.impl.UserServiceImpl"><!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写--><!--引用另外一个bean , 不是用value 而是用 ref--><property name="userDao" ref="OracleImpl"/></bean></beans>
案例一 spring01-ioc1 中 UserServiceImpl 如下:
public class UserServiceImpl implements UserService {private UserDao userDao;// 利用set进行实现动态值的注入public void setUserDao(UserDao userDao) {this.userDao = userDao;}@Overridepublic void getUser() {userDao.getUser();} }
在上述Spring XML配置中,主要展示了Spring的依赖注入(Dependency Injection,DI)机制,具体过程如下:
1. 加载配置文件
Spring容器会首先加载
beans.xml
配置文件。在加载过程中,Spring会解析XML文件中的内容,识别其中定义的<bean>
元素及其属性。2. 创建Spring容器
Spring容器会基于配置文件的内容创建一个容器实例,通常是
ApplicationContext
的一个实现类(例如ClassPathXmlApplicationContext
)。这个容器管理着整个应用程序中所有的Bean(即类的实例),并且负责它们的生命周期管理。3. 解析Bean定义
每个
<bean>
元素都定义了一个Bean,它包含了Bean的唯一标识符(id
)和对应的类(class
)。在此配置文件中,定义了3个Bean:
MysqlImpl
:对应com.kuang.dao.impl.UserDaoMySqlImpl
类OracleImpl
:对应com.kuang.dao.impl.UserDaoOracleImpl
类ServiceImpl
:对应com.kuang.service.impl.UserServiceImpl
类4. 实例化Bean
- Spring会根据
class
属性的值(即类的全名)创建相应的类的实例。Spring会调用类的无参构造方法实例化对象。此时,MysqlImpl
和OracleImpl
是直接创建的,而ServiceImpl
的实例化还涉及到依赖注入。5. 依赖注入
- 注入方式:
ServiceImpl
类的userDao
属性需要注入一个UserDao
类型的实现,配置文件中的<property>
元素负责实现这一注入。name
属性:name="userDao"
指定的是ServiceImpl
类中userDao
属性的名称,这个名称会对应到UserServiceImpl
类中的setUserDao()
方法。ref
属性:ref="OracleImpl"
指定了注入的Bean为OracleImpl
,这意味着Spring会将OracleImpl
实例注入到userDao
属性中。这里,OracleImpl
是一个已经在配置文件中定义的Bean,它对应com.kuang.dao.impl.UserDaoOracleImpl
类。6. 依赖注入的注解和方法调用
- Spring通过反射机制调用
UserServiceImpl
类的setUserDao()
方法,并将OracleImpl
实例传递给该方法。这是JavaBean的标准方式,通过setter方法注入依赖。- 如果
ServiceImpl
类中的userDao
属性没有指定ref
,Spring将尝试自动注入。此时,自动注入会根据类型匹配(即UserDao
接口)来选择适当的Bean进行注入,但在此例中明确使用了ref="OracleImpl"
。7. 容器中的Bean管理
- 当Spring完成所有Bean的创建和依赖注入后,
ServiceImpl
实例和它的依赖(即OracleImpl
)都会被添加到Spring容器中。- Spring容器管理这些Bean的生命周期,例如在容器关闭时会自动销毁Bean。
8. 使用Bean
- 在应用程序中,当需要使用
ServiceImpl
时,Spring容器会提供一个ServiceImpl
实例(并且userDao
已注入了OracleImpl
)。通过ApplicationContext
的getBean()
方法可以获取到这些Bean。总结来说,以上配置文件的执行过程如下:
- Spring加载XML配置文件。
- 创建并管理容器中的所有Bean。
- 创建
MysqlImpl
、OracleImpl
、ServiceImpl
的实例。- 使用
ref
进行依赖注入,将OracleImpl
实例注入到ServiceImpl
的userDao
属性。- 完成所有Bean的依赖注入和生命周期管理。
所有通过 bean 注册的类,都有个这样的标志,说明是被 spring 托管了
对于 UserServiceImpl 的注册,注意如下说明
测试!
@Test
public void test2(){// 获取 ApplicationContext,拿到 Spring 的容器ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");// 需要什么就 get 什么,直接去 Sping 容器中获取UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl");serviceImpl.getUser();
}
OK , 到了现在 , 我们彻底不用再程序中去改动了 , 要实现不同的操作 , 只需要在xml配置文件中进行修改 , 所谓的 IoC,一句话搞定 : 对象由 Spring 来创建 , 管理 , 装配 !
2.2 IOC创建对象方式
- 使用无参构造创建对象,默认!
- 假设我们要使用有参构造创建对象。
- 下标赋值
<!-- 第一种根据index参数下标设置 --> <bean id="user" class="com.lqh.pojo.User"><!-- index指构造方法 , 参数的下标从0开始 --><constructor-arg index="0" value="qingnianyouzhi"/> </bean>
- 参数名
<!-- 第二种根据参数名字设置 --> <bean id="user" class="com.lqh.pojo.User"><!-- name指参数名 --><constructor-arg name="name" value="qingnianyouzhi"/> </bean>
- 类型
<!-- 第三种根据参数类型设置 --> <bean id="user" class="com.lqh.pojo.User"><constructor-arg type="java.lang.String" value="qingnianyouzhi"/> </bean>
2.2.1 通过无参构造方法来创建
1、User.java
package com.lqh.pojo;public class User {private String name;public User() {System.out.println("user无参构造方法");}public void setName(String name) {this.name = name;}public void show() {System.out.println("name="+ name );}
}
2、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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="com.lqh.pojo.User"><property name="name" value="QianNianYouZhi"/></bean></beans>
3、测试类
import com.lqh.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyTest {@Testpublic void test(){ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//在执行getBean的时候, user已经创建好了 , 通过无参构造User user = (User) context.getBean("user");//调用对象的方法 .user.show();}}
结果可以发现,在调用show方法之前,User对象已经通过无参构造初始化了!
通过 Debug 发现,User user = (User) context.getBean(“user”); 执行完后,实例话了 User 类
无参构造默认是有的,但是当我们显示定义一个有参构造,无参构造就被去掉了,如下:
此时,运行测试:发送了报错,显示初始化失败
2.2.2 通过有参构造方法来创建
1、User. java
package com.lqh.pojo;public class User {private String name;public User(String name) {this.name = name;}public void setName(String name) {this.name = name;}public void show(){System.out.println("name="+ name );}
}
2、beans.xml 有三种方式编写
<!-- 第一种根据index参数下标设置 -->
<bean id="user" class="com.lqh.pojo.User"><!-- index指构造方法 , 参数的下标从0开始 --><constructor-arg index="0" value="qingnianyouzhi"/>
</bean><!-- 第二种根据参数名字设置 -->
<bean id="user" class="com.lqh.pojo.User"><!-- name指参数名 --><constructor-arg name="name" value="qingnianyouzhi"/>
</bean><!-- 第三种根据参数类型设置,不建议使用,如果同时两个参数都是 string 这个方式就不行了,判断不了-->
<bean id="user" class="com.lqh.pojo.User"><constructor-arg type="java.lang.String" value="qingnianyouzhi"/>
</bean>
3、测试
在测试的时候,beans.xml 的三种去掉两种
@Test
public void test(){ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");User user = (User) context.getBean("user");user.show();
}
结论:在配置文件加载的时候。其中管理的对象都已经初始化了!
下面再来一个实验
pojo 包创建一个 UserT,为无参构造方法
package com.lqh.pojo;public class UserT {private String name;public UserT() {System.out.println("UserT 被创建了");}public void setName(String name) {this.name = name;}public void show(){System.out.println("name="+ name );}}
beans.xml 下对 User 和 UserT 进行注册
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 第一种根据index参数下标设置 --><bean id="user" class="com.lqh.pojo.User"><!-- index指构造方法 , 参数的下标从0开始 --><constructor-arg index="0" value="qingnianyouzhi"/></bean><bean id="userT" class="com.lqh.pojo.UserT"><property name="name" value="QianNianYouZhi"/></bean></beans>
测试,只在 spring 容器中获取 user,而不获取 userT
@Test
public void test(){ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");User user = (User) context.getBean("user");user.show();
}
执行结果显示, UserT 的构造方法也被执行了,因此我们在创建 bean 的时候(编写 beans.xml 时),实际上已经帮助我们实例化对象了
再测试一种情况,context.getBean 相同的对象
public void test(){ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");User user = (User) context.getBean("user");User user2 = (User) context.getBean("user");System.out.println(user == user2);
}
出来的是同一个实例,说明使用了单例模式
总结: 在配置文件加载的时候,容器中管理的对象就已经初始化了!
2.3 Spring配置
2.3.1 别名
alias 设置别名 , 为 bean 设置别名 , 可以设置多个别名
<!--设置别名:在获取Bean的时候可以使用别名获取-->
<alias name="userT" alias="userNew"/>
2.3.2 Bean的配置
<!--bean就是java对象,由Spring创建和管理--><!--id 是bean的标识符,要唯一,如果没有配置id,name就是默认标识符如果配置id,又配置了name,那么name是别名name可以设置多个别名,可以用逗号,分号,空格隔开如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象;class是bean的全限定名=包名+类名
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello"><property name="name" value="Spring"/>
</bean>
2.3.3 import
团队的合作通过 import 来实现 .
<import resource="{path}/beans.xml"/>
这个import。一般用于团队开发使用,它可以将多个配置文件,导入合并为一个。
假设,现在项目中有多个人开发,这三个人负责不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!
applicationContext.xml 作为总的,其他不同的 beans.xml 由不同的人开发
相关文章:

深入浅出 Spring(一) | Spring简介、IOC理论推导、快速上手 Spring
1. spring 1.1 简介 Spring : 春天 —>给软件行业带来了春天 2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。 2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。 很难想象…...
IDEA 社区版 SpringBoot不能启动
报错原因,Failed to load class [javax.servlet.Filter] <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope> </dependency>…...

职场常用Excel基础01-数据验证
大家好,excel在职场中使用非常频繁,今天和大家一起分享一下excel中数据验证相关的内容~ 在Excel中,数据验证(Data Validation)是一项非常有用的功能,它可以帮助用户限制输入到单元格中的数据类型和范围&am…...

活动预告 |【Part1】Microsoft Azure 在线技术公开课:数据基础知识
课程介绍 参加“Azure 在线技术公开课:数据基础知识”活动,了解有关云环境和数据服务中核心数据库概念的基础知识。通过本次免费的介绍性活动,你将提升在关系数据、非关系数据、大数据和分析方面的技能。 活动时间:01 月 07 日…...

RabbitMQ - 1 ( 7000 字 RabbitMQ 入门级教程 )
一: 在互联网行业,许多公司喜欢用动物命名产品或作为公司的 Logo 和吉祥物,比如腾讯的企鹅、京东的狗、美团的袋鼠、携程的海豚,而阿里更是凭借蚂蚁、飞猪、天猫、菜鸟、闲鱼、盒马等,打造了一座“动物园”。Rabbit&a…...

Docker Compose 构建 EMQX 集群 实现mqqt 和websocket
EMQX 集群化管理mqqt真香 目录 #目录 /usr/emqx 容器构建 vim docker-compose.yml version: 3services:emqx1:image: emqx:5.8.3container_name: emqx1environment:- "EMQX_NODE_NAMEemqxnode1.emqx.io"- "EMQX_CLUSTER__DISCOVERY_STRATEGYstatic"- …...
Spring 过滤器:OncePerRequestFilter 应用详解
在Web应用中,过滤器(Filter)是一个强大的工具,它可以在请求到达目标资源之前或响应返回客户端之前对请求或响应进行拦截和处理。然而,在某些情况下,我们可能希望确保过滤器逻辑在一次完整的HTTP请求中仅执行…...

3.CSS字体属性
3.1字体系列 CSS使用font-family属性定义文本的字体系列。 p{font-family:"微软雅黑"} div{font-family:Arial,"Microsoft Yahei",微软雅黑} 3.2字体大小 css使用font-size属性定义字体大小 p{ font-size:20px; } px(像素)大小是我们网页的最常用的单…...
微信小程序 单选多选radio/checkbox 纯代码分享
单选按钮 <radio-group class"radiogroup" bindchange"radioChange"> <label class"radio" wx:for"{{items}}"> <radio value"{{item.name}}" checked"{{item.checked}}" /> {{item.value}} &…...
k8s 部署meilisearch UI
https://github.com/riccox/meilisearch-ui 拉取镜像 sudo docker pull riccoxie/meilisearch-ui:latestk8s 部署 apiVersion: v1 kind: Service metadata:name: meilisearch-uinamespace: meilisearch spec:type: NodePortselector:app: meilisearch-uiports:- port: 24900…...

gitlab 还原合并请求
事情是这样的: 菜鸡从 test 分支切了个名为 pref-art 的分支出来,发布后一机灵,发现错了,于是在本地用 git branch -d pref-art 将该分支删掉了。之后切到了 prod 分支,再切出了一个相同名称的 pref-art 分支出来&…...

ChatGPT最新版本“o3”的概要
o3简介 o3于2024年12月20日发布——也就是OpenAI 12天直播的最后一天。目前处于安全性测试阶段。它是o1的继任者,旨在处理更复杂的推理任务。o3特别针对数学、科学和编程等领域进行了优化。 o3在多项基准测试中表现出色。例如,在ARC-AGI基准测试中&…...
uniapp——App下载文件,保存、打开文件(二)
uniapp如何下载文件、保存、打开文件 时光荏苒,2024即将过去! 迈向2025,祝大家新的一年工作顺利、万事如意,少一点BUG,涨一点工资…↖(ω)↗ 文章目录 uniapp如何下载文件、保存、打开文件下载文件保存并打开文件处理 …...

Postman接口测试05|实战项目笔记
目录 一、项目接口概况 二、单接口测试-登录接口:POST 1、正例 2、反例 ①姓名未注册 ②密码错误 ③姓名为空 ④多参 ⑤少参 ⑥无参 三、批量运行测试用例 四、生成测试报告 1、Postman界面生成 2、Newman命令行生成 五、token鉴权(“…...

【paddle】初次尝试
张量 张量是 paddlepaddle, torch, tensorflow 等 python 主流机器学习包中唯一通货变量,因此应当了解其基本的功能。 张量 paddle.Tensor 与 numpy.array 的转化 import paddle as paddle import matplotlib.pyplot as plt apaddle.to_t…...

01-2023年上半年软件设计师考试java真题解析
1.真题内容 在某系统中,类 Interval(间隔) 代表由下界(lower bound(边界))上界(upper bound )定义的区间。 要求采用不同的格式显示区间范围。 如[lower bound , upper bound ]、[ lower bound … upper bound ]、[ lower bou nd - upper bound &#x…...
一文讲清楚CSS3新特性
文章目录 一文讲清楚CSS3新特性1. 新增选择器特性2. 新增的样式3. 新增布局方式 一文讲清楚CSS3新特性 1. 新增选择器特性 层次选择器(div~p)选择前面有div的p元素伪类选择器 :first-of-type 表示⼀组同级元素中其类型的第⼀个元素:last-of-type 表示⼀组同级元素中其类型的最…...

系统设计案例:设计 Spotify
https://levelup.gitconnected.com/system-design-interview-question-design-spotify-4a8a79697dda 这是一道系统设计面试题,即设计 Spotify。在真正的面试中,你通常会关注应用程序的一两个主要功能,但在本文中,我想从高层次概述…...

太速科技-633-4通道2Gsps 14bit AD采集PCie卡
4通道2Gsps 14bit AD采集PCie卡 一、板卡概述 二、性能指标 板卡功能 参数 内容 ADC 芯片型号 AD9689 路数 4路ADC, 采样率 2Gsps 数据位 14bit 数字接口 JESD204B 模拟接口 交流耦合 模拟输入 1V 连接器 6路 SMA 输入阻抗 50Ω 模拟指…...

图片叠加拖拽对比展示效果实现——Vue版
图片叠加拖拽对比展示效果实现——Vue版 项目中遇见一个需求:2张图片按竖线分割,左右两侧分别展示对应图片,通过滚动条拖动对应展示图片区域;; 网上搜索了下,没有找到直接可用的组件,这里自己封装了一个次功…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...