Spring IOC知识详解

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的方式比较

  1. 通过 bean 的缺省构造函数创建,当各个 bean 的业务逻辑相互比较独立的时候 或者和外界关联较少的时候可以使用。
  2. 利用静态 factory 方法创建,可以统一管理各个 bean 的创建,如各个 bean 在 创建之前需要相同的初始化处理,则可用这个 factory 方法险进行统一的处理等等。
  3. 利用实例化 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实例化的方式:构造器实例化、静态工厂实例化、实例化工厂创建现组件的解耦。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值