Spring5——IOC操作Bean管理(基于xml文件)
前言
最近在学习Spring5框架,下面关于Spring5之IOC容器管理Bean的学习笔记和心得,如有错误,欢迎指正。
学习资源:
IOC容器
控制反转(IOC)。IOC容器就是具有依赖注入功能的容器,面向对象中的一种设计原则,可以降低代码之间的耦合度。通过IOC,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所有依赖的对象的引用传递给它,即依赖被注入到对象中。
通俗点来讲,就是通过IOC我们可以使用第三方工具来创建对象,而不必再使用传统方法 new 一个对象,并且可以通过IOC容器将其他对象、属性注入到需要创建的对象中去,这一切都交给IOC进行管理,大大降低代码的耦合度。
- 把对象的创建和对象之间调用的操作都交给Spring进行管理;
- 使用IOC的目的:降低耦合度;
IOC底层原理
- xml解析、工厂模式、反射
IOC接口(BeanFactory)
IOC的思想要基于IOC的容器来完成,本质上就是对象工厂(主要还是要实现 BeanFactory 这个接口);
Spring中对于容器的实现提供了两种方法(也就是两个接口):
- BeanFactory:IOC容器内部使用的接口,一般不提供给开发人员使用(加载配置文件的时候,不会创建对象,而是在获取对象(使用对象)的时候才去创建对象);
- ApplicationContext:BeanFactory的子接口,提供更强大的功能,一般给开发人员进行使用(加载配置文件的时候,就会将配置文件中对象进行创建)。
- l两者都可以加载配置文件,创建对象
- ApplicationContext中接口有实现类
IOC操作Bean管理(基于xml文件)
创建对象:通过在xml文件中使用bean标签,并且在标签中的属性设置值,我们就可以在Java程序中创建一个对象。
比如下面的配置文件中,我们就创建了一个Users类的对象users,并且可以通过users来调用Users类中的add方法。
<?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="users" class="com.blue.spring5.Users"></bean>
</beans>
//在Spring的配置文件中,使用bean标签,并在标签中添加对应的属性,就可以实现对象的创建
//常用属性
id属性:给对象起一个标识,可以通过id获得对象
class属性:写要创建的对象所在的类的全路径
name属性:与id作用类似,但是id中不能添加特殊符号,id中可以
//在创建对象的时候默认执行无参构造器
package com.blue.spring5;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* User: Blueshadow
* Date&Time: 2021/12/8 21:10
*/
public class TestUsers {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Users users = context.getBean("users", Users.class);
users.add();
}
}
注入属性
- 通过xml文件,我们可以在创建对象过程中,将给对象注入需要的属性值。
//DI:依赖注入(注入属性),DI是IOC中的一种具体实现,必须在创建对象的基础上实现
package com.blue.spring5.testDemo;
public class Book {
private String bName;//书名
public void setbName(String bName) {
this.bName = bName;
}
public Book(){}
public Book(String bName) {
this.bName = bName;
}
public static void main(String[] args) {
//set方法注入
Book book = new Book();
book.setbName("西游记");
System.out.println(book.bName);
//有参构造器参数注入
Book book = new Book("西游记");
System.out.println(book.bName);
}
}
- 基于Spring的xml配置文件配置对象创建,配置set方法属性注入
<!--配置属性注入-->
<!--set方法注入属性-->
<bean id="book" class="com.blue.spring5.testDemo.Book">
<!--在bean标签里面使用property标签完成属性注入
name 类里面属性名称
value 向属性注入的值
-->
<property name="bName" value="西游记"></property>
<property name="bauthor" value="罗贯中"></property>
- 基于Spring的xml配置文件配置对象创建,配置参数方法属性注入
<!--用有参构造器注入-->
<!--创建对象-->
<bean id="orders" class="com.blue.spring5.Orders">
<constructor-arg name="oName" value="abc"></constructor-arg>
<constructor-arg name="address" value="china"></constructor-arg>
</bean>
- 基于Spring的xml配置文件注入空值和特殊符号
- 字面量:给类中的属性设置的固定值
- null;
- 特殊符号。
<property name="address">
<value>
<![CDATA[《北京》]]>
</value>
</property>
注入集合类型属性
可以通过配置文件,将集合类型的数据注入到对象属性中去。
-
注入数组类型属性
-
注入List集合类型属性
-
注入Map集合类型属性
<?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="stu" class="com.blue.spring5.collectiontype.Student">
<!--集合类型属性注入-->
<!--数组类型属性注入-->
<property name="course">
<array>
<value>语文</value>
<value>数学</value>
</array>
</property>
<!--list类型集合属性注入-->
<property name="lists">
<list>
<value>张三</value>
<value>李四</value>
</list>
</property>
<!--map类型集合属性注入-->
<property name="map">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PYTHON" value="python"></entry>
</map>
</property>
<!--set类型集合属性注入-->
<property name="set">
<set>
<value>Redis</value>
<value>MySQL</value>
</set>
</property>
</bean>
</beans>
package com.blue.spring5.testDemo;
import com.blue.spring5.collectiontype.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@SuppressWarnings({"all"})
/**
* @Author Blueshadow
* @Date 2021/10/24 20:55
* @Version 1.0
*/
public class TestSpring5 {
@Test
public void testCourse(){
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
Student stu = context.getBean("stu", Student.class);
stu.testDemo();
}
}
package com.blue.spring5.collectiontype;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
//数组类型的属性
private String[] course;
private List<String> lists;
private Map<String,String> map;//k-v结构
private Set<String> set;
public void setSet(Set<String> set) {
this.set = set;
}
public void setCourse(String[] course) {
this.course = course;
}
public void setLists(List<String> lists) {
this.lists = lists;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void testDemo(){
System.out.println(Arrays.toString(course));
System.out.println(lists);
System.out.println(map);
System.out.println(set);
}
}
注入外部Bean
注入外部bean,就是在xml文件中创建两个对象,然后将其中一个对象注入到另一个对象中去,这种方法可以用于处理业务逻辑层和DAO层之间的对象引用。
- xml
<?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">
<!-- service 和 DAO 的对象进行创建-->
<bean id="userService" class="com.blue.service.UserService">
<!-- 在 service 中注入 userDAO 对象-->
<property name="userDAO" ref="userDAO"></property>
<!-- 完成了注入-->
</bean>
<!-- 创建 DAO 对象-->
<bean id="userDAO" class="com.blue.dao.UserDAOImpl"></bean>
</beans>
- service
package com.blue.service;
import com.blue.dao.UserDAOImpl;
import com.blue.dao.UserDAOInterface;
/**
* User: Blueshadow
* Date&Time: 2021/12/6 16:42
*/
public class UserService {
//创建 UserDAO 类型属性
private UserDAOInterface userDAO;
public UserDAOInterface getUserDAO() {
return userDAO;
}
public void setUserDAO(UserDAOInterface userDAO) {
this.userDAO = userDAO;
}
public void add(){
System.out.println("Service add ...");
userDAO.upDate();
}
}
注入内部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注入操作-->
<bean id="emp" class="com.blue.bean.Emp">
<property name="name" value="jack"></property>
<property name="gender" value="男"></property>
<property name="dept">
<!-- 再嵌套定义一个对象-->
<bean id="dept" class="com.blue.bean.Dept">
<property name="dname" value="开发部"></property>
</bean>
</property>
</bean>
</beans>
- 级联赋值1
<?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="emp" class="com.blue.bean.Emp">
<property name="name" value="jack"></property>
<property name="gender" value="男"></property>
<!-- 级联赋值-->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.blue.bean.Dept">
<property name="dname" value="财务部"></property>
</bean>
</beans>
- 级联赋值2
<?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="emp" class="com.blue.bean.Emp">
<property name="name" value="jack"></property>
<property name="gender" value="男"></property>
<!-- 级联赋值-->
<property name="dept" ref="dept"></property>
<!-- 需要有dept对象的get方法-->
<property name="dept.dname" value="技术部"></property>
</bean>
<bean id="dept" class="com.blue.bean.Dept">
</bean>
</beans>
Bean管理
Factory Bean
- Spring中有两种bean,一种是普通bean,一种是 FactoryBean(工厂bean)
- 普通bean在配置文件中,定义的对象类型就是返回类型
- FactoryBean在配置文件中定义的对象类型可以和返回类型不同
package com.blue.factorybean;
import com.blue.colectiontype.Course;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* User: Blueshadow
* Date&Time: 2021/12/7 20:15
* 该类作为一个工厂bean
*/
public class FactoryBean_ implements FactoryBean<Course> {
//自定义要返回的类型
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("1906");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
Bean的作用域
- 在Spring中可以设置,创建的ben实例是单实例还是多实例
- 默认情况下创建的是单实例对象
- 顾名思义:单实例对象就是一个对象,多实例对象就是两个不同的对象
<?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="student" class="com.blue.colectiontype.Stu"></bean>
</beans>
package com.blue.scope;
import com.blue.colectiontype.Stu;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* User: Blueshadow
* Date&Time: 2021/12/7 20:56
*/
public class Scope_ {
public static void main(String[] args) {
new Scope_().testScope();
}
public void testScope(){
ApplicationContext context = new ClassPathXmlApplicationContext("scope.xml");
Stu student1 = context.getBean("student", Stu.class);
Stu student2 = context.getBean("student",Stu.class);
System.out.println("stu1: "+student1);
System.out.println("stu2: "+student2);
//stu1: com.blue.colectiontype.Stu@5f341870
//stu2: com.blue.colectiontype.Stu@5f341870
}
}
- 多实例对象
- 通过bean标签中的scope属性来设置多实例对象(scope属性值:singleton 单实例对象、prototype 多实例对象)
- 两者区别
- singleton 单实例、prototype 多实例
- 设置singleton时,在加载配置文件过程中,会创建单实例对象
- 设置prototype时,不是在加载配置文件过程中创建对象,而是在调用 getBean 方法过程中创建对象,即每次创建的都是一个新的对象
<?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="student" class="com.blue.colectiontype.Stu" scope="prototype"></bean>
</beans>
package com.blue.scope;
import com.blue.colectiontype.Stu;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* User: Blueshadow
* Date&Time: 2021/12/7 20:56
*/
public class Scope_ {
public static void main(String[] args) {
new Scope_().testScope();
}
public void testScope(){
ApplicationContext context = new ClassPathXmlApplicationContext("scope.xml");
Stu student1 = context.getBean("student", Stu.class);
Stu student2 = context.getBean("student",Stu.class);
System.out.println("stu1: "+student1);
System.out.println("stu2: "+student2);
//stu1: com.blue.colectiontype.Stu@f6c48ac
//stu2: com.blue.colectiontype.Stu@13deb50e
}
}
Bean的生命周期
- 对象创建~对象销毁的过程被称作bean的生命周期
- 通过无参构造器去创建实例;
- 为bean的属性设置对应的值或者对其他bean的引用(调用set方法);
- 把bean的实例传递给bean的后置处理器的方法 postProcessBeforeInitialization;
- 调用bean里面初始化的方法(需要进行配置);
- 把bean的实例传递给bean的后置处理器的方法 postProcessAfterInitialization;
- bean可以使用了(对象获取到了);
- 当容器在关闭的时候,会调用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 id="orders" class="com.blue.lifecycle.Orders" init-method="initMethod" destroy-method="destoryMethod">
<property name="oname" value="vivo"></property>
</bean>
</beans>
package com.blue.lifecycle;
/**
* User: Blueshadow
* Date&Time: 2021/12/7 21:18
*/
public class Orders {
private String oname;
public Orders() {
System.out.println("执行了Orders的无参构造器 ...");
}
public void setOname(String oname) {
this.oname = oname;
System.out.println("调用了setOname 设置属性值 ...");
}
//创建执行的初始化方法
public void initMethod(){
System.out.println("执行初始化方法 ...");
}
//销毁对象的方法
public void destoryMethod(){
System.out.println("执行销毁对象方法 ...");
}
@Override
public String toString() {
return "Orders{" +
"oname='" + oname + '\'' +
'}';
}
}
package com.blue.lifecycle;
import com.sun.xml.internal.ws.api.pipe.ClientTubeAssemblerContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* User: Blueshadow
* Date&Time: 2021/12/7 21:19
*/
public class TestOrders {
public static void main(String[] args) {
new TestOrders().testOrders();
}
public void testOrders(){
ApplicationContext context = new ClassPathXmlApplicationContext("lifecycle.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("获取到了创建出来的实例对象 ... "+orders);
System.out.println(orders);
//手动销毁实例对象
((ClassPathXmlApplicationContext)context).close();
}
//执行了Orders的无参构造器 ...
//调用了setOname 设置属性值 ...
//执行初始化方法 ...
//获取到了创建出来的实例对象 ... Orders{oname='vivo'}
//Orders{oname='vivo'}
//执行销毁对象方法 ...
}
xml自动装配
- 手动装配:在xml文件中手动输入要创建的对象的属性值;
- 自动装配:根据指定的装配规则(属性类型、属性名称),自动将匹配的属性值进行注入
<?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="emp" class="com.blue.autowire.Emp" autowire="byType">
<!-- <property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.blue.autowire.Dept"></bean>
</beans>
外部属性文件
这种操作在连接数据库的过程中会用到,可以将properties配置文件引入到xml文件中,然后在程序中引用xml文件来创建相应的对象。
<?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: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/context http://www.springframework.org/schema/beans/spring-context.xsd">
<!-- 直接配置连接池-->
<!-- 创建druid连接对象-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- dataSource.setDriverClassName("com.mysql.jdbc.Driver");
set方法注入
-->
<!-- 获取properties文件内容,根据key获取,使用spring表达式获取 -->
<!-- <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>-->
<!-- <property name="url" value="jdbc:mysql://locahost:3306/test"></property>-->
<!-- <property name="username" value="root"></property>-->
<!-- <property name="password" value="xxx"></property>-->
<!-- 引入外部的properties属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 配置连接池-->
<property name="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
</beans>
#key=value
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
#url=jdbc:mysql://localhost:3306/girls
username=root
password=xxx
#initial connection Size
initialSize=10
#min idle connecton size
minIdle=5
#max active connection size
maxActive=50
#max wait time (5000 mil seconds)
maxWait=5000