本文主要是介绍Spring入门01-IOCDI,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
一、学习导图
二、Spring 框架概念
三、基本环境搭建
四、SpringIOC容器Bean对象的实例化的模拟实现
什么是IOC?
(1)定义bean属性对象
(2)添加dom4j坐标依赖
(3)自定义spring.xml配置文件
(4)定义bean工厂接口
(5)测试
五、配置文件加载
六、IOC容器Bean对象实例化
Spring三种实例化Bean的方式比较
七、Spring IOC 注入
注入方式的选择
七、Spring IOC 自动装配(注入)
注解方式注入 Bean
@Resource注解
@Autowired注解
八、Spring IOC 扫描器
九、Bean的作用域与生命周期
1.Bean的作用域
(1)lazy-init属性(懒加载)
lazy-init属性为什么要设置为false?
(2)Scope属性:
1.singleton:单例作用域(默认)
什么对象适合作为单例对象?(什么对象适合交给IOC容器实例化?)
2.prototype:原型作用域
2.Bean的生命周期
一、学习导图
二、Spring 框架概念
三、基本环境搭建
1.新建Maven项目:模板quick-start
2.配置pom文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.msb</groupId><artifactId>Spring01</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><name>Spring01</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- 添加Spring框架的核心依赖 --><!-- https://mvnrepository.com/artifact/org.springframework/spring-context --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.4.RELEASE</version></dependency></dependencies>
</project>
3.编写Bean对象,如dao层、service层对象。
4.添加spring配置文件
在项目的src下创建resources并标记为Resources Root
5.测试类中加载配置文件
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--xmlns 即 xml namespace xml使用的命名空间xmlns:xsi 即xml schema instance xml 遵守的具体规范xsi:schemaLocation 本文档xml遵守的规范 官方指定--><!--id:bean标签的唯一标识,一般是Javabean对象的名称的首字母小写class:Javabean对象的唯一路径(包名+类名)--><bean id="userService" class="com.msb.service.UserService"/><bean id="userService02" class="com.msb.service.UserService02"/></beans>
6.启动
public class Starter01 {public static void main(String[] args) {//得到spring的上下文环境ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");//通过id属性得到指定的bean对象UserService userService = (UserService) ac.getBean("userService");//调用实例化好的javabean对象的方法userService.test();//通过id属性得到指定的bean对象UserService02 userService02 = (UserService02) ac.getBean("userService02");//调用实例化好的javabean对象的方法userService02.test();}
}
四、SpringIOC容器Bean对象的实例化的模拟实现
什么是IOC?
解释1:创建对象的权利,或者是控制的位置,由JAVA代码转移到spring容器,由spring的容器控制对象的创建,就是控制反转。spring创建对象时,会读取配置文件中的信息,然后使用反射给我们创建好对象之后在容器中存储起来,当我们需要某个对象时,通过id获取对象即可,不需要我们自己去new。
一句话:创建对象交给容器
解释2:Spring框架管理这些Bean的创建工作,即由用户管理Bean转变为框架管理Bean,这个就叫 控制反转 - Inversion of Control (IoC)
部分引用自什么是控制反转(IOC)? - 知乎
思路:
- 定义Bean 工厂接口,提供获取bean方法
- 定义Bean工厂接口实现类,解析配置文件,实例化Bean对象
- 实现获取 Bean 方法
(1)定义bean属性对象
/*** Bean属性对象* 用来存放配置文件中bean标签对应的id和class属性值*/
public class MyBean {private String id; //bean标签的id属性值private String clazz; //bean标签的class属性值public MyBean() {}public MyBean(String id, String clazz) {this.id = id;this.clazz = clazz;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getClazz() {return clazz;}public void setClazz(String clazz) {this.clazz = clazz;}
}
(2)添加dom4j坐标依赖
<!-- dom4j --><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency><!-- XPath --><dependency><groupId>jaxen</groupId><artifactId>jaxen</artifactId><version>1.1.6</version></dependency>
(3)自定义spring.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<beans><!-- 设置JavaBean对应的bean标签 --><bean id="userDao" class="com.msb.dao.UserDao"></bean><bean id="userService" class="com.msb.service.UserService"></bean>
</beans>
(4)定义bean工厂接口
public interface MyFactory {//通过id属性值获取对象public Object getBean(String id);
}
实现类:
/*** 模拟Spring的实现* 1. 通过带参构造器得到对应的配置文件* 2. 通过dom4j解析配置文件(xml文件),得到List集合(存放bean标签的id和class属性值)* 3. 通过反射得到对应的实例化对象,放置在Map对象 (遍历List集合,通过获取对应的class属性,利用Class.forName(class).newIntance())* 4. 通过id属性值获取指定的实例化对象*/
public class MyClassPathXmlApplicationContext implements MyFactory {private List<MyBean> beanList; // 存放从配置文件中获取到的bean标签的信息(MyBean代表的就是每一个bean标签)private Map<String, Object> beanMap = new HashMap<>(); // 存放实例化好的对象,通过id获取对应的对象/* 通过带参构造器得到对应的配置文件 */public MyClassPathXmlApplicationContext(String fileName) {/* 通过dom4j解析配置文件(xml文件),得到List集合 */this.parseXml(fileName);/* 通过反射得到对应的实例化对象,放置在Map对象 */this.instanceBean();}/*** 通过dom4j解析配置文件(xml文件),得到List集合* 1. 获取解析器* 2. 获取配置文件的URL* 3. 通过解析器解析配置文件(xml文件)* 4. 通过xpath语法解析,获取beans标签下的所有bean标签* 5. 通过指定的解析语法解析文档对象,返回元素集合* 6. 判断元素集合是否为空* 7. 如果元素集合不为空,遍历集合* 8. 获取bean标签元素的属性 (id和class属性值)* 9. 获取MyBean对象,将id和class属性值设置到对象中,再将对象设置到MyBean的集合中** @param fileName*/private void parseXml(String fileName) {
// 1. 获取解析器SAXReader saxReader = new SAXReader();
// 2. 获取配置文件的URLURL url = this.getClass().getClassLoader().getResource(fileName);try {
// 3. 通过解析器解析配置文件(xml文件)Document document = saxReader.read(url);
// 4. 通过xpath语法解析,获取beans标签下的所有bean标签XPath xPath = document.createXPath("beans/bean");
// 5. 通过指定的解析语法解析文档对象,返回元素集合List<Element> elementList = xPath.selectNodes(document);
// 6. 判断元素集合是否为空if (elementList != null && elementList.size() > 0) {// 实例化beanListbeanList = new ArrayList<>();
// 7. 如果元素集合不为空,遍历集合for (Element el : elementList) {
// 8. 获取bean标签元素的属性 (id和class属性值)String id = el.attributeValue("id");//id属性值String clazz = el.attributeValue("class");//class属性值
// 9. 获取MyBean对象,将id和class属性值设置到对象中,再将对象设置到MyBean的集合中MyBean myBean = new MyBean(id, clazz);beanList.add(myBean);}}} catch (DocumentException e) {e.printStackTrace();}}/*** 通过反射得到对应的实例化对象,放置在Map对象* 1. 判断对象集合是否为空,如果不为空,则遍历集合,获取对象的id和calss属性* 2. 通过类的全路径名 反射 得到实例化对象 Class.forName(class).newInstance()* 3. 将对应的id和实例化好的bean对象设置到map对象中*/private void instanceBean() {
// 1. 判断对象集合是否为空,如果不为空,则遍历集合,获取对象的id和calss属性if (beanList != null && beanList.size() > 0) {for (MyBean bean : beanList) {String id = bean.getId();String clazz = bean.getClazz();try {
// 2. 通过类的全路径名 反射 得到实例化对象 Class.forName(class).newInstance()Object o = Class.forName(clazz).newInstance();
// 3. 将对应的id和实例化好的bean对象设置到map对象中beanMap.put(id, o);} catch (Exception e) {e.printStackTrace();}}}}/*** 通过id获取对应的map对象中的value(实例化好的bean对象)** @param id* @return*/@Overridepublic Object getBean(String id) {Object obj = beanMap.get(id);return obj;}
}
(5)测试
public class App {public static void main(String[] args) {//得到工厂的实现类MyFactory factory = new MyClassPathXmlApplicationContext("spring.xml");//得到对应的实例化对象UserDao userDao = (UserDao) factory.getBean("userDao");UserService userService = (UserService) factory.getBean("userService");userDao.test();userService.test();UserDao userDao02 = (UserDao) factory.getBean("userDao");System.out.println(userDao==userDao02);}
}
五、配置文件加载
- 根据相对路径加载资源(常规)
- 根据绝对路径加载资源(了解)
- 多配置文件加载,可变参数,传入多个文件名
- 多配置文件加载,总的配置文件import其他文件,只需要加载总文件即可
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--通过import导入其他配置文件--><import resource="bean.xml"></import><import resource="spring.xml"></import>
</beans>
六、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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--构造器实例化 对应Bean对象需要提供空构造--><bean id="typeDao" class="com.msb.dao.TypeDao"/><!--静态工厂实例化1.定义工厂类及对应的静态方法2.配置bean对象对应的工厂类及静态方法id:需要被实例化的bean对象的IDclass:静态工厂类的路径factory-method:静态工厂类中实例化bean对象的静态方法--><bean id="typeService" class="com.msb.factory.StaticFactory" factory-method="createService" /><!--实例化工厂1.定义工厂类以及对应的方法2.配置工厂对象3.配置bean对象对应的工厂对象及工厂方法factory-bean:工厂对象对应的id属性值factory-method:工厂类中的方法--><!--工厂对象--><bean id="instanceFactory" class="com.msb.factory.InstanceFactory" /><!--bean对象--><bean id="typeController" factory-bean="instanceFactory" factory-method="createTypeController" /></beans>
public class StaticFactory { //静态/*** 定义对应的静态方法* @return*/public static TypeService createService(){// 实例化前可以做事return new TypeService();}
}public class InstanceFactory { //实例化public TypeController createTypeController(){return new TypeController();}
}
public static void main(String[] args) {/*** 返回的全是单例*/BeanFactory factory = new ClassPathXmlApplicationContext("spring02.xml");//构造器实例化TypeDao typeDao = (TypeDao) factory.getBean("typeDao");typeDao.test();System.out.println(typeDao);System.out.println(factory.getBean("typeDao"));//静态工厂实例化TypeService typeService = (TypeService) factory.getBean("typeService");typeService.test();// 实例化工厂实例化TypeController typeController = (TypeController)factory.getBean("typeController");typeController.test();}
注意:当我们指定Spring使用静态工厂方法来创建Bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静态工厂方法的返回值作为Bean实例,在这个过程中,Spring不再负责创建Bean实例,Bean实例是由用户提供的静态工厂方法提供的。
Spring三种实例化Bean的方式比较
七、Spring IOC 注入
<!--Set方法注入通过property属性注入name:bean对象中属性字段的名称ref:指定bean标签的id属性值 (注入JavaBean)value:具体的值 (基本类型 常用对象|日期 集合)--><bean id="userService" class="com.msb.service.UserService" ><property name="userDao" ref="userDao"/><property name="studentDao" ref="studentDao" /><!-- 常用对象 String --><property name="host" value="127.0.0.1"/><!-- 基本类型 Integer --><property name="port" value="8080" /><!-- List集合 --><property name="list"><list><value>北京</value><value>上海</value><value>深圳</value></list></property><!-- Set集合 --><property name="sets"><set><value>西藏</value><value>新疆</value><value>云南</value></set></property><!-- Map对象 --><property name="map"><map><entry key="周杰伦" value="晴天"/><entry><key><value>许嵩</value></key><value>玫瑰花的葬礼</value></entry><entry><key><value>林俊杰</value></key><value>江南</value></entry></map></property><!-- properties属性对象 --><property name="properties"><props><prop key="sd">山东</prop><prop key="hb">河北</prop><prop key="hn">河南</prop></props></property></bean>
<!--构造器注入设置构造器所需要的的参数通过constructor-arg标签设置构造器的参数name:属性名称ref:要注入的bean对象对应的bean标签的id属性值value:数据具体的值index:参数的位置(从0开始)--><bean id="userService02" class="com.msb.service.UserService02"><constructor-arg ref="userDao02" name="userDao02"/><constructor-arg ref="studentDao" name="studentDao"/><constructor-arg name="uname" value="abc"/></bean><bean id="userDao02" class="com.msb.dao.UserDao02"/><bean id="studentDao" class="com.msb.dao.StudentDao"/><!--<!–循环依赖问题–><bean id="accountService" class="com.msb.service.AccountService"><constructor-arg name="accountDao" ref="accountDao"/></bean><bean id="accountDao" class="com.msb.dao.AccountDao"><constructor-arg name="accountService" ref="accountService"/></bean>--><!--如果出现循环依赖,需要通过set注入解决--><bean id="accountService" class="com.msb.service.AccountService"><property name="accountDao" ref="accountDao"/></bean><bean id="accountDao" class="com.msb.dao.AccountDao"><property name="accountService" ref="accountService"/></bean><!--定义bean对象--><bean id="typeService" class="com.msb.service.TypeService"><property name="typeDao" ref="typeDao"/></bean><!--静态工厂注入:通过静态工厂实例化需要被注入的对象-->
<!-- <bean id="typeDao" class="com.msb.factory.StaticFactory" factory-method="createTypeDao"/>--><!--实例化工厂注入:通过实例化工厂实例化需要被注入的对象--><bean id="instanceFactory" class="com.msb.factory.InstanceFactory" ></bean><bean id="typeDao" factory-bean="instanceFactory" factory-method="createTypeDao"/></beans>
注入方式的选择
<?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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
"><!--p名称空间 spring2.5以后,为了简化setter方法属性注入,引用p名称空间的概念,可以将<property> 子元素,简化为<bean>元素属性配置。--><bean id="userDao" class="com.msb.dao.UserDao"></bean><bean id="userService03" class="com.msb.service.UserService03"p:host="127.0.0.1"p:userDao-ref="userDao"/></beans>
七、Spring 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"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--开启自动化装配(注入)--><context:annotation-config /></beans>
参考:<context:annotation-config/>的作用_tiny-dong的博客-CSDN博客
@Resource注解
@Resource注解实现自动注入 (反射)
1. 注解默认通过属性字段名称查找对应的bean对象(属性字段名称与bean标签的id属性值一致)
2. 如果属性字段名称不一样,则会通过类型(Class)类型
3. 属性字段可以提供set方法 也可以不提供
4. 注解可以声明在属性字段上 或 set方法级别
5. 可以设置注解的name属性,name属性值要与bean标签的id属性值一致(如果设置了name属性,则会按照name属性查询bean对象)
6. 当注入接口时,如果接口只有一个实现类,则正常实例化;如果接口有多个实现类,则需要使用name属性指定需要被实例化的bean对象
@Autowired注解
@Autowired注解实现自动化注入
1. 注解默认使用类型(Class类型)查找bean对象,与属性字段名称没有关系
2. 属性字段可以提供set方法 也可以不提供
3. 注解可以声明在属性级别 或 set方法级别
4. 如果想要通过指定名称查找bean对象,需要结合@Qualifier使用(通过设置value属性值查找,value属性值要bean标签的id属性值保持一致)
八、Spring IOC 扫描器
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--Spring IOC扫描器作用:bean对象的统一管理,简化开发配置,提高开发效率。1. 设置自动化扫描的范围如果bean对象未在扫描范围范围,即使声明了注解,也不会被实例化2. 在需要被实例化的JavaBean的类上添加指定的注解(注解声明在类级别) (ben对象的id属性默认是 类的首字母小写)Dao层:@RepositoryService层:@ServiceController层:@Controller任意类:@Component注:开发过程中建议按照规则声明注解。--><!-- 设置自动化扫描的范围 --><context:component-scan base-package="com.msb" /></beans>
九、Bean的作用域与生命周期
1.Bean的作用域
(1)lazy-init属性(懒加载)
如果设置为true,表示懒加载,容器在启动时,不会实例化bean对象,在程序调用时才会实例化;
如果设置false(默认),表示不懒加载,容器启动则实例化bean对象。
lazy-init属性为什么要设置为false?
- 可以提前发现潜在的配置问题
- Bean对象在启动时就设置在单例缓存池中,使用时不需要再去实例化bean对象,提高程序运行效率
(2)Scope属性:
1.singleton:单例作用域(默认)
注意:
- 默认懒加载是false即Spring容器启动时实例化。如果等于true作用是指Spring容器启动的时候不会去实例化这个bean, 而是在程序调用时才去实例化。
- 默认单例:被管理的Bean只会在IOC容器中存在一个实例,对于所有获取该Bean的操作,Spring容器将只返回同一个Bean。
- 容器在启动的情况下就实例化所有singleton 的 bean对象,并缓存与容器中。
总结:Spring IOC容器在启动时,会将所有在singleton作用域中的bean对象实例化,并设置到单例缓存池中。
配置如下:
<bean id="roleService" class="com.xxxx.service.RoleService" scope="prototype"></bean>
什么对象适合作为单例对象?(什么对象适合交给IOC容器实例化?)
无状态的对象(不存在改变当前对象状态的成员变量)比如:controller层、service层、dao层。
2.prototype:原型作用域
通过scope="prototype" 设置bean的类型 ,每次向Spring容器请求获取Bean都返回一个全新的Bean,相对于"singleton"来说就是不缓存Bean,每次都是一个根据Bean定义创建的全新Bean。
总结:Spring IOC容器在启动时,不会将bean对象实例化设置到单例缓存池中,每次实例化对象都会创建一个新的实例。
2.Bean的生命周期
在Spring中,Bean的生命周期包括Bean的定义、初始化、使用和销毁4个阶段。
Bean的定义
在配置文件中定义bean,通过bean标签定义对应bean对象。
Bean的初始化
IOC容器启动时,自动实例化Bean对象
1. 在配置文档中通过指定 init-method 属性来完成。
2. 实现 org.springframework.beans.factory.InitializingBean 接口。
<!-- Bean的初始化:在配置文档中通过指定 init-method 属性来完成-->
<bean id="roleService" class="com.msb.service.RoleService" init-method="init"/>
<!-- Bean的初始化:实现 org.springframework.beans.factory.InitializingBean 接口 -->
<bean id="roleService" class="com.msb.service.RoleService"/>
Bean的使用
1. 使用 BeanFactory对象
2. 使用 ApplicationContext对象
Bean的销毁
步骤一:通过 AbstractApplicationContext 对象,调用其close方法实现bean的销毁过程
// 通过 AbstractApplicationContext 对象,调用其close方法实现bean的销毁过程
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("spring03.xml");
System.out.println("销毁前");
ac.close();
System.out.println("销毁后");
步骤二:在配置文件中指定对应销毁的方法 destroy-method
<!-- Bean的销毁 -->
<bean id="roleService" class="com.msb.service.RoleService" destroy-method="destroy"/>
这篇关于Spring入门01-IOCDI的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!