Spring 的IOC和DI

IOC(Inversion of Control)控制反转

控制反转(Inversion of Control),把创建对象的权力交给框架,是框架的重要特征,并非面向对象变成的专用术语,包括依赖注入(Dependency Injection)和依赖查找Dependency Lookup

1.传统的操作实例化Bean(手动初始化Bean)

private IAccountDao accoutDao = new AccountDaoImpl();

在这里插入图片描述

交给Spring管理后(声明在xml里面的Bean)

private IAccountDao accountDao = (IAccountDao)BeanFactory.getBean("accountDao");

在这里插入图片描述
这种被动接收的方式获取对象的思想就是控制反转,是Spring框架的核心之一
IOC的作用就是帮我们削弱计算机程序的耦合(减少我们代码中的依赖关系)

实战演习

1.准备Spring依赖包(5.0.2)

Spring官网下载Jar包dis
解压后
在这里插入图片描述

  • docs 顾名思义API文档
  • libs 所用的工具jar包(aop,aspects,beans,context,core,expression)
  • schema 所有Spring合集的xsd约束文件

2.操作

2.1Maven中引入pom

在这里插入图片描述

2.2创建xml文件(bean.xml)

  • 添加文件头约束描述文件
    在这里插入图片描述
  • 声明想要创建的Bean
    在这里插入图片描述
  • IDEA创建项目结构
    项目结构
  • 创建模拟操作的类
    创建模拟操作的类
  • 结果
    打印结果

由此可以说明Spring帮我们创建实例成功,如果你写个for循环会发现打印多次的类和类的hash码
相同的,也说明了Spring帮我们创建的是单例的实例。。。。(PS:挖个小坑。。。。)

ApplicationContext的三个常用实现类

1.ClassPathXmlApplicationContext(类路径加载)

它可以加载类路径下的配置文件,要求配置文件必须在类路径下,不在的话,便加载不了
上面图片便是,不在重复

2.FileSystemXmlApplicationContext(文件路径加载)

它可以加载磁盘任意路径下的配置文件(必须有访问权限)

第二种创建Bean的方式

3.AnnotationConfigApplicationContext(注解加载)

它是用于读取注解创建容器的配置类信息
被@Configuration声明的Spring配置类,详见请看SpringConfigration.class
作用:当采用配置类配置Spring常用的工具集时,采用该注解进行测试SpringBoot大部分都采用配置类

public class AccountServiceTest{
	@Test
	public void testFindAll(){
		ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
		IAccountService as = ac.getBean("accountService",IAccountService.class);
		System.out.println(as.findAllAccount());
	}
	// 省略...
}

!!!废话不多说,上代码!!!

@Configuration
@ComponentScan(value="com.heartskihigh")
//ComponentScan(basePackages="")
public class SpringConfiguration{
	@Bean("runner")
	public QueryRunner createQueryRunmer(DataSource dataSource){
		return new QueryRunner(dataSource);
	}
	@Bean("dataSource")
	public DataSource createDataSource(){
		try{
		ComboPooledDataSource ds = new ComboPooledDataSource();
		ds.setDriverClass("com.mysql.jdbc.Driver");
		ds.setJdbcUrl("jdbc:mysql://localhost:3306/user");
		ds.setUser("root");
		ds.setPassword("123456");
		} catch(Exception e){
			log.error("【数据源异常】,{}",e);
			throw new NsiOperationException("初始化数据源失败...");
		}
	}
	// 省略...
}

核心容器的两个接口的区别

1.ApplicationContext(单例对象适用)

它是在构建容器时,创建对象采取的策略是采用立即加载方式,也就是只要读完配置文件马上就创建文件
中配置的对象

测试
测试

  • Debug后发现,读取完配置文件,对象就被创建并存入容器(类中添加一个无参构造,并打印一句话)

2.BeanFactory(多例对象适用)

它是在构建核心容器时,创建对象采取的策略时延迟加载的方式,什么时候根据Id获取对象,什么时候在创
建对象

测试
测试

  • Debug后发现,读取完配置文件,并没有立即创建,而是当执行完getBean方法时,对象才被创建

Spring对Bean的管理细节

1.创建Bean的

使用默认构造函数创建
在Spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时
采用的就是默认无参构造函数创建对象,此时如果类中没有默认构造函数,则对象无法闯将

<bean id="instanceFactory" class="com.heartskyhigh.factory.InstanceFactory"></bean>

2.工厂中的普通方法创建对象

使用xml配置普通方法创建对象

public class InstanceFactory{
	public void getAccountService(){
		return new AccountServiceImpl();
	}
}
<bean id="instanceFactory" class="com.heartskyhigh.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>

3.工厂中的静态方法创建对象

使用xml配置静态方法创建对象

public class StaticFactory{
	public static IAccountService getAccountService(){
		return new AccountServiceImpl();
	}
}
<bean id="accountService" class="com.heartskyhigh.factory.StaticFactory" factory-method="getAccountService"></bean>

Spring Bean对象的作用范围和生命周期

bean标签的scope属性,用于指定bean的作用范围
取值singleleton,prototype,request,session,global-session

  • singleton:默认单例,无论创建多少次,整个spring应用上下文只有一个实例

当容器创建时对象出生,只要容器存在,对象一直存活,容器销毁对象消亡

  • prototype:多例,创建多少次就有多少个对象,相当于new了两次

使用对象时spring为我们创建对象出生,对象使用过程中一直存活,当对象长时间不用且没有别的对象引用
时,由java的GC回收

public static void main(String[] args){
	ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
	IAccountService ac1 = (IAccountService)ac.getBean("accountService");
	IAccountService ac2 = (IAccountService)ac.getBean("accountService");
	System.out.println(ac1==ac2);
}

多例描述

  • request:作用于web应用的请求范围
  • session:作用于web应用的会话范围
  • global-session:作用于集群环境的绘画范围(全局绘画范围,当不是集群环境,它就是session)

DI(Dependency Injection)依赖注入

1.可以注入的类型三种

  • 基本数据类型和String
  • 其他bean类型(配置文件里面的bean)
  • 复杂类型/集合类型

2.注入的方式

  • 使用构造函数提供

使用constructor-arg标签,出现在bean标签内部
取值type,index,name,value,ref
type:用于指定注入数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值,索引的位置从0开始
name:用于指定给构造函数中指定名称的参数赋值
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据,它指的就是在Spring的IOC核心容器中出现锅的bean对象

<bean id="accountService" class="com.heartskyhigh.factory.StaticFactory" factory-method="getAccountService">
	<constructor-arg name="name" value="TuoMaSi"></constructor-arg>
	<constructor-arg name="age" value="17"></constructor-arg>
	<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>

<bean id="now" class="java.util.Date"></bean>

优势:获取bean对象,注入数据时是必须的操作,否则对象无法创建成功
弊端:改变了bean对象的实例化方式,使我们创建对象时,如果用不到这些数据,也必须提供

  • 使用set方法提供

使用property标签,出现在bean标签内部
属性name,value,ref

<bean id="accountService" class="com.heartskyhigh.factory.StaticFactory" factory-method="getAccountService">
	<property name="name" value="TuoMaSi"></property>
	<property name="age" value="17"></property>
	<property name="birthday" ref="now"></property>
</bean>

<bean id="now" class="java.util.Date"></bean>

优势:创建对象没有限制,可以直接使用默认构造函数
弊端:如果某个成员必须有值,则获取对象是有可能set方法没有执行

  • 给数组,集合,Map赋值
	private String[] myStrs;
	private List<String> myList;
	private Set<String> mySet;
	private Map<String,String> myMap;
	private Properties myProps;

	// set方法省略。。。
<bean id="accountService" class="com.heartskyhigh.factory.StaticFactory" factory-method="getAccountService">
    <!-- 定义数组 -->
	<property name="myStrs">
		<array>
			<value>AAA</value>
			<value>BBB</value>
			<value>CCC</value>
		</array>
	</property>
	<!-- 定义List -->
	<property name="myList">
			<list>
				<value>AAA</value>
				<value>BBB</value>
				<value>CCC</value>
			</list>
	</property>
	<!-- 定义Set -->
	<property name="mySet">
			<set>
				<value>AAA</value>
				<value>BBB</value>
				<value>CCC</value>
			</set>
	</property>
	<!-- 定义Map -->
	<property name="myMap">
			<map>
				<entry key="test1" value="AAA"></entry>
				<entry key="test2">
					<value>BBB</value>
				</entry>
			</map>
	</property>
	<!-- 定义Properties -->
	<property name="myProps">
			<props>
				<prop key="test1">AAA</prop>
				<prop key="test2">BBB</prop>
			</props>
	</property>

</bean>

<bean id="now" class="java.util.Date"></bean>
  • 使用注解提供

后续补充。。。。

发布了9 篇原创文章 · 获赞 9 · 访问量 612

猜你喜欢

转载自blog.csdn.net/weixin_41241629/article/details/103952834