Inversion of Control
反转控制
凡是你所需要的对象并不是由自己所准备的
而是由其他组件控制你所获取的对象的时候
简单来讲:我们所需要进行的操作是收到其他组件控制的
这种情况就称之为反转控制
注重的是结果
Dependency injection
依赖注入
凡是你所需要使用的对象的属性的值不是由自己所准备的
而是由其他组件控制你的属性的值的时候
简单来讲:我们所需要操作的过程是收到其他组件所控制的
这种情况称之为依赖注入
主要的是过程
初始情况下,IDEA中无法自动创建Spring的配置文件
但是当IDEA中对应的工程导入了Spring的基本依赖的时候
此时IDEA将会提供自动创建Spring配置文件的方式
导入Spring基本依赖
<properties> <spring.version>5.2.5.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> </dependencies>简单值:基本数据类型、String、包装类型、Class、Resource
<!-- 简单值装配方式一 --> <bean id="someBean" class="ioc01.SomeBean"> <!-- value属性:为当前指定的属性赋予一个简单值 --> <property name="id" value="1"/> <property name="name" value="admin"/> <property name="salary" value="1000.0"/> <property name="c" value="java.lang.String"/> </bean> <!-- 简单值装配方式二 --> <bean id="someBean2" class="ioc01.SomeBean"> <!-- 可以使用value子标签进行简单值装配,效果与value属性一致 --> <property name="id"> <value>2</value> </property> <property name="name"> <value>alice</value> </property> <property name="salary"> <value>2000.0</value> </property> <property name="c"> <value>java.lang.Exception</value> </property> </bean>当当前的bean中的属性的值是另一个已经存在的bean的实例的时候
可以使用ref属性或者ref标签进行其他bean的引用
<!-- 其他bean的引用 --> <bean id="otherBean" class="ioc02.OtherBean"> <property name="id" value="1"/> <property name="name" value="admin"/> </bean> <!-- 方式一 --> <bean id="someBean" class="ioc02.SomeBean"> <!-- ref属性:指向当前容器中已经存在的另一个bean的id属性值 --> <property name="otherBean" ref="otherBean"/> </bean> <!-- 方式二 --> <bean id="someBean2" class="ioc02.SomeBean"> <!-- ref子标签:指定当前属性所引用的bean bean属性:指向当前容器中已经存在的另一个bean的id属性值 --> <property name="otherBean"> <ref bean="otherBean"></ref> </property> </bean>集合类型:List、Set、Map、Properties、Array
这些集合属性又分为两种类型
List、Set、Array相当于链表结构
Map、Properties相当于键值对结构
同一种结构的类型可以混用
链表结构的集合类型当元素的值有且仅有一个的时候,可以使用简单值的方式进行装配
<!-- 集合类型装配 --> <bean id="someBean" class="ioc03.SomeBean"> <!-- 使用list标签对List类型的属性进行装配 该标签存在无数个value子标签 每一个value子标签装配一个元素的值 --> <property name="list"> <list> <value>l1</value> <value>l2</value> <value>l3</value> </list> </property> <property name="set"> <set> <value>s1</value> <value>s2</value> <value>s3</value> </set> </property> <property name="arr"> <array> <value>s1</value> <value>s2</value> <value>s3</value> </array> </property> <property name="map"> <map> <entry key="k1" value="m1"></entry> <entry key="k2" value="m2"></entry> <entry key="k3" value="m3"></entry> </map> </property> <property name="properties"> <props> <prop key="kp1">p1</prop> <prop key="kp2">p2</prop> <prop key="kp3">p3</prop> </props> </property> </bean> <!-- 同一种结构的集合属性可以混用 --> <bean id="someBean2" class="ioc03.SomeBean"> <!-- 使用list标签对List类型的属性进行装配 该标签存在无数个value子标签 每一个value子标签装配一个元素的值 --> <property name="list"> <list> <value>l1</value> <value>l2</value> <value>l3</value> </list> </property> <property name="set"> <list> <value>s1</value> <value>s2</value> <value>s3</value> </list> </property> <property name="arr"> <list> <value>s1</value> <value>s2</value> <value>s3</value> </list> </property> <property name="map"> <map> <entry key="k1" value="m1"></entry> <entry key="k2" value="m2"></entry> <entry key="k3" value="m3"></entry> </map> </property> <property name="properties"> <map> <entry key="kp1" value="p1"></entry> <entry key="kp2" value="p2"></entry> <entry key="kp3" value="p3"></entry> </map> </property> </bean>实例化–>DI–>初始化–>使用–>销毁
无参构造函数实例化对象
<bean id="someBean" class="ioc04.SomeBean"></bean>有参构造函数实例化对象
通过constructor-arg标签来实现有参构造函数的配置一个标签对应构造函数中的一个参数index属性:指定当前参数的索引位置 索引从0开始如果不设置该属性,默认按照参数顺序进行执行 type属性:指定当前参数的类型 该属性一般可以不配置,Spring自动检测参数的类型 <bean id="someBean2" class="ioc04.SomeBean"> <constructor-arg index="1" type="java.lang.String"> <value>admin</value> </constructor-arg> <constructor-arg index="0" type="java.lang.Integer"> <value>1</value> </constructor-arg> </bean>静态工厂实例化对象
静态工厂创建对象的时候,class指向的是当前对应的工厂类的class但是如果仅仅只是通过class指向工厂,根本无法获取到我们想要的bean该bean是根据工厂中对应的方法获取的因此需要通过factory-method进行指定所调用的静态方法名 <bean id="userService" class="ioc05.ObjectFactory" factory-method="getObject"></bean> <bean id="map" class="java.lang.System" factory-method="getenv"></bean> <bean id="javaHome" class="java.lang.System" factory-method="getenv"> <constructor-arg> <value>JAVA_HOME</value> </constructor-arg> </bean>实例工厂实例化对象
该bean是通过工厂bean中的方法获取的因此该bean需要调用指定的工厂bean中的方法在配置中需要指定所使用的工厂bean与工厂方法factory-bean 表示当前所调用的工厂bean是谁其值是当前容器所管理的工厂bean的id值 factory-method 生产当前bean的工厂bean所使用的方法名此处为实例方法默认情况下,IOC容器中所有的bean都是单例的
有些时候,我们需要多个不同的实例
可以通过scope属性更改组件作用域
使得bean不再是单例的
scope属性:组件作用域,值有两种 prototype:每一次调用都会生成一个新的实例singleton:默认值,单例 <bean id="someBean" class="ioc09.SomeBean" scope="prototype"></bean> <bean id="someBean2" class="ioc09.SomeBean"></bean>将当前的bean实现ApplicationContextAware接口
重写其中的setApplicationContext方法
将其作为一个注入操作
其容器的实例是由Spring帮我们传递的
传递到对应的setApplicationContext方法的参数中
将该实例传递到当前的全局变量中,则当前bean中可以获取到当前容器的实例
public class SomeBean implements ApplicationContextAware { private ApplicationContext ac; @Override public void setApplicationContext(ApplicationContext ac) throws BeansException { this.ac = ac; } public void doSome(){ // ApplicationContext ac = new ClassPathXmlApplicationContext("ioc10/spring.xml"); System.out.println("doSome-ac:"+ac); } }继承配置存在两种情况
多个bean,拥有相同的属性,且这些属性具有相同的属性值 此时在容器中可以使用一个抽象的父类对这些属性进行注入这个父类是一个虚拟的、抽象的、并不是真实存在的使用abstract="true"配置当前父类 表示当前的bean并不是真实存在的 在父类中可以对属性进行注入当父类被继承之后,在父类中可以配置子类的所有属性的注入子类通过parent="父类id"配置继承指定的父类 当子类继承父类之后会自动继承父类中一切的配置如果子类中存在了与父类相同的配置则优先使用子类中的配置,相当于重写操作 <bean id="fatherBean" abstract="true"> <property name="id" value="1"></property> <property name="name" value="admin"></property> </bean> <bean id="someBean" class="ioc11.SomeBean" parent="fatherBean"> <property name="password" value="123456"></property> </bean> <bean id="otherBean" class="ioc11.OtherBean" parent="fatherBean"> <property name="salary" value="8000.0"></property> </bean> 同一个bean,在容器中存在多个该bean的实例 在这些bean中,有些属性值相同,有些属性值不相同此时可以定义一个抽象的父类将这些bean中相同的配置均在父类中进行配置所有的bean继承该父类,将会继承父类中的一切配置 <bean id="fatherBean" class="ioc11.SomeBean" abstract="true"> <property name="name" value="admin"/> <property name="password" value="123456"/> </bean> <bean id="someBean" parent="fatherBean"> <property name="id" value="1"/> </bean> <bean id="someBean2" parent="fatherBean"> <property name="id" value="2"/> </bean> <bean id="someBean3" class="ioc11.SomeBean" parent="fatherBean"> <property name="id" value="3"/> </bean>Autowire
只有在其他bean的引用的时候进行使用
通过autowire属性进行自动装配的使用
其值常用的有两种
byType 根据bean的类型进行自动装配在对当前bean的属性进行注入的时候会根据当前属性的类型在当前的容器查找与该属性类型一致的bean当找到了类型一致的bean的时候,会将该bean注入到该属性中该方式存在一种bug 当在容器中找到了多个与属性类型一致的bean的时候此时会报错 byName 根据bean的id进行自动装配在对当前bena的属性进行注入的时候会根据当前属性的名字在当前的容器中查找所有bean的id找到与属性名一致的id的值此时会将该id所在bean注入到对应的属性中由于id属性值具有唯一性,因此不可能找到多个bean <bean id="otherBean" class="ioc12.OtherBean"> <property name="id" value="1"/> <property name="name" value="admin"/> </bean> <bean id="otherBean2" class="ioc12.OtherBean"> <property name="id" value="2"/> <property name="name" value="tom"/> </bean> <!--<bean id="someBean" class="ioc12.SomeBean">--> <!--<property name="otherBean" ref="otherBean"/>--> <!--</bean>--> <!--<bean id="someBean" class="ioc12.SomeBean" autowire="byType"></bean>--> <bean id="someBean" class="ioc12.SomeBean" autowire="byName"></bean>Resource属于简单值装配
该类型一般是操作文件的
在为Resource类型注入值的时候,其值一般指向的是一个文件的路径
值的格式:classpath:路径名/文件名
//File f = new File("ioc13/a.txt"); //Resource resource = new ClassPathResource("ioc13/a.txt"); //File file = resource.getFile(); //System.out.println(file.getName()); //System.out.println(file.length()); // //InputStream in = resource.getInputStream(); //BufferedReader br = new BufferedReader(new InputStreamReader(in)); //System.out.println(br.readLine()); ApplicationContext ac = new ClassPathXmlApplicationContext("ioc13/spring.xml"); //Resource resource = ac.getResource("ioc13/a.txt"); //Resource resource = ac.getResource("classpath:ioc13/a.txt"); SomeBean someBean = (SomeBean) ac.getBean("someBean"); Resource resource = someBean.getResource(); InputStream in = resource.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(in)); System.out.println(br.readLine()); <bean id="someBean" class="ioc13.SomeBean"> <property name="resource" value="classpath:ioc13/a.txt"></property> </bean>该bean本质上是一个工厂
该bean并不是用于创建自己的
而是为了创建另一个bean
在某些时候,某些bean的实例化过程比较麻烦
但是对于使用者而言,只关心最终生成的bean
需要的仅仅只是最终的bean
其过程使用者并不关心
对当前容器中的所有的bean做一个后处理
在初始化之前或者之后做一些额外的处理
实例化–>DI–>postProcessBeforeInitialization–>初始化
–>postProcessAfterInitialization–>使用–>销毁
后处理bean并不是针对某一个bean进行处理
而是针对整个IOC容器
后处理bean是对整个IOC容器中所有的bean都生效
将一个对象使用简单值装配的方式进行值的注入
可以通过编写转换规则将对象与简单值进行转换
编写转换规则的时候,对于需要的转换的简单值
其格式必须有限制
创建一个Java类 该类继承PropertyEditorSupport选择重写你所需要的的方法 void setAsText(String text) 将一个简单值转换成对象 String getAsText() 将一个对象转换成简单值 在操作的时候,提供的方法中只能操作简单值的数据如果想要设置/获取对象的数据,需要使用内置的方法 setValue(Object obj) 设置转换后的对象将简单值转换成对象之后,通过该方法返回对应的对象 getValue() 获取需要转换的对象将对象转换成简单值的时候,获取需要转换的对象是谁 public class AddressEditorSupport extends PropertyEditorSupport { /** * 将简单值text转换成Address对象 * 对于简单值的格式存在要求,其格式必须为:province-city * @param text * @throws IllegalArgumentException */ @Override public void setAsText(String text) throws IllegalArgumentException { String[] arr = text.split("-"); Address address = new Address(); address.setProvince(arr[0]); address.setCity(arr[1]); setValue(address); } }将转换规则注册到Spring容器中
在容器中对转换规则进行配置
<bean id="someBean" class="ioc16.SomeBean"> <property name="id" value="1"/> <property name="name" value="admin"/> <property name="address" value="江苏-南京"/> <property name="date" value="2020-05-29"/> </bean> <!-- 注册转换规则 --> <!-- 使用Spring提供的后处理bean对转换规则进行注册 --> <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <!-- 通过customEditors属性注册所用到的转换规则 可以注册无数个转换规则,其值是一个map类型 key:指向的是所使用到的对象的类型 value:指向的是所使用的转换规则是谁 --> <property name="customEditors"> <map> <entry key="ioc16.Address" value="ioc16.AddressEditorSupport"/> <entry key="java.util.Date" value="ioc16.DateEditorSupport"/> </map> </property> </bean>