spring02之Spring IOC的基本配置使用

本文共12001字,阅读本文大概需要24~40分钟

容器概述

ApplicationContext 是 Spring IOC 容器实现的代表,它负责实例化,配置和组装Bean。容器通过读取配置元数据获取有关实例化、配置和组装哪些对象的说明。配置元数据可以使用XML、Java注解或Java代码来呈现,它允许你处理应用程序的对象与其他对象之间的互相依赖关系

配置元数据

  • 使用 Xml 的配置
    简单、直观,适合入门
  • 基于注解的配置:@Compont(@Service @Controller @Repository) @Autowride
    Spring 2.5 支持基于注解的元数据配置,SSM 框架开发中使用
  • 基于Java的配置:@Configuration @Bean @Import
    从 Spring 3.0 开始,由Spring JavaConfig项目提供的功能已经成为Spring核心框架的一部分。因此,你可以使用java配置来代替XML配置定义外部Bean
    从 Spring 4.0 开始支持springboot1.0之后springboot完全采用javaconfig的方式进行开发

容器的实例化

对象在Spring容器创建完成的时候就已经创建完成,不是需要用的时候才创建

容器的使用

ApplicationContext 是能够创建bean定义以及处理相互依赖关系的高级工厂接口,使用方法 T getBean(String name,Class<T> requiredType)获取容器实例

// 加载 spring 容器
// ApplicationContext spring的顶层核心接口
// ClassPathXmlApplicationContext 根据项目路径的xml配置来实例化spring容器
// FileSystemXmlApplicationContext 根据磁盘路径的xml配置来实例化spring容器
// AnnotationConfigApplicationContext 根据 javaconfig 来配置实例化spring容器
// 在容器实例化的时候时候 就会加载所有的bean
ApplicationContext ioc = new ClassPathXmlApplicationContext("ioc.xml");

// 在执行此句时会先执行 User 的构造方法
System.out.println("spring容器以加载");

// 获取 bean
// 1>通过类来获取bean ==> User user = ioc.getBean(User.class);
// 2>通过xml配置中名字或者id来获取bean ==> User user = (User)ioc.getBean("user");
// 3>通过名字+id来获取bean ==> User user = ioc.getBean("user",User.class);
// 区别于第一种,若xml配置中出现多个完全限定名完全相同仅id不同的bean,需要采用第3种指定,若使用第1种会发生异常:
// NoUniqueBeanDefinitionException: No qualifying bean of type 'com.ydj.spring.beans.User' available: expected single matching bean but found 2: user,user1
User user = ioc.getBean(User.class);
System.out.println(user);

bean的概述

学习之前的环境搭建

  • 实体类
public class User {
    private int id;
    private String username;
    private String realname;

    // 这里省略 setter,getter,toString 方法
    // 省略有参无参函数

}
  • 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/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
  • 测试代码
public class IocTest {

    ApplicationContext ioc = null;

    @Before
    public void before() {
        // 加载 spring 容器
        ioc = new ClassPathXmlApplicationContext("ioc.xml");
    }

    @Test
    public void test02() {
	// 这里书写测试代码
    }

}

命名bean

<!--
	命名bean
		在使用name获取bean的时候 ioc.getBean(name)
		无论是user还是user2甚至是xiaoyang都能正确获取到
		eg: ioc.getBean("xiaoyang")
-->
<bean class="com.ydj.spring.beans.User" name="user user2,xiaoyang"/>
  • 为外部定义的bean起别名
<bean class="com.ydj.spring.beans.User" id="uu"/>

<!--
	为外部定义的bean起别名
	注意: alias的name为外部bean的id
-->
<alias name="uu" alias="user666"></alias>

实例化bean

  • 使用构造器实例化(默认)
    无法干预实例化的过程
  • 使用静态工厂方法实例化
<bean class="com.tuling.service.impl.UserServiceImpl" id="userService2" facto‐method="createUserServiceInstance">
</bean>
public static UserServiceImpl createUserServiceInstance(){ 
    return new UserServiceImpl();
}
  • 使用实例工厂方法实例化
<bean class="com.tuling.service.impl.UserServiceImpl" id="userService" factory‐bean="serviceFactory" factor‐method="createUserService" >
</bean>
public class createUserService{
    public UserServiceImpl createUserFactory(){
      return new UserServiceImpl();
    }
}

依赖

依赖注入

  • 基于setter方法的依赖注入
<!--基于setter方法的依赖注入
	1>属性必须声明set方法
	2>name是根据set方法的名字来的,比如方法名字 setIdxx -> name="idxx"
-->
<bean class="com.ydj.spring.beans.User" id="user3">
	<property name="id" value="10000"></property>
	<property name="username" value="xiaoyang"></property>
	<property name="realname" value="xiaoyang666"></property>
</bean>
  • 基于构造函数的依赖注入
<!--基于构造函数的依赖注入
	a.将会调用自定义构造函数来实例化对象,就不会调用默认的无参构造函数
	b.name是根据构造函数的参数名来的, 比如:User(String idxx) ‐> name="idxx"
		注,构造器有多少个参数就必须有多少个<constructor-arg/>,允许有多个构造器
	c.name属性可以省略 但是要注意参数的位置,一般情况下按构造方法中出现的参数顺序注入,不推荐省略name
	d.如果非要把位置错开 可以使用 name 或者 index 或者 type
	e.index[指定注入的顺序,从0开始]
	f.在位置错开情况下只能在类型不一样的时候指定才有明显效果
	g.推荐使用name的构造即序号为b的方式
-->
<bean class="com.ydj.spring.beans.User" id="user4">
	<constructor-arg name="id"  value="20000"></constructor-arg>
	<constructor-arg name="username"  value="xiaoyangabc"></constructor-arg>
	<constructor-arg name="realname"  value="xiaoyangabc123456"></constructor-arg>
</bean>

依赖和配置的细节

环境搭建,创建实体类Person,实体类Wife

public class Person {
    private Integer id;
    private String name;
    private String gender;
    private Date birthday;
    private List<String> hobbies;
    private Map<Integer,String> course;
    private Wife wife;
	
    // 这里省略了 setter,getter,toString方法
}
public class Wife {
    private Integer age;
    private String name;

    // 这里省略了 setter,getter,toString方法
	
}

相关代码参考

<!--复杂数据类型的依赖注入-->
<bean class="com.ydj.spring.beans.Person" id="person">
	<property name="id" value="666" />
	<!--设置null值-->
	<property name="name">
		<null />
	</property>
	<property name="gender">
		<value></value>
	</property>
	<!--引入外部bean-->
	<!--<property name="wife" ref="wife"></property>-->
	<!--使用内部内-->
	<property name="wife">
		<bean class="com.ydj.spring.beans.Wife">
			<property name="name" value="少司命"></property>
			<property name="age" value="18"></property>
		</bean>
	</property>

	<!--list类型的注入
		如果泛型是基本数据类型<value>
		如果泛型是bean<bean>
	-->
	<property name="hobbies">
		<list>
			<value>唱歌</value>
			<value>跳舞</value>
		</list>
	</property>

	<!--map类型的注入
		如果value是基本数据类型<entry key="1" value="Java"></entry>
		 如果value是bean  value-ref-->
	<property name="course">
		<map>
			<entry key="1" value="java" />
			<entry key="2" value="数据库" />
		</map>
	</property>
</bean>

<bean class="com.ydj.spring.beans.Wife" id="wife">
	<property name="name" value="少司命"></property>
	<property name="age" value="16"></property>
</bean>

<!--使用p命名空间简化基于setter属性注入XML配置
	p:按Alt+Enter 自动加上命名空间
	设置基本数据类型   或者p:xxx-ref 引用外部bean
	如果有集合类型 就不支持, 需要额外配置 <property>
	若需要使用p标签,需要在配置头加上p标签的配置
-->
<bean class="com.ydj.spring.beans.User" id="user5" p:id="999" p:username="xiaoyang">
</bean>

<!--使用c命名空间简化基于构造函数的XML-->
<bean class="com.ydj.spring.beans.User" id="user6" c:id="1234" c:realname="xy" c:username="xy">
</bean>

提供一份p标签c标签的配置文件头

<?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:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

使用 depends-on 属性

<!--
	使用depends‐on可以设置先加载的Bean 也就是控制bean的加载顺序
	这段表明在加载user之前会先加载wife
-->
<bean class="com.ydj.spring.beans.Wife" id="wife"></bean>
<bean class="com.ydj.spring.beans.User" id="user" depends-on="wife"></bean>

懒加载bean

<!--懒加载
	使用 lazy‐init 可以设置懒加载
	默认是 false:在 spring容器创建的时候就会加载
	true:在使用到的时候(getBean)才会去加载
-->
<bean class="com.ydj.spring.beans.User" id="user2" lazy-init="true">
</bean>

bean的作用域

<!--使用 scope 可以指定bean的作用域
	singleton:单例的,默认值,同一个id始终只会创建一次bean
	prototype:多例的(原型),每一次使用都会创建一次bean

	此时之外还提供了4种作用域,只有在继承 web 的时候才会用到
	request:一次http请求创建一次bean
	session:一次会话创建一次bean
	application:一次应用只会创建一次bean
	websocket:一个长连接创建一次bean
-->
<bean class="com.ydj.spring.beans.User" id="user3" scope="prototype">
</bean>

自动注入

当一个对象中需要引用另外一个对象的时候,在之前的配置中我们都是通过property标签来进行手动配置的,其实在spring中还提供了一个非常强大的功能就是自动装配,可以按照我们指定的规则进行配置,配置的方式有以下几种:

  • default/no: 不自动装配
  • byName: 按照名字进行装配,以属性名作为id去容器中查找组件,进行赋值,如果找不到则装配null
  • byType: 按照类型进行装配,以属性的类型作为查找依据去容器中找到这个组件,如果有多个类型相同的bean对象,那么就会报异常,如果找不到则装配null
  • constructor: 按照构造器进行装配,先按照有参构造器参数的类型进行装配,没有就直接装配null;如果按照类型找到了多个,那么就使用参数名作为id继续匹配,找到就装配,找不到就装配null
<!--自动注入:
	bytype 根据类型自动注入(spring会根据bean里面的所有对象属性的类型,只要它匹配到bean里面某一个类型跟属性类型吻合就会自动注入
	byname 会根据属性setxxx的名字来自动匹配 (spring会根据bean里面的所有对象属性的set的名字,只要它匹配到bean里面某一个名字跟属性名字吻合就会自动注入
	constructor 优先根据名字来找, 如果名字没有匹配到根据类型来匹配,  如果类型匹配到多个则不会自动注入
	注意:bytype  如果匹配到两个同样的类型会出现错误,所以一定要保证ioc容器里面只有一个对应类型的bean
		byname  最能匹配到唯一的那个bean
		constructor 保证构造函数不能包含多余的其他参数
		default:不会进行自动注入-->
<bean class="com.ydj.spring.beans.Person" id="person" autowire="byName">
</bean>

<bean class="com.ydj.spring.beans.Wife" id="wife">
	<property name="name" value="ssm"></property>
	<property name="age" value="16"></property>
</bean>

<bean class="com.ydj.spring.beans.Wife" id="wife2">
	<property name="name" value="ss"></property>
	<property name="age" value="18"></property>
</bean>

生命周期的回调

<!--生命周期回调
	1>使用接口的方式实现(在实体类)
		a.初始化回调 实现InitializingBean 重写afterPropertiesSet()
		b.销毁回调  实现DisposableBean 重写destroy()
		什么时候销毁:在spring容器关闭的时候  close()
					或者 使用ConfigurableApplicationContext.registerShutdownHook方法优雅的关闭

	2>使用指定具体方法的方式实现生命周期的回调:
		在对应的bean里面创建对应的两个方法
		init-method="init" destroy-method="destroy"
-->
<bean class="com.ydj.spring.beans.User" id="user" init-method="initConfig" destroy-method="destroyConfig">
	<property name="id" value="666"></property>
	<property name="username" value="ssm"></property>
	<property name="realname" value="ssm"></property>
</bean>

spring创建第三方bean对象

在spring中,很多对象都是单例的,在日常开发过程中,我们经常需要使用某些外部的单实例对象,例如数据库连接池

  • 导入数据连接池的pom文件
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid</artifactId>
	<version>1.1.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.47</version>
</dependency>
  • 编写配置文件
    ioc.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:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="root"></property>
        <property name="password" value="xxxxxx"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>
</beans>
  • 编写测试类
@Test
public void test() throws Exception{
	ApplicationContext context = new ClassPathXmlApplicationContext("ioc3.xml");
	DataSource dataSource = (DataSource) context.getBean("dataSource", DataSource.class);
	System.out.println(dataSource);
}

spring引用外部配置文件

  • 在resource中添加db.properties
username=root
password=xxxxxx
url=jdbc:mysql://localhost:3306/test
driverClassName=com.mysql.jdbc.Driver
  • 编写配置文件
<?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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">


    <!--加载外部配置文件
        在加载外部依赖文件的时候需要context命名空间
    -->
    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    	<property name="username" value="{username}"></property>
    	<property name="password" value="{password}"></property>
    	<property name="url" value="{url}"></property>
    	<property name="driverClassName" value="{driverClassName}"></property>
    </bean>
</beans>

bean定义的继承

<!--bean的继承 一个bean继承另一个bean
	可以使用parent属性指定父类bean
	如果想让父类bean不能被实例化  abstract="true"
-->
<bean class="com.ydj.spring.beans.User" id="user2" abstract="true">
	<property name="id" value="1"></property>
	<property name="username" value="parent"></property>
	<property name="realname" value="parent"></property>
</bean>

<bean class="com.ydj.spring.beans.User" id="user3" parent="user2">
	<property name="username" value="son"></property>
</bean>

SpEL的使用

SpEL:Spring Expression Language,spring的表达式语言,支持运行时查询操作对象
使用#{...}作为语法规则,所有的大括号中的字符都认为是SpEL.

<bean class="com.ydj.spring.beans.Person" id="person2">
	<!--支持任何运算符-->
	<property name="id" value="#{1*3+2}"></property>
	<!--引用其他bean-->
	<property name="wife" value="#{wife}"></property>
	<!--可以引用其他bean的某个属性值-->
	<property name="name" value="#{wife.name}"></property>
	<!--调用非静态方法-->
	<property name="gender" value="#{wife.getName()}"></property>
	<!--调用静态方法-->
	<property name="hobbies" value="#{T(java.util.UUID).randomUUID().toString().substring(0,4)}"></property>
</bean>
posted @   小羊abc  阅读(63)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示