SpringIOC
文章目录
一、Spring概念
Spring是众多开源 java 项目中的一员,基于分层的javaEE应用一站式轻量级开源框架,主要核心是Ioc(控制反转/依赖注入) 与 Aop(面向切面)两大技术,实现项目在开发过程中的轻松解耦,提高项目的开发效率。下面着重介绍SpringIOC的相关知识,本文仅供参考,详情了解请参考官方文档说明。
官方文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html
二、 Spring核心源码架构
1、核心容器:
Spring-beans和Spring-core模块是Spring框架的核心模块,包括控制反转和依赖注入,核心容器提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,工厂模式的实现。BeanFactory 使用控制反转(IOC)思想将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring上下文Spring Context:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring-Expression 模块是统一表达式语言(unified EL)的扩展模块,可 以查询、管理运行中的对象,同时也方便的可以调用对象方法、操作数组、 集合等。
2、Spring-AOP(面向切面编程):
Spring-aop 是 Spring 的另一个核心模块, 在 Spring 中,他 是以 JVM 的动态代理技术为基础,然后设计出了一系列的 Aop 横切实现,比如前置通知、返回通知、异常通知等。通过其配置管理特性,Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。
3、Spring Data Access(数据访问):
Spring-jdbc模块是Spring 提供的 JDBC 抽象框架的主要实现模块,用于简化 Spring JDBC。
Spring-tx模块是SpringJDBC 事务控制实现模块。使用 Spring 框架,它 对事务做了很好的封装,通过它的 Aop 配置,可以灵活的配置在任何一层。
4、Web模块
由 Spring-web、Spring-webmvc、Spring-websocket 和 Spring-webmvc-portlet 4 个模块组成,Web 上下文模块建立在应用 程序上下文模块之上,为基于 Web 的应用程序提供了上下文。Web 模块还 简化了处理多部分请求以及将请求参数绑定到域对象的工作。
5、单元测试
即 Spring-test 模块。Spring-test 模块主要为测试提供支持。
三、Spring框架环境搭建
1、环境要求:jdk 1.7 及以上、Spring 版本:4.3.2
2、基于 maven 创建普通 java 工程并调整整体工程环境(jre 编译器版本)
3、添加Spring核心坐标依赖
<!-- spring 核心jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
4、编写一个Bean(编写一个HelloService类,构造一个Hello方法,输出文字)
5、配置Bean到xml中,把对应bean纳入到Spring容器管理
<?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">
<!--
xmlns 即 xml namespace xml 使用的命名空间
xmlns:xsi 即 xml schema instance xml 遵守的具体规范
xsi:schemaLocation 本文档 xml 遵守的规范 官方指定
-->
<!--配置bean 其中id唯一标记这个bean,class属性代表是这个bean的类-->
<bean id="helloService" class="com.shsxt.service.HelloService"></bean>
</beans>
6、验证Spring框架环境是否搭建成功
通过 junit4 进行验证,添加坐标依赖:
<!-- junit 测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
再通过当前类路径的方式加载 xml 文件,启动 Spring 容器框架如5代码块
小结:Spring 容器在启动的时候 读取 xml 配置信息,并对配置的 bean 进行实例化,同时通过上下文对象提供的 getbean 方法 拿到我们配置的 bean 对象,从而实现外部容器自动化维护并创建 bean 的效果。
四、SpringIOC配置文件加载
Spring框架启动时可以加载多个配置文件到环境中。比如说对于比较复杂的项目,可能对应的配置文件有多个,项目在启动部署时会将多个配置文件同时加载进来。
1、编写三个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">
<bean id="userDao" class="com.shsxt.dao.UserDao"></bean>
</beans>
Service.xml
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
http://www.Springframework.org/schema/beans/Spring-beans.xsd">
<bean id="userService" class="com.shsxt.service.UserService"></bean>
</beans>
Controller.x
controller.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="userController"
class="com.shsxt.comtroller.UserController"></bean>
</beans>
测试类:
启动容器时将配置文件同时加载,并获取对应 bean 实例
@Test
public void test01() throws Exception{
ApplicationContext ac=new ClassPathXmlApplicationContext("dao.xml","service.xml","controller.xml");
// 获取 dao 层 bean
UserDao userDao=(UserDao) ac.getBean("userDao");
userDao.save();
//获取 service 层 bean
UserService userService= (UserService) ac.getBean("userService");
userService.hello();
// 获取 controller bean
UserController userController=(UserController)
ac.getBean("userController");
u
**结果:**先获取的bean先执行方法
---->使用 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"
xsi:schemaLocation="http://www.Springframework.org/schema/beans
http://www.Springframework.org/schema/beans/Spring-beans.xsd">
<import resource="dao.xml"/>
<import resource="service.xml"/>
<import resource="controller.xml"/>
</beans>
运行结果和分开配置一样。
五、SpringIOC Bean对象实例化
1、构造器的方式实例化bean对象
**注意:**通过默认构造器创建,空构造方法必须存在否则创建失败
<bean id="userServiceImpl"
class="com.shsxt.service.impl.UserServiceImpl"></bean>
2、静态工厂方法方式实例化bean
**要求:**①要有该工厂类及工厂方法
②工厂方法为静态的
package com.shsxt.factory;
import com.shsxt.service.UserService;
public class StaticFactory {
public static UserService createUserService(){
return new UserService();
}
}
Bean配置:
<bean id="userService" class="com.shsxt.factory.StaticFactory"
factory-method="createUserService"/>
**总结:**当我们指定 Spring 使用静态工厂方法来创建 Bean 实例时,Spring 将先解析配置 文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静 态工厂方法的返回值作为 Bean 实例,在这个过程中,Spring 不再负责创建 Bean 实例,Bean 实例是由用户提供的静态工厂方法提供的。
3、实例化工厂方式创建bean
要求:
①工厂方法为非静态方法
②配置工厂 bean,并在业务 bean 中配置factory-bean、factory-method 属性
实例化工厂定义:
package com.shsxt.factory;
import com.shsxt.service.UserService;
public class InstanceFactory {
public UserService createUserService(){
return new UserService();
}
}
Bean配置:
<!--
实例化工厂
1.定义实例化工厂 bean
2.引用工厂 bean 指定工厂创建方法(方法为非静态)
-->
<bean id="instanceFactory" class="com.shsxt.factory.InstanceFactory"></bean>
<bean id="userService" factory-bean="instanceFactory" factorymethod="createUserService"></bean>
4、Spring三种实例化bean的方式比较
- 通过 bean 的缺省构造函数创建,当各个 bean 的业务逻辑相互比较独立的时候 或者和外界关联较少的时候可以使用。
- 利用静态 factory 方法创建,可以统一管理各个 bean 的创建,如各个 bean 在 创建之前需要相同的初始化处理,则可用这个 factory 方法险进行统一的处理等等。
- 利用实例化 factory 方法创建,即将 factory 方法也作为了业务 bean 来控制,可用于集成其他框架的 bean 创建管理方法,还能够使 bean 和 factory 的角色互换。
小结:开发中项目一般使用一种方式实例化 bean,项目开发基本采用第一种方式,交给Spring 托管,使用时直接拿来使用即可。另外两种了解。
六、Spring IOC Bean对象依赖注入
比起传统对象创建实例化,Spring提供支持四种注入方式,交给外部来创建
1、Spring IOC对象注入四种方式:
①set 注入:
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="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.shsxt.dao.UserDao"></bean>
</beans>
java类:
package com.shsxt.service.impl;
import com.shsxt.dao.UserDao;
import com.shsxt.vo.User;
public class UserServiceImpl {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public UserDao getUserDao() {
return userDao;
}
public void saveUser(User user){
System.out.println("userName:"+userName+"price:"+price);
userDao.add(user);
}
}
基本数据类型set注入:
<bean id="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
<property name="userName" value="sxt">
</property>
<property name="price" value="123">
</property>
</bean>
<!--同时对应 Service 提供对应属性字段 以及 get 、set 方法即可-->
②构造器注入:
xml配置:
<bean id="userDao" class="com.shsxt.dao.UserDao"></bean>
<bean id="userServiceImpl2"
class="com.shsxt.service.impl.UserServiceImpl2">
<constructor-arg ref="userDao"></constructor-arg>
</bean>
Java类提供构造函数:
package com.shsxt.service.impl;
import com.shsxt.dao.UserDao;
import com.shsxt.vo.User;
public class UserServiceImpl2 {
private UserDao userDao;
public UserServiceImpl2(UserDao userDao) {
this.userDao = userDao;
}
public void saveUser(User user){
userDao.add(user);
}
}
构造器注入字符串值:
Index属性为参数顺序 如果只有一个参数index可以不设置
<bean id="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl">
<constructor-arg name="userName" index="0" value="123">
</constructor-arg>
<constructor-arg name="userPwd" index="1" value="321"></constructorarg>
</bean>
③静态工厂注入:
<bean id="userDao" class="com.shsxt.factory.StaticFactory" factory-method="createUserDao"></bean>
<bean id="userService" class="com.shsxt.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
静态工厂类:
package com.shsxt.factory;
import com.shsxt.dao.UserDao;
public class StaticFactory {
public static UserDao createUserDao(){
return new UserDao();
}
}
④实例化工厂注入 :
<bean id="sxtBeanFactory" class="com.shsxt.factory.SxtBeanFactory" >
<bean id="instanceFactory" class="com.shsxt.factory.InstanceFactory"></bean>
<bean id="userDao" factory-bean="instanceFactory" factory-method="createUserDao"></bean>
<bean id="userService" class="com.shsxt.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
**小结:**重点掌握 set,构造器注入,工厂方式了解即可。实际开发中基本使用 set 方式注入 bean。
2、Spring IOC集合类型属性注入
List集合注入:
<bean id="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl">
<property name="list">
<list>
<value>河南烩面</value>
<value>南方臊子面</value>
<value>油泼面</value>
<value>方便面</value>
</list>
</property
</bean>
Ser集合注入:
<bean id="userServiceImpl"
class="com.shsxt.service.impl.UserServiceImpl">
<property name="set">
<set>
<value>快乐小馒头</value>
<value>北方馒头</value>
<value>天津麻花</value>
<value>新疆大饼</value>
</set>
</property>
</bean>
Map集合注入:
<bean id="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl">
<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>
</bean>
properties 属性注入:
遍历类似Map
<bean id="userServiceImpl"
class="com.shsxt.service.impl.UserServiceImpl">
<property name="prop">
<props>
<prop key="北京">北京尚学堂</prop>
<prop key="上海">上海尚学堂</prop>
<prop key="西安">西安尚学堂</prop>
</props>
</property>
</bean>
3、注解方式注入bean
对于 bean 的注入,除了使用 xml 配置以外,注解的配置简化开发的速度,使程序 看上去更简洁。对于注解的解释,Spring 对于注解有专门的解释器,对定义的注解进行解 析,实现对应 bean 对象的注入,反射技术实现。
实现步骤:
-
加入Spring-aop jar包 Spring-aop-4.3.2RELEASE
-
Xml配置:加入context命名空间和xsd地址
-
添加context:annotation-config配置
<?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/context/Spring-context.xsd"> <context:annotation-config/> </beans>
常用注入注解类型
@Autowired
和@Resource
区别:
@Autowired 默认按 bean 的类型匹配可以修改按名称匹配和@Qualifier 配合使用。
@Resource 默认按名称进行装配,名称可以通过 name 属性进行指定,如果没有指定 name 属性,当注解写在字段上时,默认取字段名进行匹配注入,如果注解写在 setter 方 法上默认取属性名进行装配。当找不到与名称匹配的 bean 时才按照类型进行装配。但是 需要注意的是,如果 name 属性一旦指定,就只会按照名称进行装配。
小结:推荐使用@Resource 注解是属于 J2EE 的,减少了与 Spring 的耦合。
七、Bean的作用域和生命周期
在Spring容器中,一共提供五种作用域类型。可在配置文件中,通过属性scope(范围)设置bean的作用域返回,针对不同作用域。这个作用域指在spring容器中指其创建bean对象相对于其他bean对象的请求可见返回。
1、Bean的作用域
Singleton(单例):
在Spring Ioc容器中仅存在一个Bean实例,Bean以单例方式存在,默认值。无状态的Bean建议使用,Bean创建好之后会存在单例Bean的缓存池中,获取Bean时从池中直接拿取即可,性能高。
<!--设置scope属性为singleton-->
<bean id="userInfo" class="com.shsxt.Service" scope="singleton"/>
<!--设置singleton属性为true-->
<bean id="userInfo" class="com.shsxt.Service" singleton="true"/>
<!--默认为singleton-->
<bean id="userInfo" class="com.shsxt.Service"/>
Prototype(原型):
通过 scope=”prototype” 设置 bean 的类型 ,每次从容器中调用Bean是,都会返回一个新的实例,即每次调用getBean()时,相当于执行new XxxBean()。有状态的Bean建议使用,不会缓存。
<!--设置scope属性为prototype-->
<bean id="userInfo" class="com.shsxt.dao" scope="prototype"/>
Request:
表示每个请求需要容器创建一个全新 Bean。比如提交表单的数 据必须是对每次请求新建一个 Bean 来保持这些表单数据,请求结束释放这些数据。当处理请求结束,request作用域的bean实例将被销毁。
<!--设置scope属性为request-->
<bean id="userInfo" class="com.shsxt.dao" scope="request"/>
Session:
表示每个会话需要容器创建一个全新 Bean。比如对于每个用户 一般会有一个会话,该用户的用户信息需要存储到会话中,此时可以将该 Bean 作用域配置为 session 级别。每个HTTP Session中的实例都是独立互不影响的,当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃。
<!--设置scope属性为session-->
<bean id="userInfo" class="com.shsxt.dao" scope="sessio"/>
globalSession:
类似于 session 作用域,其用于 portlet(Portlet 是基于 Java 的 Web 组件,由 Portlet 容器管理,并由容器处理请求,生产动态内容)环境的 web 应用。 如果在非 portlet 环境将视为 session 作用域。
**小结:**Request、Session、globalSession这三个web作用只有在spring web ApplicationContext的实现中才会起作用,若在常规Spring IOC容器,比如ClassPathXmlApplicationContext中会收到illegal State Exception来告诉你不能识别bean的作用域。在使用springMVC访问这些作用域bean,会使用Spring DispatcherServlet或者类似DispatcherPortlet处理request,无需特别配置,因为已经爆露相关状态。若是非Spring的DispatcherServlet(比如说Struts)则需要注册。也就是在web.xml添加监听器–>RequestContextListener(Servlet2.4以前增加过滤器–>RequestContextFilter)值得注意的是它们三个做的都是相同的事情,就是绑定HTTPRequest对象到服务的Thread线程中,并开启接下来用到的scoped-session功能。
2、Bean的生命周期
bean装载到spring应用上下文中的生命周期过程:
Start->实例化->填充属性->调用BeanNameAware的setBeanName()方法->调用BeanFactoryAware的setBeanFactory()方法->调用ApplicationContextAware的setApplicationContext()方法->调用BeanPostProcessor的预初始化方法->调用InitializingBean的afterPropertiesSet()方法->调用自定义的初始化方法->调用BeanPostProcessor的初始化后方法->恭喜你到这一步bean可以使用了!->容器关闭->调用DisposableBean的destory()方法->调用自定义的销毁方法->End。
解析整个过程:
- spring对bean进行实例化
- spring将值和bean的引用注入到bean对应的属性中
- 如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBeanName方法
- 如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
- 如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的PostProcessBeforeInitalization()方法
- 如果bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet()方法。类似的如果bean使用initmethod声明了初始化方法后,该方法也会被调用。
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的PostProcessAfterInitalization()方法
- 此时bean已经准备就绪,可以被应用程序使用,它们将一直驻留在应用上下文中,直到该应用上下文被销毁
- 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法。同样如果bean使用destory-method声明了销毁方法,该方法也会调用。
八 、Spring中自动装配的方式
- no:不进行自动装配,手动设置Bean的依赖关系。
- byName:根据Bean的名字进行自动装配。
- byType:根据Bean的类型进行自动装配。
- constructor:类似于byType,不过是应用于构造器的参数,如果正好有一个Bean与构造器的参数类型相同则可以自动装配,否则会导致错误。
- autodetect:如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配
九、Spring支持的事务管理类型
Spring支持编程式事务管理和声明式事务管理。许多Spring框架的用户选择声明式事务管理,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理,尽管在灵活性方面它弱于编程式事务管理,因为编程式事务允许你通过代码控制业务。
事务分为全局事务和局部事务。全局事务由应用服务器管理,需要底层服务器JTA支持(如WebLogic、WildFly等)。局部事务和底层采用的持久化方案有关,例如使用JDBC进行持久化时,需要使用Connetion对象来操作事务;而采用Hibernate进行持久化时,需要使用Session对象来操作事务。
10、Spring IOC个人理解总结
什么是IOC?
IOC(Inversion of Control)是控制反转,不是什么技术,而是一种设计思想。意思就是对对象的创建和管理由原来的程序员自己手动创建,改成交给Spring管理,其优点是:降低对象与对象之间的依赖,实现组件的解耦。
控制?谁控制谁?控制什么?
传统的JavaSE程序设计,我们是直接在对象内部通过new创建对象,是程序主动创建依赖对象,而IOC有一个专门的容器来创建这些对象,所以说是IOC容器来控制对象的创建,主要控制外部资源获取(不只是对象,还有文件等等资源)
反转?哪些方面反转?
传统应用程序是由我们自己在对象中主动控制区直接获取依赖对象,这是正转;而反转就是有SpringIOC容器帮我们查找及注入依赖对象,对象只是被动的接收依赖对象,所以说是反转。反转的是依赖对象的获取。
什么是DI?
DI叫依赖注入,它是从对象之间关系角度来说明IOC,是IOC的另外的一种表达方式。依赖注入方式:构造器注入、setter注入、静态工厂注入、实例化工厂注入。
谁依赖于谁?
应用程序依赖于IOC容器
为什么需要依赖?
应用程序需要IOC容器来提供某个对象需要的外部资源
谁注入谁?
IOC容器注入应用程序某个对象,应用程序一开的对象
注入了什么?
注入某个对象所欲要的外部资源(对象、资源、常量数据…)
什么是Bean?
Bean就是交由Spring管理的对象,Bean实例化的方式:构造器实例化、静态工厂实例化、实例化工厂创建现组件的解耦。