spring框架的IOC容器和Bean配置_ReflectMirroring的博客-程序员信息网

技术标签: Spring(+注解开发)&&SpringMVC  

IOC

IOC全名是inversion of control ,就是反转控制,也叫控制反转,其实它也不是听得那么高达上,其实就是一种思想,
之前我们创建类后需要new对象,对象的创建的控制权是在我们程序员的手上,现在我们将创建对象的权力交给spring,我们不需要知道对象是如何创建的,只知道需要向spring要对象使用就行,这样提高了开发的效率
这种将创建对象的权力交给spring的思想就是反转控制

DI

DI全名是dependency injection ,也叫依赖注入
这里就是顾名思义,依赖就是一个对象的创建需要什么对象,比如上面的例子,如果一个person的创建必须要id和name两个属性,那么在创建person对象前就必须先new出id和name两个对象,然后在这两个对象的基础上创建person对象,这就是依赖
而注入就是spring根据对象的创建需要什么就注入什么,比如上面需要id和name,那么就会给你id和name
其实IOC就是一种反转控制的思想,而DI就是IOC这种思想的具体实现

package jane;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test
{
    
	public static void main(String[] args)
	{
    
		/*
		 * 初始化容器,ApplicationContext是一个接口,我们需要用它的实现类来创建容器
		 * ClassPathXmlApplicationContext里面的参数是配置文件的路径,所以conf里面的
		 * 配置文件名是可以改的,但是在以后的ssm框架里面是自动初始化容器,会自动找
		 * applicationContext.xml文件,所以建议还是写成applicationContext.xml
		 * 在配置文件里面有一个唯一标识的id,这里使用id来得到bean
		 */
		ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
		/*
		 * 这个方法是直接通过bean的id属性进行查找的,
		 * 因为bean的id是不能重复的,所以这里不会冲突
		 */
//		Person bean = (Person)ac.getBean("Person");
		
		/*
		 * 这个方法是通过类来得到bean的,如果使用这个方法,
		 * 那么确保配置文件里面这个class对应的bean只能有一个,
		 * 如果这个class有多个bean的时候,就会报错
		 * Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [jane.Person] is defined: expected single matching bean but found 2: Person1,Person2
			at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:312)
			at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:985)
			at jane.Test.main(Test.java:19)
		 */
//		Person bean = ac.getBean(Person.class);
		
		/*
		 * 这个重载的方法就是使用id和类确定bean的位置,这个一般不会有太多问题
		 * 所以一般我们使用这个
		 */
		Person bean = ac.getBean("Person1", Person.class);
		System.out.println(bean);
		
		/*
		 * spring能帮我们管理对象,但是spring到底是怎么创建对象的呢?
		 * 其实我们可以大胆地尝试,之前学过反射,反射创建对象就是先加载
		 * 这个类,使用class.forname()的方法加载,然后newInstance()创建对象
		 * 其实spring就是根据反射进行创建对象的,前面配置的bean的class属性
		 * 就是类的全限定名,就是用来加载类的
		 * 测试验证:
		 * 我们如果在person类中写出有参的构造方法,那么无参的构造方法就会被覆盖
		 * 那么如果spring是反射创建对象的应该会出现错误
		 * 如我们所愿出现了错误
		 * Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [jane.Person]: No default constructor found; nested exception is java.lang.NoSuchMethodException: jane.Person.<init>()
				at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)
				at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1069)
				... 13 more
			Caused by: java.lang.NoSuchMethodException: jane.Person.<init>()
				at java.base/java.lang.Class.getConstructor0(Class.java:3354)
				at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2558)
				at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80)
				... 14 more
			所以spring就是使用反射创建对象的
		 */
	}
}

IOC容器在spring中的实现

spring中最重要的是IOC思想,IOC思想必须基于IOC容器来实现,IOC的最底层实际上就是一个对象工厂,我们来看一下里面的继承关系
在这里插入图片描述
最上面的接口就是BeanFactory,就是最基础的东西,而最下面的就是
ClassPathXmlApplicationContext和FileSystemXmlApplicationContext类,
其实这两个类都是一样效果的,
ClassPathXmlApplicationContext是从当前项目的文件中读取配置文件,写的是相对的路径
FileSystemXmlApplicationContext是从系统上读取配置文件,写的是绝对路径,因为有些
项目的配置文件独立地放在一个服务器里面,所以就可以使用这种方法,使用绝对路径

在通过IOC容器读取Bean的实例之前,需要先将IOC容器本身实例化。
Spring提供了IOC容器的两种实现方式

  • BeanFactory:IOC容器的基本实现,是Spring内部的基础设施,是面向Spring本身的,不是提供给开发人员使用的。
  • ApplicationContext:BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory。

里面有个onfigurableApplicationContext是ApplicationContext的子接口,包含一些扩展方法:refresh()和close()让ApplicationContext具有启动、关闭和刷新上下文的能力。

Bean的属性赋值

依赖注入的方式

通过bean的setXXX()方法赋值
	<bean id="Person1" class="jane.Person">
		<property name="id" value="1"></property>
		<property name="name" value="张三"></property>
	</bean>

比如这里的bean里面,<property name="id" value="1"></property>是如何给person对象赋值的,
在person类里面,所有的属性都是私有化的,我们访问不了,那么spring是如何赋值
通过追踪查看,原来是调用里面的get和set方法进行赋值

通过bean的构造器进行赋值
	<bean>
		<constructor-arg value="3"></constructor-arg>
		<constructor-arg value="小红" index="1" type="java.lang.String"></constructor-arg>
	</bean>

通过构造方法注入是有个小问题,比如类中的构造方法有多个,例如person类中有两个构造方法public person(Integer id,String name)和public person(Double id,String name)
那么通过这种方法就出现赋值的对象不是你想要的或者报错,那么就需要在constructor-arg
标签里面增加index索引和type类型属性,索引是说明是第几个参数,类型说明它属于什么类型,这种方法不常用,通过set方法注入常用

p命名空间
这也不是什么高达上的东西,就是简化给属性赋值的快捷方式 如果你是使用STS的话,很方便直接在namesspace里面将p勾上就行 STS会自动在命名空间里面增加p命名空间的约束 `xmlns:p="http://www.springframework.org/schema/p"`

在这里插入图片描述
设置好后这样bean的设置就简单了
直接设置成这样就行<bean id="4" class="jane.Person" p:id="4" p:name="小明"></bean>

属性的值
字面量
字面量就是spring管理的对象的属性是基本数据类型或基本数据类型的封装类还有string类,可以通过value属性或者value子节点的方式给属性赋值, 如果字面量中包含特殊的字符,可以使用<![CDATA[]]>把字面量包裹起来
<property name="name" value="李四"></property>
这个可以改成
<property name="name">
	<value>李四</value>
</property>
引用外部声明的bean
字面量我们可以直接赋值,但是如果这个属性不是字面量,而是一个我们自己定义的类或者其他,那么我们就是不可以通过value进行赋值了,那么就得需要使用ref进行引用赋值了,ref的值就是引用的bean的id
	<bean id="Person2" class="jane.Person">
		<property name="id" value="2"></property>
		<property name="name" value="李四"></property>
		<property name= "eat" ref ="eat"/>
	</bean>
//其中person里面有一个eat类的属性
级联属性赋值
级联就是将属性分成一层一层,就好比如淘宝的收货地址,一个省下面对应的是这个省的市,绝不会访问到其他省的市,那么属性赋值的时候也是可以使用这种级联,比如
	<bean id="Person2" class="jane.Person">
		<property name="id" value="2"></property>
		<property name="name" value="李四"></property>
		<property name= "eat" ref ="eat"/>
		<property name= "eat.run" value="用筷子"/>
	</bean>
//这里是在eat类里面有个run的属性,将这个属性赋值为"用筷子"
内部bean
当bean实例仅仅给一个特定的属性使用的时候,可以将它声明成为内部bean,声明直接包含在< property>或< constructor-arg>元素里面,因为只给这个bean使用,不需要设置id或name,内部bean也不能使用在其他的任何地方,例如
	<bean id="Person2" class="jane.Person">
		<property name="id" value="2"></property>
		<property name="name" value="李四"></property>
		<property name= "eat">
			<bean class="jane.run">
				<property name="run" value="用筷子"/>
			</bean>
		</property>
	</bean>
//这里是在eat类里面有个run的属性,将这个属性赋值为"用筷子"
集合属性
现在就是来说我们经常用的数组,List,Map集合的实现
List集合
直接使用< list>标签就可以给list属性赋值,list标签里面可以包含字面量< value>实现,引用数据类型< ref > 实现或者内部bean实现,例如
	<bean id="t1" class="jane.Teacher">
		<property name="tid" value="1001"></property>
		<property name="tname" value="jane1"></property>
		<property name="clas">
			<list>
				<value>A</value>
				<value>B</value>
				<value>C</value>
			</list>
		</property>
	</bean>
	</bean>
	
		<bean id="t2" class="jane.Teacher">
		<property name="tid" value="1002"></property>
		<property name="tname" value="jane2"></property>
		<property name="students">
			<list>
				<ref bean="s1"/>
			</list>
		</property>
	</bean>

而数组和list一样,用< array>进行注入,其实数组也可以使用list进行赋值,因为List的底层就是数组,Set使用< set>标签进行注入,定义方法和list一样
这里说下要交给spring管理的类的属性的命名规范,比如sName,不能这样命名属性,因为这样生成的get和set方法不符合set和get方法的规范,生成的get和set方法的属性的名字会弄成大写的,但是sName这样命名就不会变成大写,就直接说没有get和set方法的

Map
通过< map>标签进行注入,< map>标签里面可以使用多个< entry>作为子标签,每一个< entry>就包含一个键和一个值,例如
	<bean id="t3" class="jane.Teacher">
		<property name="tid" value="1003"></property>
		<property name="tname" value="jane2"></property>
		<property name="bossMap">
			<map>
				<entry>
					<key>
						<value>1001</value>
					</key>
					<value>jane1</value>
				</entry>
			</map>
		</property>
	</bean>
util命名空间对集合属性的注入
也是直接在Namespaces里面直接勾选上util就行 util命名空间里面有对集合的简单创建,比如一个< util:list>就是一个list集合
	<bean id="t4" class="jane.Teacher">
		<property name="tid" value="10042"></property>
		<property name="tname" value="jane4"></property>
		<property name="students" ref="list"></property>
	</bean>
	
	<util:list id="list">
		<ref bean="s1"/>
	</util:list>

FactoryBean

Spring中有两种类型的bean,一种是普通bean,另一种是工厂bean,就是FactoryBean,不多说,先上代码

//Car类
package factorybean;
public class Car
{
    
	private String brand;
	private Double price;
	//下面的get和set方法就在这里写了
}

//Myfactory类
package factorybean;

import org.springframework.beans.factory.FactoryBean;

public class Myfactory implements FactoryBean<Car>
{
    
	@Override
	public Car getObject() throws Exception
	{
    
		Car car=new Car();
		car.setBrand("法拉利");
		car.setPrice(800000.0);
		return car;
	}
	@Override
	public Class<?> getObjectType()
	{
    
		return Car.class;
	}
	@Override
	public boolean isSingleton()
	{
    
		return false;
	}
}
//对应的factory-bean配置文件
<?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">

	<bean id="Myfactory" class="factorybean.Myfactory"></bean>
</beans>
//测试类
package factorybean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test
{
    
	public static void main(String[] args)
	{
    
		ApplicationContext ac=new ClassPathXmlApplicationContext("factory-bean.xml");
		Object bean = ac.getBean("Myfactory");
		System.out.println(bean);
	}
}
//结果
Car [brand=法拉利, price=800000.0]

Factory Bean就是对象工厂,就是用来产生对象的,我们在bean里面配置工厂的bean,最后运行返回的就是这个工厂对应的的生产的类的对象,就是通过getObject方法得到的

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_43416157/article/details/104978997

智能推荐

jQuery选择器:nth-child(2) 与:nth-child(2n) 的区别_iteye_13003的博客-程序员信息网

// nth-child(2)$('table tr td:nth-child(2)').css('background-color','red'); // :nth-child(2n)$('table tr td:nth-child(2n)').css('background-color','red');   演示地址: http://qiaole.sina...

云文档能代替服务器吗,云存储能代替服务器存储吗_mogego七海的博客-程序员信息网

云存储能代替服务器存储吗 内容精选换一换本章节主要介绍云硬盘、弹性文件服务、对象存储服务等存储服务,让您更好的了解这些存储服务。使用存储容灾服务前,请您先了解表1中描述的使用限制。在生产站点可用区整个AZ故障时,可通过容灾演练功能恢复服务器业务。首次切换/故障切换和容灾演练操作后,登录弹性云服务器有哪些注意事项?云存储能代替服务器存储吗 相关内容ModelArts为用户提供了多种常见的预置引擎,但...

数据建模步骤文档_二维溃坝洪水模拟(五)二维模型建模_weixin_39811478的博客-程序员信息网

1 前言本文主要说明案例中水库下游区域HEC-RAS二维建模的过程。文章首先给出建模的基本原则与建模的注意事项,确定了大致的研究区域。其次,整个下游洪水演进区域由单一二维模型模拟,下游存在一条较大的城市内河,沿河堤线对网格调整加密重生成。HEC-RAS2D建模功能较为丰富,本文远未穷尽全部功能,仅供参考2 建模原则建模的原则其实很简单,首先是针对研究区域分析,确认所有需水动力模拟的现实对象。之后抽...

实现微信小程序中间部分导航滑动--swiper组件_在路上`的博客-程序员信息网_swiper组件

一、实现效果图二、实现方法 swiper组件主要点在于组件中的 display-multiple-items 属性以及 float: left浮动图标,下面的指示点是另外加的新样式三、事例代码wxml&lt;!--头部导航开始 --&gt;&lt;view class="headerModel"&gt; &lt;swiper indicator-dots="{{indicatorDots}}" display-multiple-items="5" bindchange="mddotCh

tars学习_虚拟的伪装者的博客-程序员信息网

rpc微服务框架涉及的问题:高效、可靠的调度器同步调用和异步调用的设计适当的发送协议已经解析结果提供不同的服务选择节点的策略-轮询、hash、权重管理服务节点状态,节点是否已连接,是否连接中,是否超时,是否重连,超时时间设置,重连时间设置等,如何可靠的接受请求,发送结果,请求量的控制,接受到1.5个请求怎么办,发送请求,未收到结果怎么办;rpc-client...

Spring中的@Valid 和 @Validated注解_yzc_sky的博客-程序员信息网_spring validate注解

Spring中的@Valid 和 @Validated注解文章目录Spring中的@Valid 和 @Validated注解1. 概述2. @Valid和@Validate注解3. 例子4. 使用@Valid批注标记嵌套对象5. 总结1. 概述本文我们将重点介绍Spring中 @Valid和@Validated注解的区别 。验证用户输入是否正确是我们应用程序中的常见功能。Spring提供了@Valid和@Validated两个注解来实现验证功能,下面我们来详细介绍它们。2. @Valid和@Val

随便推点

WinInet 使用_roman1232008的博客-程序员信息网

一、WinInet简介http://baike.baidu.com/link?url=5JMMt-y0RlKfCRIy3UVXq-pwauKdBi5nvsQ_31ptpHQyS-IHJjJgOuAoYXFF94TYWinInet(“Windows Internet”)API帮助程序员使用三个常见的Internet协议,这三个协议是用于World Wide Web万维网的超文本传输协议(

为什么每次进入命令都要重新source /etc/profile 才能生效?_lwplvx的博客-程序员信息网_为什么每次都要source

#编辑JDK8export JAVA_HOME="/usr/java/java8"#编辑mavenexport M2_HOME="/opt/idea-IU-162.1121.32/plugins/maven/lib/maven3"#编辑PATHexport PATH="$JAVA_HOME/bin:$M2_HOME/bin:$PATH"这是我的/etc/profile末尾的

seata源码解析:TM RM 客户端的初始化过程_Java识堂的博客-程序员信息网

TM和RM初始化过程上一篇文章说过,在Spring启动的过程中就会就会初始化TM和RM,建立与TC的长连接。TM,RM,TC都是用netty来处理网络连接的,初始化netty客户端和服务端的过程也非常类似。本篇文章只分析TM的初始化过程,RM和TM复用了很多方法// TmNettyRemotingClientpublic void init() { // registry processor // 注册消息处理器 registerProcessor(); if (i.

学习Linux踩过的那些坑_互联网老辛的博客-程序员信息网

(1)进行linux实战训练的时候,改动了/etc/fstab文件,导致Linux无法正常运行。故障截图;故障原因:我们都知道/etc/fstab 文件识用来挂载分区的,...

Flutter学习笔记-IOS心型图标的颜色和大小_yyxgs的博客-程序员信息网

import 'package:flutter/cupertino.dart';import 'package:flutter/material.dart';void main() =&gt; runApp(MyApp());class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp ( title: 'flutter Demo'.

推荐文章

热门文章

相关标签