深入浅出 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张图片按竖线分割,左右两侧分别展示对应图片,通过滚动条拖动对应展示图片区域;; 网上搜索了下,没有找到直接可用的组件,这里自己封装了一个次功…...

结合长短期记忆网络(LSTM)和无迹卡尔曼滤波器(UKF)的技术在机器人导航和状态估计中的应用前景
结合长短期记忆网络(LSTM)和无迹卡尔曼滤波器(UKF)的技术在机器人导航和状态估计中具有广泛的应用前景。如有滤波、导航方面的代码定制需求,可通过文末卡片联系作者获得帮助 文章目录 结合LSTM和UKF的背景结合LSTM和UKF的优势应用实例研究现状MATLAB代码示例结论结合LSTM和…...

【MATLAB APP Designer】小波阈值去噪(第一期)
代码原理及流程 小波阈值去噪是一种信号处理方法,用于从信号中去除噪声。这种方法基于小波变换,它通过将信号分解到不同的尺度和频率上来实现。其基本原理可以分为以下几个步骤: (1)小波变换:首先对含噪信…...

ClickHouse副本搭建
一. 副本概述 副本的目的主要是保障数据的高可用性,ClickHouse中的副本没有主从之分。所有的副本都是平等的。 副本写入流程: 二. 副本搭建 1. 实验环境 hadoop1(192.168.47.128) hadoop2(192.168.47.129)2. 修改配置文件 修改两台主机/etc/click…...

K3知识点
提示:文章 文章目录 前言一、顺序队列和链式队列题目 顺序队列和链式队列的定义和特性实际应用场景顺序表题目 链式队列 二、AVL树三、红黑树四、二叉排序树五、树的概念题目1左子树右子树前序遍历、中序遍历,后序遍历先根遍历、中根遍历左孩子右孩子题目…...

cocos creator 3.x版本如何添加打开游戏时首屏加载进度条
前言 项目有一个打开游戏时添加载入进度条的需求。这个功能2.X版本是自带的,不知为何在3.X版本中移除了。 实现 先说一下解决思路,就是在引擎源码加载场景的位置插入一个方法,然后在游戏入口HTML处监听即可。 1.找到对应源码脚本 在coco…...

Fama MacBeth两步法与多因子模型的回归检验
Fama MacBeth两步法与多因子模型的回归检验 – 潘登同学的因子投资笔记 本文观点来自最近学习的石川老师《因子投资:方法与实践》一书 文章目录 Fama MacBeth两步法与多因子模型的回归检验 -- 潘登同学的因子投资笔记 多因子回归检验时序回归检验截面回归检验Fama–…...

IDEA 搭建 SpringBoot 项目之配置 Maven
目录 1?配置 Maven 1.1?打开 settings.xml 文件1.2?配置本地仓库路径1.3?配置中央仓库路径1.4?配置 JDK 版本1.5?重新下载项目依赖 2?配置 idea 2.1?在启动页打开设置2.2?配置 Java Compiler2.3?配置 File Encodings2.4?配置 Maven2.5?配置 Auto Import2.6?配置 C…...

node.js之---事件循环机制
事件循环机制 Node.js 事件循环机制(Event Loop)是其核心特性之一,它使得 Node.js 能够高效地处理大量并发的 I/O 操作。Node.js 基于 非阻塞 I/O,使用事件驱动的模型来实现异步编程。事件循环是 Node.js 实现异步编程的基础&…...

Python OpenAI 库开发指南:从入门到实战精通
在人工智能(AI)领域,OpenAI无疑是全球最受瞩目的机构之一。它推出的GPT系列模型、DALLE等创新技术,正在深刻改变各行各业。作为Python开发者,我们该如何快速上手并高效利用OpenAI的API,成为了提升个人竞争力…...

flash-attention保姆级安装教程
FlashAttention安装教程 FlashAttention 是一种高效且内存优化的注意力机制实现,旨在提升大规模深度学习模型的训练和推理效率。 高效计算:通过优化 IO 操作,减少内存访问开销,提升计算效率。 内存优化:降低内存占用…...