IOC 操作 Bean 管理(概念)
1、什么是 Bean 管理
- Bean 管理的两个操作
- Spring 创建对象
- Spring 注入属性
2、Bean 管理操作有两种实现方式
- IOC 操作 Bean 管理 (基于xml)
- IOC 操作 Bean 管理 (基于注解)
IOC 操作 Bean 管理 (基于xml)
1、基于 xml 方式创建对象
<bean id="dao" class="classAddress"></bean> <!--address 地址-->
- 在 spring 配置文件中,使用 bean 标签,标签内添加对应属性,就可以实现对象创建
- bean 中的常用属性值
- id —— 唯一标识
- name —— 同 id 一样,但可以使用特殊符号,以舍弃
- class —— 类全路径(包类路径)
- 创建对象的时候,默认执行无参构造方法
2、基于 xml 方式注入属性
-
DI :依赖注入,就是注入属性。DI 是 IOC 的一种具体实现,需要在创建对象的基础上使用
-
第一种注入方式:使用 set 方法进行注入
-
① 创建类,定义属性和对应的 set 方法
public class book{ private String bname; public void setBname(String bname){ this.bname = bname; } }
-
② 在 spring 配置文件配置对象创建,配置属性注入
方法一:如果要将对象注入到某个类中,那么对应类中需要有 set 方法
<!-- 通过 bean标签 创建对象 --> <bean id="book" class="classAddress"> <!--控制器调用 set 方法--> <property name="attributeName" value="attributeValue"></property> <!-- 将容器中的aaa bean作为传入的参数 外部bean 中有详细介绍 <property name="attributeName" ref="aaa"></property> --> </bean> <!--address 地址 attributName 属性-->
方法二:简化:p 名称空间注入,原理:spring 的底层 set 方法 ```xml <!--在 xml 文件头部 beans 标签中插入 p名称空间--> xmlns:p="http://www.springframework.org/schema/p"
<!--进行属性注入,在 bean 标签中进行操作--> <bean id="book" class="classAddress" p:bname="attributeValue"></bean> <!--address 地址 attributName 属性-->
-
property 标签:控制器调用 set 方法
-
name 属性:决定类中的哪个参数
-
value 属性:创建一个新的对象
-
ref 属性:引用一个已经存在的对象
ref:指当前xml文件中叫做aaa的这个bean,把它当作参数传进class中
-
-
第二种注入方式:使用有参构造进行注入
-
① 创建带有 有参构造方法 的类
-
② 在 spring 配置文件配置对象创建,配置属性注入
<bean id="className" class="ClassAddress"> <constructor-arg name="attributeName" value="attributeValue"/> </bean>
<!-- 第一种根据index参数下标设置 --> <bean id="userT" class="com.kuang.pojo.UserT"> <!-- index指构造方法 , 下标从0开始 --> <constructor-arg index="0" value="kuangshen2"/> </bean> <!-- 第二种根据参数名字设置 --> <bean id="userT" class="com.kuang.pojo.UserT"> <!-- name指参数名 --> <constructor-arg name="name" value="kuangshen2"/> </bean> <!-- 第三种根据参数类型设置 --> <bean id="userT" class="com.kuang.pojo.UserT"> <constructor-arg type="java.lang.String" value="kuangshen2"/> </bean>
-
3、IOC 操作 Bean 管理( xml 注入其他类型属性)
-
① null 值 – 使用
<null/>
标签表示空值<property name="attributeName"> <null/> </property>
-
② 属性值包含特殊符号
- 方法一,<>进行转义
< >
(转义符) - 方法二,把带特殊符号的内容写到 CDATA 中
<property name="attributeName"> <!--注入 <<南京>> --> <value><![CDATA[<<南京>>]]></value> </property>
<![CDATA[]]>
标记为 xml 文档标记- (1) 此部分不能再包含
”]]>”
;
(2) 不允许嵌套使用;
(3)”]]>”
这部分不能包含空格或者换行。 <![CDATA[]]>
表示xml解析器忽略解析,所以更快。
- (1) 此部分不能再包含
- 方法一,<>进行转义
4、注入属性 – 外部bean
-
创建两个类 service 类和 dao 类 ,在 service 设置 userdao 的 set 方法
public class UserDao{ private String uname; public void setUname(String uname) { this.uname = uname; } public void add(){ System.out.println("add+++"); } }
public class UserService{ // 创建 UserDao 类的对象 userdao private UserDao userDao; // 设置 userdao 的 set 方法 public void setUserDao(UserDao userDao){ this.userDao = userDao; } public void servAdd(){ System.out.println("servAdd+++"); userDao.add(); } }
-
在 bean.xml 文件中注入属性 – 外部bean,使用ref
<!-- 将 bean 对象 userDao 通过 ref 属性注入 UserService 类的 userDao 属性中--> <bean id="userService" class="UserService"> <property name="userDao" ref="userDao"></property> </bean> <!-- 创建 UserDao 的 bean 对象 userDao --> <bean id="userDao" class="UserDao"></bean>
-
创建 TestBean 测试类,并调用 spring 加载文件
public class TestBean { @Test public void TestBean_01() { // 1 加载 spring 配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("bean_01.xml"); // 2 获取配置文件中创建的对象 UserService userService = context.getBean("userService", UserService.class); userService.servAdd(); } }
-
输出结果:
servAdd+++ add+++
5、注入属性 – 内部 bean
-
创建 service 类和 dao 类,
-
bean.xml注入属性 – 内部bean
<!-- 内部 bean --> <bean id="userService" class="UserService"> <property name="userDao"> <!-- 通过在 property 属性中新建新的 bean 标签来替代 value/ref 来实现内部 bean 注入属性--> <bean id="userDao" class="UserDao"> <property name="uname" value="guxinhu"></property> </bean> </property> </bean>
-
创建 TestBean 测试类,并调用 spring 加载文件
public class TestBean { @Test public void TestBean_01() { // 1 加载 spring 配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("bean_01.xml"); // 2 获取配置文件中创建的对象 UserService userService = context.getBean("userService", UserService.class); userService.servAdd(); } }
-
输出结果:
servAdd+++ add+++
6、注入属性 – 级联赋值
-
创建 service 类和 dao 类
public class UserDao{ private String uname; // 输出的方法 public void setUname(String uname){ this.uname = uname; } public String toString(){ return "uname:"+uname; } }
public class UserService{ private UserDao userDao; public void setUserDao(UserDao userDao){ this.userDao = userDao; } //设置 userdao 对象的 get 方法 public UserDao getUserDao(){ return userDao; } public void servAdd(){ System.out.println(userDao.toString()); } }
-
bean.xml注入属性 – 级联赋值
<!-- 内部 bean --> <bean id="userService" class="UserService"> <!-- 级联赋值 --> <!-- 第一种方法,类似于 外部bean 注入,区别在 级联赋值 存在property标签--> <property name="userDao" ref="userDao"></property> <!-- 第二种方法,需要在对应的类(service)中,写入对应属性的 get 方法 --> <!-- 使用 UserService 对象 userdao 调用 UserDao 的属性 uname --> <property name="userDao.uname" value="guxinhu"></property> </bean> <bean id="userDao" class="UserDao"> <!-- 级联赋值 存在property标签--> <property name="uname" value="guxinhu"></property> </bean>
-
创建 TestBean 测试类,并调用 spring 加载文件
public class TestBean { @Test public void TestBean_01() { //调用spring配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("bean_01.xml"); //获取配置文件中创建的对象 并放入 userSerice 对象中 UserService userService = context.getBean("userService", UserService.class); // 输出 userService.servAdd(); } }
-
输出结果:
uname:guxinhu
7、注入容器(集合)属性(xml)
数组,list集合,map集合,set集合
-
创建容器的类,和相应属性、set方法
public class Container{ // container -- 容器 // 创建容器 // 数组类型属性 private String[] num; // list 集合类型属性 private List<String> list; // map 集合类型属性 private Map<String,String> maps; // set 集合类型属性 private Set<String> sets; // 相应的set方法 public void setNum(String[] num) { this.num = num; } public void setList(List<String> list) { this.list = list; } public void setMaps(Map<String, String> maps) { this.maps = maps; } public void setSets(Set<String> sets) { this.sets = sets; } //输出的方法 public void test(){ // 数组无法直接输出内容,使用 Arrays.toString() System.out.println("num:"+ Arrays.toString(num)); System.out.println("list:"+list); System.out.println("maps:"+maps); System.out.println("set:"+sets); } }
-
bean.xml 注入属性
<bean id="container" class="Container"> <!-- 给数组 num && value标签 注入属性值 --> <property name="num"> <!-- 数组可以使用 array/list标签 进行属性值注入 --> <array> <value>num1</value> <value>num2</value> </array> </property> <!-- 给list集合 list 注入属性值 --> <property name="list"> <!-- 使用 list标签 && value标签 注入属性值 --> <list> <value>list1</value> <value>list2</value> </list> </property> <!-- 给map集合 maps 注入属性值 --> <property name="maps"> <!-- 使用 map标签 && entry标签 注入属性值 --> <map> <entry key="key1" value="maps1"></entry> <entry key="key2" value="maps2"></entry> </map> </property> <!-- 给set集合 sets 注入属性值 --> <property name="sets"> <!-- 使用 set标签 && value标签 注入属性值 --> <set> <value>set1</value> <value>set2</value> </set> </property> </bean>
-
创建 TestBean 测试类,并调用 spring 加载文件
public class TestBean{ @Test public void TestBean_02(){ //调用spring配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("bean_02.xml"); //获取配置文件中创建的对象 并放入 userSerice 对象中 Container container = context.getBean("container", Container.class); // 输出 container.test(); } }
-
输出结果:
num:[num1, num2] list:[list1, list2] maps:{key1=maps1, key2=maps2} set:[set1, set2]
-
集合中注入对象
<!-- 以list 为例子 --> <!-- 给list集合 list 注入属性值(属性值为对象) --> <bean id="container" class="Container"> <property name="list"> <!-- 使用 list标签 && ref标签 注入属性值 --> <list> <!-- 使用级联赋值(外部bean) --> <ref bean="user1"></ref> <ref bean="user2"></ref> </list> </property> </bean> <bean id="user1" class="UserDao"> <property name="uname" value="gu"></property> </bean> <bean id="user2" class="UserDao"> <property name="uname" value="xin"></property> </bean>
-
集合注入部分其他 xml文件 可用
<!-- 使用 名称空间util ,xml文件 头部中插入--> <!-- 创建list集合类型,名为 userDao 的 bean对象 --> <util:list id="userDao"> <value>gu</value> <value>xin</value> <value>hu</value> </util:list> <!-- 使用 ref 进行注入(外部bean 注入) -->
8、FactoryBean
-
spring 有俩种 bean,一种 普通bean (默认类型),一种 工厂bean(FactoryBean)
-
普通bean:在配置文件中定义的 bean类型 就是返回类型
-
工厂bean:在配置文件中定义的 bean类型 可以和返回类型不一样
-
第一步:创建类,让这个类成为 工厂bean ,实现接口 FactoryBean
-
第二步:实现接口里面的方法(3个方法),在实现的方法中定义返回的 bean类型
public class MyBean implements FactoryBean<Xin>{ // 定义返回的 bean类型——“Xin”,创建一个 Xin类,属性有Xname @Override public Xin getObject() throws Exception{ Xin xin = new Xin(); xin.setXname("asd"); return xin; } } // 在 TestBean 测试类中,接收xml配置文件中创建的对象时,使用 Xin类 的实例化对象,而不是MyBean
-
bean.xml 配置文件
<!-- class属性值为 工厂bean 的绝对位置(全限定名) --> <bean id="myBean" class="MyBean"></bean>
-
9、 Bean 作用域
-
spring 中 Bean (scope属性)定义了 5 种作用域,分别为 singleton(单例)、prototype(原型/多列)、request(web请求)、session(web会话) 和 global session,后三种作用域仅在基于web的应用中使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eLkUu7RA-1650027008018)(C:\Users\30386\Desktop\Spring 框架\img\bean 作用域.png)]
-
Spring中的bean默认都是单例的,即singleton(单实例),在加载spring配置文件时就会创建 单实例对象
<bean id="" class="" scope="singleton"></bean> <!-- 在TeseBean类中,创建多个bean对象的接受对象时,它们的地址一样 -->
-
prototype (多实例),在每次调用getBean()时,就会创建一个新的实例
<bean id="" class="" scope="prototype"></bean> <!-- 在TeseBean类中,创建多个bean对象的接受对象时,它们的地址不一样 -->
10、Bean 生命周期
-
图示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nOTcWnkm-1650027008022)(C:\Users\30386\Desktop\Spring 框架\img\bean 生命周期.png)]
-
第三步,第五步 BeanPostProcessor接口
- 针对所有Spring上下文中所有的bean,可以在配置文档applicationContext.xml中配置一个BeanPostProcessor,然后对所有的bean进行一个初始化之前和之后的代理。
- BeanPostProcessor接口中有两个方法: postProcessBeforeInitialization和postProcessAfterInitialization。
- postProcessBeforeInitialization方法在bean初始化之前执行,
- postProcessAfterInitialization方法在bean初始化之后执行。
-
第四步,bean 的属性 init-method,初始化bean的时候执行,可以针对某个具体的bean进行配置。
<!-- testInit 方法名 --> <bean id="testInitMethod" class="com.TestInitMethod" init-method="testInit"></bean>
-
Spring 容器 Bean 生命周期中,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,常用的设定方式有以下三种:
-
通过实现 InitializingBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法;
-
通过 元素的 init-method/destroy-method属性指定初始化之后 /销毁之前调用的操作方法;
-
在指定方法上加上@PostConstruct 或@PreDestroy注解来制定该方法是在初始化之后还是销毁之前调用但他们之前并不等价。即使3个方法都用上了,也有先后顺序.
Constructor > @PostConstruct >InitializingBean > init-method
-
11、xml 自动装配
-
自动装配是根据指定装配规则(属性名称或者属性类型),spring 自动将属性值进行注入
-
bean标签 autowire 属性实现自动装配,两个值
- byName 根据属性名称注入,注入值 bean 的 id值 和属性名称一至,可以重复
- byType 根据属性类型注入,无法重复
-
xml
<bean id="" class="" autewire="byNaem"></bean> <!-- 假设 Dept 类中存在名为dept的属性 --> <bean id="dept" class=""></bean>
12、xml 引入外部属性文件
-
创建外部属性文件,properties 格式文件,存放外部数据 test.properties
// 赋值方法 key = value prop.gu=gu prop.xin=xin prop.hu=hu
-
xml
<!-- 使用 context名称空间 --> <!-- 引入外部文件 --> <!-- location="外部属性文件的绝对地址" --> <context:property-placeholder location="Test.properties"/> <!-- 配置外部数据 --> <bean id="userService" class="UserService"> <!-- value="${key}" --> <property name="gu" value="${prop.gu}"></property> <property name="xin" value="${prop.xin}"></property> <property name="hu" value="${prop.hu}"></property> </bean>