Spring IOC
次要内容
Spring 框架
Spring 框架概念
Spring 是泛滥开源java我的项目中的一员,基于分层的javaEE利用一站式轻量级开源框架,次要外围是 IOC(管制反转/依赖注入)与 AOP(面向切面)两大技术,实现我的项目在开发过程中的轻松解耦,进步我的项目的开发效率。
在我的项目中引入 Spring 立刻能够带来上面的益处 升高组件之间的耦合度,实现软件各层之间的解耦。能够应用容器提供的泛滥服务,如:事务管理服务、音讯服务等等。当咱们应用容器治理事务时,开发人员就不再须要手工管制事务.也不需解决简单的事务流传。 容器提供单例模式反对,开发人员不再须要本人编写实现代码。 容器提供了AOP技术,利用它很容易实现如权限拦挡、运行期监控等性能。
Spring 源码架构
Spring 总共大概有20个模块,由1300多个不同的文件形成。而这些组件被别离整合在外围容器(Core Container)、Aop(Aspect Oriented Programming)和设施反对(Instrmentation)、数据拜访及集成(Data Access/Integeration)、Web、报文发送(Messaging)、测试6个模块汇合中。
- 外围容器:Spring-beans 和 Spring-core 模块是 Spring 框架的外围模块,蕴含管制反转(Inversion of Control, IoC)和依赖注入(Dependency Injection, DI),外围容器提供 Spring 框架的基本功能。外围容器的次要组件是 BeanFactory,工厂模式的实现。BeanFactory 应用管制反转(IOC) 思维将应用程序的配置和依赖性标准与理论的利用程序代码离开。
Spring 上下文Spring Context:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包含企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度性能。
Spring-Expression 模块是对立表达式语言(unified EL)的扩大模块,能够查问、治理运行中的对象,同时也不便的能够调用对象办法、操作数组、汇合等。它的语法相似于传统EL,但提供了额定的性能,最出色的要数函数调用和简略字符串的模板函数。
- Spring-AOP:Spring-aop是Spring的另一个外围模块, 在Spring中,他是以JVM的动静代理技术为根底,而后设计出了一系列的Aop横切实现,比方前置告诉、返回告诉、异样告诉等。通过其配置管理个性,Spring AOP 模块间接将面向切面的编程性能集成到了 Spring 框架中。所以,能够很容易地使 Spring 框架治理的任何对象反对 AOP。
- Spring Data Access(数据拜访):由Spring-jdbc、Spring-tx、Spring-orm、Spring-jms和Spring-oxm 5个模块组成 Spring-jdbc 模块是 Spring 提供的JDBC形象框架的次要实现模块,用于简化 Spring JDBC。
Spring-tx 模块是SpringJDBC事务管制实现模块。应用Spring框架,它对事务做了很好的封装,通过它的Aop配置,能够灵便的配置在任何一层。
Spring-Orm 模块是ORM框架反对模块,次要集成 hibernate, Java Persistence API (JPA) 和 Java Data Objects (JDO) 用于资源管理、数据拜访对象(DAO)的实现和事务策略。
Spring-Jms 模块(Java Messaging Service)可能发送和承受信息。
Spring-Oxm 模块次要提供一个形象层以撑持OXM(OXM 是 Object-to-XML-Mapping 的缩写,它是一个O/M-mapper,将java对象映射成 XML 数据,或者将 XML 数据映射成 java 对象),例如:JAXB, Castor, XMLBeans, JiBX 和 XStream 等。
- Web 模块:由Spring-web、Spring-webmvc、Spring-websocket和Spring-webmvc-portlet 4个模块组成,Web 上下文模块建设在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。Web 模块还简化了解决多局部申请以及将申请参数绑定到域对象的工作。
- 报文发送:即Spring-messaging模块。
Spring-messaging是Spring4 新退出的一个模块,主要职责是为Spring 框架集成一些根底的报文传送利用。
- 单元测试:即Spring-test模块。Spring-test模块次要为测试提供反对
Spring 框架环境搭建
环境要求
JDK 版本:
JDK 1.7 及以上版本
Spring版本:
Spring 5.x版本
新建 Maven 我的项目
- 创立 Maven 的一般 Java 我的项目
- 设置我的项目的坐标
- 设置我的项目的 Maven 环境
- 设置我的项目的名称和寄存的工作空间
调整我的项目环境
批改 JDK 版本
<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>
批改单元测试 JUnit 版本
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope></dependency>
build标签中的pluginManagement标签
<!--删除build标签中的pluginManagement标签--><build></build>
增加 Spring 框架的依赖坐标
Maven仓库:https://mvnrepository.com/
<!-- 增加Spring框架的外围依赖 --><dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.4.RELEASE</version></dependency>
编写 Bean 对象
package com.xxxx.service;public class UserService { public void test(){ System.out.println("Hello Spring!"); }}
增加Spring 配置文件
- 在我的项目的src下创立文件夹 resources(Alt+insert)
- 将 resources 标记为资源目录
在 srcmainresources 目录下新建 spring.xml 文件,并拷贝官网文档提供的模板内容到 xml 中。
配置 bean 到 xml 中,把对应 bean 纳入到 Spring 容器来治理
spring.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- xmlns 即 xml namespace xml应用的命名空间 xmlns:xsi 即xml schema instance xml 恪守的具体标准 xsi:schemaLocation 本文档xml恪守的标准 官网指定 --> <bean id="userService" class="com.xxxx.service.UserService"></bean></beans>
在 spring.xml 中配置 Bean 对象
<!-- id:bean对象的id,惟一标识。个别是Bean对象的名称的首字母小写 class:bean对象的类门路--><bean id="userService" class="com.xxxx.service.UserService"></bean>
加载配置文件,获取实例化对象
package com.xxxx;import com.xxxx.service.UserService;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class App { public static void main(String[] args) { // 获取Spring上下文环境 (加载配置文件) ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); // 通过getBean办法失去Spring容器中实例化好的Bean对象 (实例化Bean对象) // userService代表的是配置文件中bean标签的id属性值 UserService userService = (UserService) ac.getBean("userService"); // 调用办法 (应用实例化对象) userService.test(); }}
Spring IOC 容器 Bean 对象实例化模仿
思路:
- 定义Bean 工厂接口,提供获取bean办法
- 定义Bean工厂接口实现类,解析配置文件,实例化Bean对象
- 实现获取Bean办法
定义 Bean 属性对象
package com.xxxx.spring;/** * bean对象 * 用来接管配置文件中bean标签的id与class属性值 */public class MyBean { private String id; // bean对象的id属性值 private String clazz; // bean对象的类门路 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; }}
增加 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>
筹备自定义配置文件
spring.xml
<?xml version="1.0" encoding="utf-8" ?><beans> <bean id="userService" class="com.xxxx.service.UserService"></bean> <bean id="accountService" class="com.xxxx.service.AccountService"></bean></beans>
定义 Bean 工厂接口
package com.xxxx.spring;/** * Bean 工厂接口定义 */public interface MyFactory { // 通过id值获取对象 public Object getBean(String id);}
定义 Bean 接口的实现类
package com.xxxx.spring;import org.dom4j.Document;import org.dom4j.DocumentException;import org.dom4j.Element;import org.dom4j.XPath;import org.dom4j.io.SAXReader;import java.net.URL;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * 模仿Spring的实现 * 1、通过结构器失去相干配置文件 * 2、通过dom4j解析xml文件,失去List 寄存id和class * 3、通过反射实例化失去对象 Class.forName(类的全门路).newInstance(); 通过Map<id,Class>存储 * 4、失去指定的实例化对象 */public class MyClassPathXmlApplicationContext implements BeanFactory { private Map beans = new HashMap(); // 实例化后的对象放入map private List<MyBean> myBeans; // 寄存已读取bean 配置信息 /* 1、通过结构器失去相干配置文件 */ public MyClassPathXmlApplicationContext(String fileName) { /* 2、通过dom4j解析xml文件,失去List (寄存id和class) */ this.parseXml(fileName); /* 3、通过反射实例化失去对象Class.forName(类门路).newInstance(); 通过Map存储 */ this.instanceBean(); } /** * 通过dom4j解析xml文件,失去List 寄存id和class * 1、获取解析器 * 2、失去配置文件的URL * 3、通过解析器解析xml文件(spring.xml) * 4、通过xpath语法,获取beans标签下的所有bean标签 * 5、通过指定语法解析文档对象,返回汇合 * 6、判断汇合是否为空,遍历汇合 * 7、获取标签元素中的属性 * 8、失去Bean对象,将Bean对象设置到汇合中 * @param fileName */ private void parseXml(String fileName) { // 1、获取解析器 SAXReader reader = new SAXReader(); // 2、失去配置文件的URL URL url = this.getClass().getClassLoader().getResource(fileName); try { // 3、通过解析器解析xml文件(spring.xml) Document document = reader.read(url); // 4、通过xpath语法,获取beans标签下的所有bean标签 XPath xPath = document.createXPath("beans/bean"); // 通过指定语法解析文档对象,返回汇合 List<Element> list = xPath.selectNodes(document); // 判断汇合是否为空,遍历汇合 if (list != null && list.size() > 0) { myBeans = new ArrayList<>(); for(Element el : list) { // 获取标签元素中的属性 String id = el.attributeValue("id"); // id 属性值 String clazz = el.attributeValue("class"); // class 属性值 System.out.println(el.attributeValue("id")); System.out.println(el.attributeValue("class")); // 失去Bean对象 MyBean bean = new MyBean(id, clazz); // 将Bean对象设置到汇合中 myBeans.add(bean); } } } catch (DocumentException e) { e.printStackTrace(); } } /** * 通过反射实例化失去对象 * Class.forName(类的全门路).newInstance(); * 通过Map<id,Class>存储 */ private void instanceBean() { // 判断bean汇合是否为空,不为空遍历失去对应Bean对象 if (myBeans != null && myBeans.size() > 0) { for (MyBean bean : myBeans){ try { // 通过类的全门路实例化对象 Object object = Class.forName(bean.getClazz()).newInstance(); // 将id与实例化对象设置到map对象中 beans.put(bean.getId(), object); } catch (Exception e) { e.printStackTrace(); } } } } /** * 通过key获取map中的指定value * @param id * @return */ @Override public Object getBean(String id) { Object object = beans.get(id); return object; }}
测试自定义 IOC 容器
创立与配置文件中对应的Bean对象
UserService.java
package com.xxxx.service; public class UserService { public void test(){ System.out.println("UserService Test..."); }}
AccountService.java
package com.xxxx.service;public class AccountService { public void test(){ System.out.println("AccountService Test..."); }}
测试是否能够获取实例化的Bean对象
package com.xxxx;import com.xxxx.spring.MyFactory;import com.xxxx.spring.MyClassPathXmlApplicationContext;import com.xxxx.service.AccountService;import com.xxxx.service.UserService;public class App { public static void main(String[] args) { MyFactory factory = new MyClassPathXmlApplicationContext("spring.xml"); // 失去实例化对象 UserService userService = (UserService) factory.getBean("userService"); userService.test(); UserService userService2 = (UserService) factory.getBean("userService"); System.out.println(userService+"=====" + userService2); AccountService accountService = (AccountService)factory.getBean("accountService"); accountService.test(); }}
Spring 容器在启动的时候 读取xml配置信息,并对配置的 bean 进行实例化(这里模仿的比较简单,仅用于帮忙大家了解),同时通过上下文对象提供的 getBean() 办法拿到咱们配置的 bean 对象,从而实现内部容器自动化保护并创立 bean 的成果。
Spring IOC 配置文件加载
Spring 配置文件加载
spring.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userService" class="com.xxxx.service.UserService"></bean></beans>
依据相对路径加载资源
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
依据绝对路径加载资源(理解)
ApplicationContext ac = new FileSystemXmlApplicationContext("C:/IdeaWorkspace/spring01/src/main/resources/spring.xml");
Spring 多配置文件加载
Spring 框架启动时能够加载多个配置文件到环境中。对于比较复杂的我的项目,可能对应的配置文件有多个,我的项目在启动部署时会将多个配置文件同时加载进来。
service.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userService" class="com.xxxx.service.UserService"></bean></beans>
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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userDao" class="com.xxxx.dao.UserDao"></bean></beans>
可变参数,传入多个文件名
// 同时加载多个资源文件ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml","dao.xml");
通过总的配置文件import其余配置文件
spring.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--导入须要蕴含的资源文件--> <import resource="service.xml"/> <import resource="dao.xml"/></beans>
加载时只需加载总的配置文件即可
// 加载总的资源文件ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
Spring IOC 容器 Bean 对象实例化
结构器实例化
注:通过默认结构器创立 空构造方法必须存在 否则创立失败
设置配置文件 spring.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userService" class="com.xxxx.service.UserService"></bean></beans>
获取实例化对象
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");UserService userService = (UserService) ac.getBean("userService"); userService.test();
动态工厂实例化(理解)
注:
- 要有该工厂类及工厂办法
- 工厂办法为动态的
定义动态工厂类
package com.xxxx.factory;import com.xxxx.service.UserService;/** * 定义动态工厂类 */public class StaticFactory { /** * 定义对应的静态方法,返回实例化对象 * @return */ public static UserService createUserService() { return new UserService(); }}
设置配置文件 spring.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--动态工厂--> <bean id="userService" class="com.xxxx.factory.StaticFactory" factory-method="createUserService"></bean></beans>
获取实例化对象
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");UserService userService = (UserService) ac.getBean("userService"); userService.test();
当咱们指定Spring应用动态工厂办法来创立Bean实例时,Spring将先解析配置文件,并依据配置文件指定的信息,通过反射调用动态工厂类的动态工厂办法,并将该动态工厂办法的返回值作为Bean实例,在这个过程中,Spring不再负责创立Bean实例,Bean实例是由用户提供的动态工厂办法提供的。
实例化工厂实例化(理解)
注:
- 工厂办法为非静态方法
- 须要配置工厂bean,并在业务bean中配置factory-bean,factory-method属性
定义工厂类
package com.xxxx.factory;import com.xxxx.service.UserService;/** * 定义工厂类 */public class InstanceFactory { /** * 定义方法,返回实例化对象 * @return */ public UserService createUserService() { return new UserService(); }}
设置配置文件 spring.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 实例化工厂 1.定义实例化工厂bean 2.援用工厂bean 指定工厂创立办法(办法为非动态) --> <bean id="instanceFactory" class="com.xxxx.factory.InstanceFactory"></bean> <bean id="userService" factory-bean="instanceFactory" factory-method="createUserService"></bean></beans>
获取实例化对象
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");UserService userService = (UserService) ac.getBean("userService"); userService.test();
Spring三种实例化Bean的形式比拟
- 形式一:通过bean的缺省构造函数创立,当各个bean的业务逻辑互相比拟独立的时候或者和外界关联较少的时候能够应用。
- 形式二:利用动态factory办法创立,能够对立治理各个bean的创立,如各个bean在创立之前须要雷同的初始化解决,则可用这个factory办法险进行对立的解决等等。
- 形式三:利用实例化factory办法创立,行将factory办法也作为了业务bean来管制,1可用于集成其余框架的bean创立治理办法,2可能使bean和factory的角色调换。
开发中我的项目个别应用一种形式实例化bean,我的项目开发根本采纳第一种形式,交给Spring托管,应用时间接拿来应用即可。另外两种理解
Spring IOC 注入
手动实例化与内部引入
图一:
图二:
比照发现:图二中对于 UserDao 对象的创立并没有像图一那样被动的去实例化,而是通过带参办法模式将UserDao 传入过去,从而实现 UserService 对UserDao类 的依赖。
而理论创建对象的幕后对象即是交给了内部来创立。
Spring IOC 手动拆卸(注入)
Spring 反对的注入形式共有四种:set 注入、结构器注入、动态工厂注入、实例化工厂注入。
set办法注入
注:
- 属性字段须要提供set办法
- 四种形式,举荐应用set办法注入
业务对象 JavaBean
属性字段提供set办法
public class UserService { // 业务对象UserDao set注入(提供set办法) private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; }}
配置文件的bean标签设置property标签
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- IOC通过property标签手动拆卸(注入): Set办法注入 name:bean对象中属性字段的名称 ref:指定bean标签的id属性值 --> <bean id="userDao" class="com.xxxx.dao.UserDao"></bean> <bean id="userService" class="com.xxxx.service.UserService"> <!--业务对象 注入--> <property name="userDao" ref="userDao"/> </bean></beans>
罕用对象和根本类型
属性字段提供set办法
public class UserService { // 罕用对象String set注入(提供set办法) private String host; public void setHost(String host) { this.host = host; } // 根本类型Integer set注入(提供set办法) private Integer port; public void setPort(Integer port) { this.port = port; }}
配置文件的bean标签设置property标签
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- IOC通过property标签手动拆卸(注入): Set办法注入 name:bean对象中属性字段的名称 value:具体的值(根本类型 罕用对象|日期 汇合) --> <bean id="userService" class="com.xxxx.service.UserService"> <!--罕用对象String 注入--> <property name="host" value="127.0.0.1"/> <!--根本类型注入--> <property name="port" value="8080"/> </bean></beans>
汇合类型和属性对象
属性字段提供set办法
public class UserService { // List汇合 set注入(提供set办法) public List<String> list; public void setList(List<String> list) { this.list = list; } // Set汇合 set注入(提供set办法) private Set<String> set; public void setSet(Set<String> set) { this.set = set; } // Map set注入(提供set办法) private Map<String,Object> map; public void setMap(Map<String, Object> map) { this.map = map; } // Properties set注入(提供set办法) private Properties properties; public void setProperties(Properties properties) { this.properties = properties; } }
配置文件的bean标签设置property标签
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- IOC通过property标签手动拆卸(注入): Set办法注入 name:bean对象中属性字段的名称 value:具体的值(根本类型 罕用对象|日期 汇合) --> <!--List汇合 注入--> <property name="list"> <list> <value>上海</value> <value>北京</value> <value>杭州</value> </list> </property> <!--Set汇合注入--> <property name="set"> <set> <value>上海SH</value> <value>北京BJ</value> <value>杭州HZ</value> </set> </property> <!--Map注入--> <property name="map"> <map> <entry> <key><value>周杰伦</value></key> <value>我是如此置信</value> </entry> <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="上海">东方明珠</prop> <prop key="北京">天安门</prop> <prop key="杭州">西湖</prop> </props> </property></beans>
测试代码
UserService.java
public class UserService { // 业务对象UserDao set注入(提供set办法) private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } // 罕用对象String set注入(提供set办法) private String host; public void setHost(String host) { this.host = host; } // 根本类型Integer set注入(提供set办法) private Integer port; public void setPort(Integer port) { this.port = port; } // List汇合 set注入(提供set办法) public List<String> list; public void setList(List<String> list) { this.list = list; } // List汇合输入 public void printList() { list.forEach(s -> System.out.println(s)); } // Set汇合 set注入(提供set办法) private Set<String> set; public void setSet(Set<String> set) { this.set = set; } // Set汇合输入 public void printSet() { set.forEach(s -> System.out.println(s)); } // Map set注入(提供set办法) private Map<String,Object> map; public void setMap(Map<String, Object> map) { this.map = map; } // Map输入 public void printMap() { map.forEach((k,v) -> System.out.println(k + "," + v)); } // Properties set注入(提供set办法) private Properties properties; public void setProperties(Properties properties) { this.properties = properties; } // Properties输入 public void printProperties(){ properties.forEach((k,v) -> System.out.println(k + ","+ v )); } public void test(){ System.out.println("UserService Test..."); userDao.test(); studentDao.test(); System.out.println("Host:" + host + ",port:" + port); // List汇合 printList(); // Set汇合 printSet(); // Map printMap(); // Properties printProperties(); }}
spring.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- IOC通过property标签手动拆卸(注入): Set办法注入 name:bean对象中属性字段的名称 ref:指定bean标签的id属性值 value:具体的值(根本类型 罕用对象|日期 汇合) --> <bean id="userDao" class="com.xxxx.dao.UserDao"></bean> <bean id="userService" class="com.xxxx.service.UserService"> <!--业务对象 注入--> <property name="userDao" ref="userDao"/> <property name="studentDao" ref="studentDao"/> <!--罕用对象String 注入--> <property name="host" value="192.168.1.109"/> <!--根本类型注入--> <property name="port" value="8080"/> <!--List汇合 注入--> <property name="list"> <list> <value>上海</value> <value>北京</value> <value>杭州</value> </list> </property> <!--Set汇合注入--> <property name="set"> <set> <value>上海SH</value> <value>北京BJ</value> <value>杭州HZ</value> </set> </property> <!--Map注入--> <property name="map"> <map> <entry> <key><value>周杰伦</value></key> <value>我是如此置信</value> </entry> <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="上海">东方明珠</prop> <prop key="北京">天安门</prop> <prop key="杭州">西湖</prop> </props> </property> </bean> </beans>
结构器注入
注:
- 提供带参结构器
单个Bean对象作为参数
Java 代码
public class UserService { private UserDao userDao; // JavaBean 对象 public UserService(UserDao userDao) { this.userDao = userDao; } public void test(){ System.out.println("UserService Test..."); userDao.test(); }}
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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- IOC通过结构器注入: 通过constructor-arg标签进行注入 name:属性名称 ref:指定bean标签的id属性值 --> <bean id="userDao" class="com.xxxx.dao.UserDao" ></bean> <bean id="userService" class="com.xxxx.service.UserService"> <constructor-arg name="userDao" ref="userDao"></constructor-arg> </bean></beans>
多个Bean对象作为参数
Java 代码
public class UserService { private UserDao userDao; // JavaBean 对象 private AccountDao accountDao // JavaBean 对象 public UserService(UserDao userDao, AccountDao accountDao) { this.userDao = userDao; this.accountDao = accountDao; } public void test(){ System.out.println("UserService Test..."); userDao.test(); accountDao.test(); }}
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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- IOC通过结构器注入: 通过constructor-arg标签进行注入 name:属性名称 ref:指定bean标签的id属性值 --> <bean id="userDao" class="com.xxxx.dao.UserDao" ></bean> <bean id="accountDao" class="com.xxxx.dao.AccountDao" ></bean> <bean id="userService" class="com.xxxx.service.UserService"> <constructor-arg name="userDao" ref="userDao"></constructor-arg> <constructor-arg name="accountDao" ref="accountDao"></constructor-arg> </bean></beans>
Bean对象和罕用对象作为参数
Java 代码
public class UserService { private UserDao userDao; // JavaBean 对象 private AccountDao accountDao; // JavaBean 对象 private String uname; // 字符串类型 public UserService(UserDao userDao, AccountDao accountDao, String uname) { this.userDao = userDao; this.accountDao = accountDao; this.uname = uname; } public void test(){ System.out.println("UserService Test..."); userDao.test(); accountDao.test(); System.out.println("uname:" + uname); }}
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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- IOC通过结构器注入: 通过constructor-arg标签进行注入 name:属性名称 ref:指定bean标签的id属性值 value:根本类型 罕用对象的值 index:结构器中参数的下标,从0开始 --> <bean id="userDao" class="com.xxxx.dao.UserDao" ></bean> <bean id="accountDao" class="com.xxxx.dao.AccountDao" ></bean> <bean id="userService" class="com.xxxx.service.UserService"> <constructor-arg name="userDao" ref="userDao"></constructor-arg> <constructor-arg name="accountDao" ref="accountDao"></constructor-arg> <constructor-arg name="uname" value="admin"></constructor-arg> </bean></beans>
循环依赖问题
循环问题产生的起因:
Bean通过结构器注入,之间彼此相互依赖对方导致bean无奈实例化。
问题展现:
Java 代码
public class AccountService { private RoleService roleService; public AccountService(RoleService roleService) { this.roleService = roleService; } public void test() { System.out.println("AccountService Test..."); }}public class RoleService { private AccountService accountService; public RoleService(AccountService accountService) { this.accountService = accountService; } public void test() { System.out.println("RoleService Test..."); }}
XML配置
<!-- 如果多个bean对象中相互注入,则会呈现循环依赖的问题 能够通过set办法注入解决--><bean id="accountService" class="com.xxxx.service.AccountService"> <constructor-arg name="roleService" ref="roleService"/></bean><bean id="roleService" class="com.xxxx.service.RoleService"> <constructor-arg name="accountService" ref="accountService"/></bean>
如何解决:将结构器注入改为set办法注入
Java代码
public class AccountService { private RoleService roleService; /* public AccountService(RoleService roleService) { this.roleService = roleService; }*/ public void setRoleService(RoleService roleService) { this.roleService = roleService; } public void test() { System.out.println("AccountService Test..."); }}public class RoleService { private AccountService accountService; /* public RoleService(AccountService accountService) { this.accountService = accountService; }*/ public void setAccountService(AccountService accountService) { this.accountService = accountService; } public void test() { System.out.println("RoleService Test..."); }}
XML配置
<!-- <bean id="accountService" class="com.xxxx.service.AccountService"> <constructor-arg name="roleService" ref="roleService"/> </bean> <bean id="roleService" class="com.xxxx.service.RoleService"> <constructor-arg name="accountService" ref="accountService"/> </bean>--><!--批改为set办法注入--><bean id="accountService" class="com.xxxx.service.AccountService"> <property name="roleService" ref="roleService"/></bean><bean id="roleService" class="com.xxxx.service.RoleService"> <property name="accountService" ref="accountService"/></bean>
动态工厂注入
定义动态工厂类
public class StaticFactory { // 定义静态方法 public static TypeDao createTypeDao() { return new TypeDao(); }}
Java代码
public class TypeService { private TypeDao typeDao; public void setTypeDao(TypeDao typeDao) { this.typeDao = typeDao; } public void test() { System.out.println("TypeService Test..."); }}
XML配置
在配置文件中设置bean标签,指定工厂对象并设置对应的办法
<bean id="typeService" class="com.xxxx.service.TypeService"> <property name="typeDao" ref="typeDao"/></bean><!-- 动态工厂注入: 动态工厂注入也是借助set办法注入,只是被注入的bean对象的实例化是通过动态工厂实例化的--><bean id="typeDao" class="com.xxxx.factory.StaticFactory" factory-method="createTypeDao"></bean>
实例化工厂注入
定义工厂类
public class InstanceFactory { public TypeDao createTypeDao() { return new TypeDao(); }}
Java代码
public class TypeService { private TypeDao typeDao; public void setTypeDao(TypeDao typeDao) { this.typeDao = typeDao; } public void test() { System.out.println("TypeService Test..."); }}
XML配置
申明工厂bean标签,申明bean对象,指明工厂对象和工厂办法
<bean id="typeService" class="com.xxxx.service.TypeService"> <property name="typeDao" ref="typeDao"/></bean><!-- 实例化工厂注入: 实例化工厂注入也是借助set办法注入,只是被注入的bean对象的实例化是通过实例化工厂实例化的--><bean id="instanceFactory" class="com.xxxx.factory.InstanceFactory"></bean><bean id="typeDao" factory-bean="instanceFactory" factory-method="createTypeDao"></bean>
重点把握set注入和结构器注入,工厂形式理解即可。理论开发中根本应用set形式注入bean。
注入形式的抉择
开发我的项目中set形式注入首选
应用结构注入能够在构建对象的同时一并实现依赖关系的建设,对象一建设则所有的所有也就筹备好了,但如果要建设的对象关系很多,应用结构器注入会在构建函数上留下一长串的参数,且不易记忆,这时应用Set注入会是个不错的抉择。
应用Set注入能够有明确的名称,能够理解注入的对象会是什么,像setXXX()这样的名称会比记忆Constructor上某个参数的地位代表某个对象更好。
p名称空间的应用
spring2.5当前,为了简化setter办法属性注入,援用p名称空间的概念,能够将 子元素,简化为元素属性配置。
属性字段提供 set 办法
public class UserService { // 业务对象UserDao set注入(提供set办法) private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } // 罕用对象String set注入(提供set办法) private String host; public void setHost(String host) { this.host = host; }}
在配置文件 spring.xml 引入 p 名称空间
xmlns:p="http://www.springframework.org/schema/p"
<?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/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userDao" class="com.xxxx.dao.UserDao"></bean> <!-- p:属性名:="xxx" 引入常量值 p:属性名-ref:="xxx" 引入其余Bean对象的id属性值 --> <bean id="userService" class="com.xxxx.service.UserService" p:userDao-ref="userDao" p:host="127.0.0.1" /></beans>
Spring IOC 主动拆卸(注入)
注解形式注入 Bean
对于 bean 的注入,除了应用 xml 配置以外,能够应用注解配置。注解的配置,能够简化配置文件,进步开发的速度,使程序看上去更简洁。对于注解的解释,Spring对于注解有专门的解释器,对定义的注解进行解析,实现对应bean对象的注入。通过反射技术实现。
筹备环境
批改配置文件
<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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
开启自动化注入
<!--开启自动化拆卸(注入)--><context:annotation-config/><bean id="userDao" class="com.xxxx.dao.UserDao"></bean><bean id="userService" class="com.xxxx.service.UserService"></bean>
- 给注入的bean对象增加注解
@Resource注解
@Resource注解实现主动注入(反射)
- 默认依据属性字段名称查找对应的bean对象 (属性字段的名称与bean标签的id属性值相等)
- 如果属性字段名称未找到,则会通过类型(Class类型)查找
- 属性能够提供set办法,也能够不提供set办法
- 注解能够申明在属性级别 或 set办法级别
- 能够设置name属性,name属性值必须与bean标签的id属性值统一;如果设置了name属性值,就只会依照name属性值查找bean对象
- 当注入接口时,如果接口只有一个实现则失常实例化;如果接口存在多个实现,则须要应用name属性指定须要被实例化的bean对象
代码示例
默认依据属性字段名称查找对应的bean对象 (属性字段的名称与bean标签的id属性值相等)
/** * @Resource注解实现主动注入(反射) * 默认依据属性字段名称查找对应的bean对象 (属性字段的名称与bean标签的id属性值相等) */public class UserService { @Resource private UserDao userDao; // 属性字段的名称与bean标签的id属性值相等 public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void test() { // 调用UserDao的办法 userDao.test(); }}
如果属性字段名称未找到,则会通过类型(Class类型)查找
/** * @Resource注解实现主动注入(反射) * 如果属性字段名称未找到,则会通过类型(Class类型)查找 */public class UserService { @Resource private UserDao ud; // 当在配置文件中属性字段名(ud)未找到,则会查找对应的class(UserDao类型) public void setUd(UserDao ud) { this.ud = ud; } public void test() { // 调用UserDao的办法 ud.test(); }}
属性能够提供set办法,也能够不提供set办法
/** * @Resource注解实现主动注入(反射) * 属性能够提供set办法,也能够不提供set办法 */public class UserService { @Resource private UserDao userDao; // 不提供set办法 public void test() { // 调用UserDao的办法 userDao.test(); }}
注解能够申明在属性级别 或 set办法级别
/** * @Resource注解实现主动注入(反射) * 注解能够申明在属性级别 或 set办法级别 */public class UserService { private UserDao userDao; @Resource // 注解也可设置在set办法上 public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void test() { // 调用UserDao的办法 userDao.test(); }}
能够设置name属性,name属性值必须与bean标签的id属性值统一;如果设置了name属性值,就只会依照name属性值查找bean对象
/** * @Resource注解实现主动注入(反射) * 能够设置name属性,name属性值必须与bean的id属性值统一; * 如果设置了name属性值,就只会依照name属性值查找bean对象 */public class UserService { @Resource(name = "userDao") // name属性值与配置文件中bean标签的id属性值统一 private UserDao ud; public void test() { // 调用UserDao的办法 ud.test(); }}
当注入接口时,如果接口只有一个实现则失常实例化;如果接口存在多个实现,则须要应用name属性指定须要被实例化的bean对象
定义接口类 IUserDao.java
package com.xxxx.dao;/** * 定义接口类 */public interface IUserDao { public void test();}
定义接口实现类 UserDao01.java
package com.xxxx.dao;/** * 接口实现类 */public class UserDao01 implements IUserDao { @Override public void test(){ System.out.println("UserDao01..."); }}
定义接口实现类 UserDao02.java
package com.xxxx.dao;/** * 接口实现类 */public class UserDao02 implements IUserDao { @Override public void test(){ System.out.println("UserDao02..."); }}
XML配置文件
<!--开启自动化拆卸(注入)--><context:annotation-config/><bean id="userService" class="com.xxxx.service.UserService"></bean><bean id="userDao01" class="com.xxxx.dao.UserDao01"></bean><bean id="userDao02" class="com.xxxx.dao.UserDao01"></bean>
应用注解 UserService.java
/** * @Resource注解实现主动注入(反射) * 当注入接口时,如果接口只有一个实现则失常实例化;如果接口存在多个实现,则须要应用name属性指定须要被实例化的bean对象 */public class UserService { @Resource(name = "userDao01") // name属性值与其中一个实现类的bean标签的id属性值统一 private IUserDao iUserDao; // 注入接口(接口存在多个实现) public void test() { iUserDao.test(); }}
@Autowired注解
@Autowired注解实现自动化注入:
- 默认通过类型(Class类型)查找bean对象 与属性字段的名称无关
- 属性能够提供set办法,也能够不提供set办法
- 注解能够申明在属性级别 或 set办法级别
- 能够增加@Qualifier联合应用,通过value属性值查找bean对象(value属性值必须要设置,且值要与bean标签的id属性值对应)
默认通过类型(Class类型)查找bean对象 与属性字段的名称无关
/** * @Autowired注解实现自动化注入 * 默认通过类型(Class类型)查找bean对象 与属性字段的名称无关 */public class UserService { @Autowired private UserDao userDao; // 默认通过类型(Class类型)查找bean对象 与属性字段的名称无关 public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void test() { // 调用UserDao的办法 userDao.test(); }}
属性能够提供set办法,也能够不提供set办法
/** * @Autowired注解实现自动化注入 * 属性能够提供set办法,也能够不提供set办法 */public class UserService { @Autowired private UserDao userDao; // 不提供set办法 public void test() { // 调用UserDao的办法 userDao.test(); }}
注解能够申明在属性级别 或 set办法级别
/** * @Autowired注解实现自动化注入 * 注解能够申明在属性级别 或 set办法级别 */public class UserService { private UserDao userDao; @Autowired// 注解能够申明在set办法级别 public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void test() { // 调用UserDao的办法 userDao.test(); }}
能够增加@Qualifier联合应用,通过value属性值查找bean对象(value属性值必须要设置,且值要与bean标签的id属性值对应)
/** * @Autowired注解实现自动化注入 * 能够增加@Qualifier联合应用,通过value属性值查找bean对象 value属性值必须要设置,且值要与bean标签的id属性值对应 */public class UserService { @Autowired @Qualifier(value="userDao") // value属性值必须要设置,且值要与bean标签的id属性值对应 private UserDao userDao; public void test() { userDao.test(); }}
举荐应用@Resource 注解是属于J2EE的,缩小了与Spring的耦合。
Spring IOC 扫描器
理论的开发中,bean的数量十分多,采纳手动配置bean的形式已无奈满足生产须要,Spring这时候同样提供了扫描的形式,对扫描到的bean对象对立进行治理,简化开发配置,进步开发效率。
Spring IOC 扫描器的配置
Spring IOC 扫描器 作用:bean对象对立进行治理,简化开发配置,进步开发效率 1、设置自动化扫描的范畴 如果bean对象未在指定包范畴,即便申明了注解,也无奈实例化 2、应用指定的注解(申明在类级别) bean对象的id属性默认是 类的首字母小写 Dao层: @Repository Service层: @Service Controller层: @Controller 任意类: @Component 注:开发过程中倡议依照指定规定申明注解
设置自动化扫描范畴
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 设置自动化扫描的范畴 --> <context:component-scan base-package="com.xxxx"/></beans>
应用特定的注解
@Repository (Dao层)
@Repositorypublic class ResourceDao { public void test() { System.out.println("ResourceDao..."); }}
@Service(Service层 )
@Servicepublic class ResourceService { @Resource private ResourceDao resourceDao; // service层注入dao层的bean对象 public void test() { System.out.println("ResourceService..."); resourceDao.test(); }}
@Controller (Controller 层 )
@Controllerpublic class ResourceController { @Autowired private ResourceService resourceService; // Controller层注入service层的bean对象 public void test() { System.out.println("ResourceController..."); resourceService.test(); }}
@Component (任意层)
@Componentpublic class PropertyUtils { public void test(){ System.out.println("PropertyUtils..."); }}
Spring 模仿用户登录流程
Dao层 (查问用户记录)
定义JavaBean User.java
package com.xxxx.po;/** * User 用户实体类 */public class User { private String userName; // 用户名称 private String userPwd; // 用户明码 public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPwd() { return userPwd; } public void setUserPwd(String userPwd) { this.userPwd = userPwd; }}
编写Dao层 UserDao.java
package com.xxxx.dao;import com.xxxx.po.User;import org.springframework.stereotype.Repository;@Repositorypublic class UserDao { private final String USERNAME = "admin"; private final String USERPWD = "admin"; /** * 通过用户名称查问用户对象 * @param userName * @return */ public User queryUserByUserName(String userName){ User user = null; // 判断用户名称是否正确 if(!USERNAME.equals(userName)){ // 如果不正确,返回null return null; } // 如果正确,将用户名称和明码设置到user对象中 user = new User(); user.setUserName(USERNAME); user.setUserPwd(USERPWD); return user; }}
Service层 (业务逻辑解决)
定义业务解决返回音讯模型 MessageModel.java
package com.xxxx.po.vo;/** * 定义业务解决返回音讯模型 * 封装返回后果 */public class MessageModel { private Integer resultCode = 1; // 后果状态码 1=胜利,0=失败 private String resultMsg = "操作胜利!"; // 后果提示信息 public Integer getResultCode() { return resultCode; } public void setResultCode(Integer resultCode) { this.resultCode = resultCode; } public String getResultMsg() { return resultMsg; } public void setResultMsg(String resultMsg) { this.resultMsg = resultMsg; }}
编写Service层 UserService.java
package com.xxxx.service;import com.xxxx.dao.UserDao1;import com.xxxx.po.User;import com.xxxx.po.vo.MessageModel;import org.springframework.stereotype.Service;import javax.annotation.Resource;@Servicepublic class UserService { @Resource private UserDao userDao; /** * 验证用户登录 * @param userName * @param userPwd * @return */ public MessageModel userLoginCheck(String userName, String userPwd){ // 定义业务解决返回音讯模型 MessageModel messageModel = new MessageModel(); // 判断用户名称是否非空 if(null == userName || "".equals(userName.trim())){ messageModel.setResultCode(0); messageModel.setResultMsg("用户名不能为空!"); return messageModel; } // 判断用户明码是否为空 if(null == userPwd || "".equals(userPwd.trim())){ messageModel.setResultCode(0); messageModel.setResultMsg("明码不能为空!"); return messageModel; } // 通过用户名称查问用户对象 User user = userDao.queryUserByUserName(userName); // 判断用户对象是否为空 if(null == user){ messageModel.setResultCode(0); messageModel.setResultMsg("该用户不存在!"); return messageModel; } // 如果用户对象不为空,判断明码是否正确 if(!user.getUserPwd().equals(userPwd)){ messageModel.setResultCode(0); messageModel.setResultMsg("用户明码不正确!"); return messageModel; } // 登录胜利 messageModel.setResultMsg("登录胜利!"); return messageModel; }}
Controller层 (接管申请)
编写Controller层 UserController.java
package com.xxxx.controller;import com.xxxx.po.vo.MessageModel;import com.xxxx.service.UserService1;import org.springframework.stereotype.Controller;import javax.annotation.Resource;@Controllerpublic class UserController { @Resource private UserService userService; /** * 用户登录 * @param userName * @param userPwd * @return */ public MessageModel login(String userName, String userPwd){ // 调用Dao层判断用户登录操作,返回后果 MessageModel messageModel = userService.userLoginCheck(userName, userPwd); return messageModel; }}
通过 JUnit 进行测试
package com.xxxx;import com.xxxx.controller.UserController;import com.xxxx.po.vo.MessageModel;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestLogin { @Test public void test() { // 失去Spring容器上下文环境 ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); // 失去UserController实例化对象 UserController userController = (UserController) ac.getBean("userController"); // 传入参数调用UserController的办法,返回封装类 MessageModel messageModel= userController.login("admin", "admin"); System.out.println("状态码:" + messageModel.getResultCode() + ",提示信息:" + messageModel.getResultMsg()); }}
Bean的作用域与生命周期
Bean的作用域
默认状况下,咱们从Spring容器中拿到的对象均是单例的,对于bean的作用域类型如下:
singleton 作用域
留神: lazy-init是懒加载, 如果等于true时作用是指Spring容器启动的时候不会去实例化这个bean, 而是在程序调用时才去实例化. 默认是false即Spring容器启动时实例化.
默认状况下,被治理的bean只会IOC容器中存在一个实例,对于所有获取该Bean的操作Spring容器将只返回同一个Bean。
容器在启动的状况下就实例化所有singleton 的 bean对象,并缓存与容器中
lazy-init属性(懒加载)
如果为false,则在IOC容器启动时会实例化bean对象,默认false
如果为true,则IOC容器启动时不会实例化Bean对象,在应用bean对象时才会实例化
lazy-init设置为false有什么益处?
1)能够提前发现潜在的配置问题
2)Bean 对象存在于缓存中,应用时不必再去实例化bean,放慢程序运行效率
什么对象适宜作为单例对象?
一般来说对于无状态或状态不可扭转的对象适宜应用单例模式。(不存在会扭转对象状态的成员变量)
比方:controller层、service层、dao层
什么是无状态或状态不可扭转的对象?
实际上对象状态的变动往往均是因为属性值得变动而引起的,比方user类 姓名属性会有变动,属性姓名的变动个别会引起user对象状态的变动。对于咱们的程序来说,无状态对象没有实例变量的存在,保障了线程的安全性,service 层业务对象即是无状态对象。线程平安的。
prototype 作用域
通过scope=“prototype” 设置bean的类型 ,每次向Spring容器申请获取Bean都返回一个全新的Bean,绝对于"singleton"来说就是不缓存Bean,每次都是一个依据Bean定义创立的全新Bean。
Web利用中的作用域
- request作用域
示意每个申请须要容器创立一个全新Bean。比方提交表单的数据必须是对每次申请新建一个Bean来放弃这些表单数据,申请完结开释这些数据。
- session作用域
示意每个会话须要容器创立一个全新Bean。比方对于每个用户个别会有一个会话,该用户的用户信息须要存储到会话中,此时能够将该Bean作用域配置为session级别。
- globalSession作用域
相似于session作用域,其用于portlet(Portlet是基于Java的Web组件,由Portlet容器治理,并由容器解决申请,生产动静内容)环境的web利用。如果在非portlet环境将视为session作用域。
配置形式和根本的作用域雷同,只是必须要有web环境反对,并配置相应的容器监听器或拦截器从而能利用这些作用域,目前先相熟概念,后续集成web时解说具体应用,大家只须要晓得有这些作用域就能够了。
Bean的生命周期
比照曾经学过的servlet 生命周期(容器启动装载并实例化servlet类,初始化servlet,调用service办法,销毁servlet)。
同样对于Spring容器治理的bean也存在生命周期的概念
在Spring中,Bean的生命周期包含Bean的定义、初始化、应用和销毁4个阶段
Bean的定义
在Spring中,通常是通过配置文档的形式来定义Bean的。
在一个配置文档中,能够定义多个Bean。
Bean 的初始化
默认在IOC容器加载时,实例化对象。
Spring bean 初始化有两种形式:
形式一:在配置文档中通过指定 init-method 属性来实现。
public class RoleService { // 定义初始化时须要被调用的办法 public void init() { System.out.println("RoleService init..."); }}
<!-- 通过init-method属性指定办法 --><bean id="roleService" class="com.xxxx.service.RoleService" init-method="init"></bean>
形式二: 实现 org.springframework.beans.factory.InitializingBean 接口。
public class RoleService implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { System.out.println("RoleService init..."); }}
<bean id="roleService" class="com.xxxx.service.RoleService" ></bean>
Bean对象实例化过程是在Spring容器初始化时被实例化的,但也不是不可扭转的,能够通过 lazy-init=“true” 属性提早bean对象的初始化操作,此时再调用getBean 办法时才会进行bean的初始化操作
Bean 的应用
形式一:应用 BeanFactory
// 失去Spring的上下文环境BeanFactory factory = new ClassPathXmlApplicationContext("spring.xml");RoleService roleService = (RoleService) factory.getBean("roleService");
形式二:应用 ApplicationContext
// 失去Spring的上下文环境ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");RoleService roleService = (RoleService) ac.getBean("roleService");
Bean的销毁
实现销毁形式(Spring容器会保护bean对象的治理,能够指定bean对象的销毁所要执行的办法)。
步骤一:实现销毁形式(Spring容器会保护bean对象的治理,能够指定bean对象的销毁所要执行的办法)
<bean id="roleService" class="com.xxxx.service.RoleService" destroy-method="destroy"></bean>
**步骤二:**通过 AbstractApplicationContext 对象,调用其close办法实现bean的销毁过程
AbstractApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");ctx.close();
IOC/DI-管制反转和依赖注入 将对象实例化的创立过程转交给内部容器(IOC容器 充当工厂角色)去负