目录
1.IOC(Inversion of Control):反转控制
2.DI(Dependency Injection):依赖注入
1.2创建bean
1.1IOC和DI
1.IOC(Inversion of Control):反转控制
在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率。
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式。
2.DI(Dependency Injection):依赖注入
IOC的另一种表述方式:即组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器的资源注入。相对于IOC而言,这种表述更直接。
总结: IOC 就是一种反转控制的思想, 而DI是对IOC的一种具体实现。
3.IOC容器在Spring中的实现
在创建Bean之前,首先需要创建IOC容器。Spring提供了IOC容器的两种实现方式:
- BeanFactory:IOC容器的基本实现,是Spring内部的使用接口,是面向Spring本身的,不是提供给开发人员使用的。
- ApplicationContext:BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory。
4.ApplicationContext的主要实现类
- ClassPathXmlApplicationContext:对应类路径下的XML格式的配置文件
- FileSystemXmlApplicationContext:对应文件系统中的XML格式的配置文件
- ConfigurableApplicationContext:是ApplicationContext的子接口,包含一些扩展方法refresh()和close(),让ApplicationContext具有启动、关闭和刷新上下文的能力。
- WebApplicationContext:专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作。
1.2创建bean
让Spring的IOC容器帮我们创建Bean,只需要在Spring的配置文件中通过bean标签配置即可。
bean标签中常用属性说明:
- Id属性:给IOC容器中的bean设置的唯一标识。
- class属性:配置让IOC容器管理的类的全类名,Spring会利用反射技术通过类的无参构造器创建对象。
<?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="book" class="com.spring.bean.Book"></bean> </beans>
1.3给Bean的属性赋值
1 setter注入
在bean标签中通过property标签设置bean的属性值,property标签中的属性说明:
- name属性:配置bean的属性名
- value属性:配置bean的属性值
- 还可以通过value子标签配置bean的属性值
<bean id="book" class="com.spring.bean.Book">
<property name="id" value="1"></property>
<property name="title" value="三国演义"></property>
<property name="price" value="12"></property>
<property name="author" value="罗贯中"></property>
<property name="sales" value="100"></property>
</bean>
2 构造器注入
在bean标签中通过constructor-arg标签设置bean的属性值,constructor-arg标签中的属性说明:
- name属性:配置构造器中的参数名
- value属性:配置参数值
- index属性:配置参数在构造器中的索引位置,从0开始
- type属性:配置构造器中参数的类型
-
只指定value属性,自动匹配合适的构造器
<bean id="book2" class="com.spring.bean.Book">
<constructor-arg value="2"></constructor-arg>
<constructor-arg value="水浒传"></constructor-arg>
<constructor-arg value="施耐庵"></constructor-arg>
<constructor-arg value="88.88"></constructor-arg>
<constructor-arg value="100"></constructor-arg>
</bean>
3 特殊值处理
- 字面量
字面量是用于表达源代码中一个固定值的表示法。基本数据类型及其包装类型、String等类型都可以采取字面值注入的方式。
- 赋null值
通过<null></null>标签给bean的属性赋null值
- 赋值中包含特殊字符
若字面值中包含特殊字符,可以使用<![CDATA[ ]]>把字面值包裹起来
<!--特殊值处理-->
<bean id="book5" class="com.spring.bean.Book">
<constructor-arg value="5"></constructor-arg>
<constructor-arg name="title">
<value><![CDATA[<<金瓶梅>>]]></value>
</constructor-arg>
<constructor-arg name="author" value="兰陵笑笑生"></constructor-arg>
<constructor-arg name="price" value="9.9"></constructor-arg>
<constructor-arg name="sales" >
<null></null>
</constructor-arg>
</bean>
4 使用p名称空间
使用p名称空间需要引入对应的约束,在Idea中根据提示引入即可。
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--通过p名称空间配置bean-->
<bean id="book5" class="com.spring.bean.Book"
p:id="5" p:title="解忧杂货店"
p:author="藤野圭吾"
p:price="33.00"
p:sales="100"></bean>
</beans>
5 引用外部已声明的bean
当bean的属性是一个其他类型的对象时,可以在property或<constructor-arg>标签中通过ref属性或ref子标签引用IOC容器中配置好的该类型的bean,ref的属性值指定为引用的bean的id值。
<bean id="cartItem" class="com.spring.bean.CartItem">
<!--引用外部bean-->
<property name="book" ref="book1"></property>
<property name="count" value="10"></property>
<property name="amount" value="100"></property>
</bean>
6 内部bean
当bean实例仅仅给一个特定的属性使用时,可以将其声明为内部bean。内部bean声明直接包含在<property>或<constructor-arg>元素里,不需要设置id。
<bean id="cartItem2" class="com.spring.beans.CartItem">
<property name="book">
<!--配置内部bean-->
<bean class="com.spring.beans.Book">
<property name="id" value="6"></property>
<property name="title" value="三体"></property>
<property name="author" value="刘慈欣"></property>
<property name="price" value="22.00"></property>
<property name="sales" value="100"></property>
</bean>
</property>
<property name="count" value="10"></property>
<property name="amount" value="100"></property>
</bean>
7 级联属性赋值
当bean的属性是一个对象,我们可以通过配置当前bean的方式给属性中对象的属性赋值,即给属性的属性赋值,这种方式我们称为给级联属性赋值。
<!--给级联属性赋值-->
<bean id="cartItem3" class="com.spring.beans.CartItem">
<property name="book" ref="book1"></property>
<!--通过给级联属性赋值将book1中的title修改为新三国-->
<property name="book.title" value="新三国"></property>
</bean>
8 集合属性
当bean的属性是集合类型时,可以通过以下标签进行配置:
- <array></array>:配置数组类型
- <list></list>:配置List类型
- <map><entry></entry></map>:配置Map类型
-
<!--配置集合属性--> <bean id="bookShop" class="com.spring.beans.BookShop"> <property name="books"> <list> <ref bean="book1"></ref> <ref bean="book2"></ref> <ref bean="book3"></ref> </list> </property> <property name="map"> <map> <entry key="user1" value="张三"></entry> <entry key="user2" value="李四"></entry> <entry key="user3" value="王五"></entry> </map> </property> </bean>
9 集合类型的bean
如果只能将集合对象配置在某个bean内部,则这个集合的配置将不能被重用。我们需要将集合bean的配置拿到外面,供其他bean引用。
配置集合类型的bean需要引入util名称空间。
<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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--配置集合bean-->
<util:list id="listBean">
<bean class="com.spring.beans.Book">
<property name="id" value="1"></property>
<property name="title" value="大秦帝国之裂变"></property>
<property name="author" value="孙皓晖"></property>
</bean>
<bean class="com.spring.beans.Book">
<property name="id" value="2"></property>
<property name="title" value="大秦帝国之纵横"></property>
<property name="author" value="孙皓晖"></property>
</bean>
<bean class="com.spring.beans.Book">
<property name="id" value="3"></property>
<property name="title" value="大秦帝国之崛起"></property>
<property name="author" value="孙皓晖"></property>
</bean>
</util:list>
</beans>
10 自动装配
手动装配:以value或ref的方式明确指定属性值都是手动装配。
自动装配:根据bean标签的autowire属性指定的装配规则,不需要明确指定,Spring自动将匹配的属性值注入bean中。
自动装配的规则,即autowire的属性值有:
- no或default:不自动装配
- byName:根据bean的属性名称自动装配,以当前bean的属性名作为id从IOC容器中寻找以实现装配。找到则装配,找不到则不装配。
- byType:根据bean的属性类型自动装配。找到一个则装配,找到多个则报错,找不到则不装配。
- constructor:根据bean的属性的构造器自动装配,不推荐使用。
<bean id="cartItem4" class="com.spring.beans.CartItem"
autowire="byName"></bean>
11 引入外部属性文件
当bean的配置信息逐渐增多时,查找和修改一些bean的配置信息就变得愈加困难。这时可以将一部分信息提取到bean配置文件的外部,以properties格式的属性文件保存起来,同时在bean的配置文件中引用properties属性文件中的内容,从而实现一部分属性值在发生变化时仅修改properties属性文件即可。这种技术多用于连接数据库的基本信息的配置。
- 导入druid-1.1.10.jar和mysql-connector-java-8.0.11-bin.jar
- 在src目录下创建外部属性文件druid.properties
jdbc.driverClassName=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/bookstore?serverTimezone=UTC&rewriteBatchedStatements=true jdbc.username=root jdbc.password=123456 jdbc.initialSize=10 jdbc.maxActive=20
- 在Spring的配置文件中通过<context:property-placeholder location=”classpath:druid.properties”/>标签引入外部属性文件”
<?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:util="http://www.springframework.org/schema/util"
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/util
https://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:druid.properties"></context:property-placeholder>
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="initialSize" value="${jdbc.initialSize}"></property>
<property name="maxActive" value="${jdbc.maxActive}"></property>
</bean>
12 FactoryBean
Spring中有两种类型的bean,一种是普通bean,另一种是工厂bean,即FactoryBean。普通bean设置的类型就是返回的类型;工厂bean设置的类型可以和返回的类型不一样,其返回的类型通过该工厂bean的getObject方法指定。
创建工厂bean必须实现org.springframework.beans.factory.FactoryBean接口。
创建工厂bean的步骤:
- 创建一个类实现FactoryBean接口
package com.spring.beans; import org.springframework.beans.factory.FactoryBean; public class MyFactoryBean implements FactoryBean<Book> { //设置返回的对象 @Override public Book getObject() throws Exception { return new Book(7,"生命不息,奋斗不止","罗永浩",11.11,1000); } //设置对象的类型 @Override public Class<?> getObjectType() { return Book.class; } //设置当前bean是否是单例的 @Override public boolean isSingleton() { return true; } }
- 在Spring的配置文件中配置工厂bean
<!--配置工厂bean--> <bean id="myFactoryBean" class="com.atguigu.spring.beans.MyFactoryBean"> </bean>
- 测试
/* 测试工厂bean */ @Test public void testFactoryBean(){ Book book = (Book) ioc.getBean("myFactoryBean"); System.out.println(book); }