IOC是容器,用于管理资源
IOC:Inversion of Control 反转控制
DI:Dependecy Injection 依赖注入 组件以预先定义好的方式接受来自容器的资源注入
spring提供两种方式:
1.BeanFactory
IOC容器的基本实现,是Spring内部使用的接口,面向spring本身
2.ApplicationContext
BeanFactory的子接口,提供更多高级特性,面向spring使用者
ApplicationContext的主要实现类:
ClassPathXmlApplicationContext:通过读取类路径下的XML格式的配置文件创建IOC容器对象
FileSystemXmlApplicaionContext:通过文件系统路径读取XML格式的配置文件创建IOC容器对象
spring管理的对象为组件或bean
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
创建spring的配置文件xml文件
自己获取IOC容器 通过类路径下的XML获取IOC
IOC可以有多个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对象 将对象交给ioc容器管理
id:bean的唯一标识,不能重复
class:设置bean对象所对应的类型
-->
<bean id="helloworld" class="edu.npu.mwan.spring.pojo.HelloWorld"></bean>
</beans>
public class HelloWorld {
public void sayHello(){
System.out.println("hello,s[ring");
}
}
public class Hello {
@Test
public void test(){
ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
//根据name获取bean 管理helloworld
HelloWorld helloWorld=(HelloWorld) ioc.getBean("helloworld");
helloWorld.sayHello();
}
}
反射加工厂模式
什么是反射:在获取到 Class 对象之后,反向获取和操作对象的各种信息
IOC创建对象用的都是无参构造
方式一:根据id获取
**方式二:**根据类型获取
@Test
public void testHelloWorld(){
ApplicationContext ac = new
ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld bean = ac.getBean(HelloWorld.class);
bean.sayHello();
}
**方式三:**根据id和类型
@Test
public void testHelloWorld(){
ApplicationContext ac = new
ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld bean = ac.getBean("helloworld", HelloWorld.class);
bean.sayHello();
}
④注意
当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看:『对象 instanceof 指定的类型』的返回结果,只要返回的是true就可以认定为和类型匹配,能够获取到。
什么是依赖注入:
为bean的属性赋值
setter:配置bean时为属性赋值
<bean id="studentOne" class="com.atguigu.spring.bean.Student">
<!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
<!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关)
-->
<!-- value属性:指定属性值 -->
<property name="id" value="1001"></property>
<property name="name" value="张三"></property>
<property name="age" value="23"></property>
<property name="sex" value="男"></property>
</bean>
构造器注入:添加有参构造后在配置bean时
<bean id="studentTwo" class="com.atguigu.spring.bean.Student">
<constructor-arg value="1002"></constructor-arg>
<constructor-arg value="李四"></constructor-arg>
<constructor-arg value="33"></constructor-arg>
<constructor-arg value="女"></constructor-arg>
</bean>
依赖注入的特殊值处理
字面量赋值
什么是字面量?即我们看到的数据本身
<property name="name" value="张三"/>
此时张三是字面量
null值
<property name="name">
<null />
</property>
错误写法
<property name="name" value="null"></property>
xml实体
<!-- 解决方案一:使用XML实体来代替 -->
<property name="expression" value="a < b"/>
<!-- 解决方案二:使用CDATA节 -->
<!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
<!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
<!-- 所以CDATA节中写什么符号都随意 -->
<value><![CDATA[a < b]]></value>
为类类型属性赋值
方式一:引用外部已声明的bean
<bean id="clazzOne" class="com.atguigu.spring.bean.Clazz">
<property name="clazzId" value="1111"></property>
<property name="clazzName" value="财源滚滚班"></property>
</bean>
<bean id="studentFour" class="com.atguigu.spring.bean.Student">
<property name="id" value="1004"></property>
<property name="name" value="赵六"></property>
<property name="age" value="26"></property>
<property name="sex" value="女"></property>
<!-- ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值 -->
<property name="clazz" ref="clazzOne"></property>
</bean>
方式二:内部bean
<bean id="studentFour" class="com.atguigu.spring.bean.Student">
<property name="id" value="1004"></property>
<property name="name" value="赵六"></property>
<property name="age" value="26"></property>
<property name="sex" value="女"></property>
<property name="clazz">
<!-- 在一个bean中再声明一个bean就是内部bean -->
<!-- 内部bean只能用于给属性赋值,不能在外部通过IOC容器获取,因此可以省略id属性 -->
<bean id="clazzInner" class="com.atguigu.spring.bean.Clazz">
<property name="clazzId" value="2222"></property>
<property name="clazzName" value="远大前程班"></property>
</bean>
</property>
</bean>
为数组类型属性赋值
<property name="hobbies">
<array>
<value>抽烟</value>
<value>喝酒</value>
<value>烫头</value>
</array>
</property>
为集合类型属性赋值
为List集合类型属性赋值
<property name="students">
<list>
<ref bean="studentOne"></ref>
<ref bean="studentTwo"></ref>
<ref bean="studentThree"></ref>
</list>
</property>
为Map集合类型属性赋值
<property name="teacherMap">
<map>
<entry>
<key>
<value>10010</value>
</key>
<ref bean="teacherOne"></ref>
</entry>
<entry>
<key>
<value>10086</value>
</key>
<ref bean="teacherTwo"></ref>
</entry>
</map>
</property>
p命名空间
-ref表示实体类赋值
<bean id="studentSix" class="com.atguigu.spring.bean.Student"
p:id="1006" p:name="小明" p:clazz-ref="clazzOne" p:teacherMapref="teacherMap"></bean>
在Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围
如果是在WebApplicationContext环境下还会有另外两个作用域
bean对象创建(调用无参构造器)
给bean对象设置属性
bean对象初始化之前操作(由bean的后置处理器负责)
bean对象初始化(需在配置bean时指定初始化方法)
bean对象初始化之后操作(由bean的后置处理器负责)
bean对象就绪可以使用
bean对象销毁(需在配置bean时指定销毁方法)
IOC容器关闭
根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类
有一个UserController、UserService、UserServiceImpl作为UserService的实现类 UserDao UserDaoImpl
配置bean
使用bean标签的autowire属性设置自动装配效果
自动装配方式:byType
byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值
若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值
null
若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常
NoUniqueBeanDefinitionException
如果属性类型是userService则有对应类型的bean为其赋值,比如 userController中有userService
<bean id="userController"
class="com.atguigu.autowire.xml.controller.UserController" autowire="byType">
</bean>
<bean id="userService"
class="com.atguigu.autowire.xml.service.impl.UserServiceImpl" autowire="byType">
</bean>
<bean id="userDao" class="com.atguigu.autowire.xml.dao.impl.UserDaoImpl"></bean>
byName
byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值
注解
和 XML 配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测
到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。
本质上:所有一切的操作都是Java代码来完成的,XML和注解只是告诉框架中的Java代码如何执行。
扫描
pring 为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后根据注
解进行后续操作。
Spring配置(applicationContext.xml)文件中可配置扫描范围
<context:component-scan base-package="com.atguigu">
</context:component-scan>
组件所对应的bean的id
在我们使用XML方式管理bean的时候,每个bean都有一个唯一标识,便于在其他地方引用。现在使用
注解后,每个组件仍然应该有一个唯一标识。
默认情况
类名首字母小写就是bean的id。例如:UserController类对应的bean的id就是userController。
基于注解的自动装配
@Autowired注解
在成员变量上直接标记@Autowired注解即可完成自动装配,不需要提供setXxx()方法。以后我们在项
目中的正式用法就是这样。
@Autowired工作流程
注:先根据类型查找