Spring IOC

Spring IOC 解释与实现


一 什么是IOC

Inversin Of Control 控制反转, 解决了对象之间的解耦问题
程序创建对象的方式由之前new 的方式变成了由 框架 来创建和注入,这样做可以降低对象之间的耦合度。IOC的主要作用是管理程序的组件,创建对象和维护组件之间的关系

1、什么是Spring 容器?

  • 在Spring 容器中,任何的Java类都被当成Bean 组件,通过容器管理和使用(任何的Java类 都可以由Spring 对象 创建对象 并进行管理 以及为维护组件关系)
  • Spring 容器中实现了IOC(控制反转) 和AOP(面向切面编程)机制,
  • Spring 容器有 ApplicationContext (应用程序上下文)和 BeanFactory (工厂模式)两种类型

2、如何使用Spring 容器

  1. 先建立一个项目, 准备好相应的 IOC的jar包点击下载建立Spring 项目相关jar包

  2. 配置Spring 相应的配置文件(applicationContext.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" 
    	xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
    	xmlns:jee="http://www.springframework.org/schema/jee" 
    	xmlns:tx="http://www.springframework.org/schema/tx"
    	xmlns:aop="http://www.springframework.org/schema/aop" 
    	xmlns:mvc="http://www.springframework.org/schema/mvc"
    	xmlns:util="http://www.springframework.org/schema/util"
    	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    	xsi:schemaLocation="
    		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
    		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd
    		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
    		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
    		http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
    		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
    		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
    		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd"><!-- schema格式限制,一下代码必须符合*.xsd中限定的规范  -->
    		<!-- 利用反射机制创建对象  -->
    		<!-- <bean id="bean组件标识" class="包名.类名"></bean> -->
    		<bean id="date" class="java.util.Date"></bean>
    </beans>
    
  3. 创建Spring 容器对象 然后获取容器中创建的对象的组件对象

    import java.util.Date;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class ApplicationContextTest1 {
    	public static void main(String[] args) {
    		    // 创建Spring 容器对象 
    		    ApplicationContext appContext = 
    		    		new ClassPathXmlApplicationContext("applicationContext.xml");
                // 获取容器中对应的对象
    		    Date date = (Date)appContext.getBean("date");
    		    System.out.println(date);
    		    // 经典写法 
    		    Date date2 = appContext.getBean("date", Date.class);
    		    System.out.println(date2);
    	}
    }
    

3、Spring 容器创建对象对的三种方式

  • 构造器的方式 实例化(默认调用无参构造器)
    配置文件:
    <bean id="对象标识符" class="对象包名.类目名"></bean>
    
    代码实现:
     // 创建Spring 容器对象 
     ApplicationContext appContext = 
     		new ClassPathXmlApplicationContext("配置文件相对路径");
           // 获取容器中对应的对象
     Date date2 = appContext.getBean("对象标识符", 对象包名.类目名);
    
  • 静态工厂的方法 实例化
    配置文件:
    <bean id="对象标识符" class="工厂包名.工厂类名" factory-method="静态方法名"></bean>
    
    代码实现:
     // 创建Spring 容器对象 
     ApplicationContext appContext = 
     		new ClassPathXmlApplicationContext("配置文件相对路径");
           // 获取容器中对应的对象
     Date date2 = appContext.getBean("对象标识符", 对象包名.类目名);
    
  • 实例化工厂方法 实例化(一般是用于 使用一个已经存在的对象 来创建另一个类型的对象)
    配置文件:
    <bean id="对象标识符" class="工厂包名.工厂类名" factory-method="实例化方法名" factory-bean="工厂对象id"></bean>
    
    代码实现:
     // 创建Spring 容器对象 
     ApplicationContext appContext = 
     		new ClassPathXmlApplicationContext("配置文件相对路径");
           // 获取容器中对应的对象
     Date date2 = appContext.getBean("对象标识符", 对象包名.类目名);
    

4、Spring 中 bean 对象的作用域

使用bean 标签中的 Scope 属性来指定, 值有:

  • singleton 单例(默认的), 在每个Spring IOC 容器中,一个 bean,定义一个对象实例
  • prototype 非单例 ,一个bean 对应多个对象实例
  • request 在一个HTTP 请求中,一个bean 定义一个实例(仅限于Web环境)
  • session 在一个HTTP Session 请求中,一个bean 定义一个实例(仅限于Web环境)
  • global Session 在一个全局的 HTTP Session 中,一个bean 定义一个实例(仅在基于portlet的Web环境中)

5、bean对象的初始化

一个对象调用构造方法之后 可以进行初始化初始化的手段有两种:

  • 第一在beans标签中 加 default-init-method=“初始化方法名” (由于这种方式影响范围比较大,则类中没有定义这个方法,也不会报错)
  • 第二种方式是在bean标签中加 init-method=“初始化方法名” (由于这种方式影响范围比较小,则类中没有定义这个方法,会报错)

6、bean对象的销毁

指定Spring容器销毁Bean对象的销毁方法也是两种:

  • 第一在beans标签中 加 default-destroy-method=“销毁方法名” (由于这种方式影响范围比较大,则类中没有定义这个方法,也不会报错)
  • 第二种方式是在bean标签中加 destroy-method=“销毁方法名” (由于这种方式影响范围比较小,则类中没有定义这个方法,会报错,需要注意的是,必须在单例的模式下)

7、bean对象的延迟实例化

如果 实例的对象是单例的,延迟实例化的两种方式:

  • 第一在beans标签中 加 default-lazy-method=“销毁方法名” (默认是false)
  • 第二种方式是在bean标签中加 lazy-method=“销毁方法名” (默认是false)

二 什么是DI

Dependence Injection 依赖注入 ,他是对IOC的一种具体实现,他解决的问题是 组件之间的关联关系(装配)问题

三 DI的实现方式

1、setter 注入

看set方法后的标识,去了set,把后面的内容首字母小写

<bean  id="对象标识符"  class="包名.类名">
	<property name="属性名(去了set,把后面的内容首字母小写)"  value="注入的值"></property>
	<!-- 如果注入的值是 引用类型  -->
	<property name="属性名(去了set,把后面的内容首字母小写)"  ref="对象标识符"></property>
</bean>

2、构造器 注入

<bean  id="对象标识符"  class="包名.类名">
	<constructor-arg  index="属性的下标"  value="注入的值"></constructor-arg>
	<!-- 如果注入的值是 引用类型  -->
	<constructor-arg  index="属性的下标"  ref="对象标识符"></constructor-arg>
</bean>

3、自动化 注入

在bean 标签上 指点一个属性 autowire 可以根据指定的值 进行 自动化 注入

  • byName 检查Spring 中有没有和属性名一致的 对象 id 如果找不到 不会报错
  • constructor 可以使用<constructor-arg 占参数位置 然后 剩下的参数 可以采用自动化 优先使用名字进行匹配 如果名字不符合会启用类型查找
  • byType 根据Spring 中属性类型进行查找,如果找不到或者多个类型相同的,会报错
    <!-- autowire="constructor"   -->
    <bean  id="对象标识符"  class="包名.类名"   autowire="constructor">
    	<constructor-arg  index="属性的下标"  value="注入的值"></constructor-arg>
    	<!-- 如果注入的值是 引用类型  -->
    	<constructor-arg  index="属性的下标"  ref="对象标识符"></constructor-arg>
    </bean>
    <!-- autowire="byName"   -->
    <bean  id="对象标识符"  class="包名.类名"  autowire="byName">
            <property name="属性名"  value=""></property>
    </bean>
    <!-- autowire="byType"   -->
    <bean  id="对象标识符"  class="包名.类名"  autowire="byType">
            <property name="属性名"  value=""></property>
    </bean>
    

4、bean 参数的注入

  • 简单值得注入 主要以setter 注入为主, 构造器注入为辅

    <bean id="对象标识符"  class="包名.类名">
    	<property name="属性名" value=""></property>
    </bean>
    
  • 集合类型的注入List ,Set(Set的值会排重),Map, Properties等

    <bean id="对象标识符"  class="包名.类名">
    	<property name="属性名">
    		<list>
    			<value></value>
    			<value></value>
    		</list>
    	</property>
    	<property name="属性名">
    		<set>
    			<value></value>
    			<value></value>
    		</set>
    	</property>
    	<property name="属性名">
    		<map>
    			<entry key="" value=""></entry>
    			<entry key="" value=""/>
    		</map>
    	</property>
    	<property name="属性名">
    		<props>
    			<prop key=""></prop>
    			<prop key=""></prop>
    		</props>
    	</property>
    </bean>
    
  • 自定义List,Set,Map, Properties等集合

    <util:list id="list自定义对象标识符">
    	<value></value>
    </util:list>
    
    <util:set id="set自定义对象标识符">
    	<value></value>
    </util:set>
    
    <util:map id="map自定义对象标识符">
    	<entry key="" value="" ></entry >
    </util:map>
    
    <util:properties id="properties自定义对象标识符">
        <prop key=""></prop>
    </util:properties>
    
    <bean id="对象标识符"  class="包名.类名">
    	<property name="属性名" ref="list自定义对象标识符"></property>
    	<property name="属性名" ref="set自定义对象标识符"></property>
    	<property name="属性名" ref="map自定义对象标识符"></property>
    	<property name="属性名" ref="properties自定义对象标识符"></property>
    </bean>
    
  • 文件引入及表达式的引用
    表达式值得引用:#{key}
    表达式对象的引用:#{自定义对象标识符.key}
    引用其他配置文件

     <util:properties id="自定义对象标识符" location="classpath:需要引入配置文件的相对路径"/>
    

    数据库连接池的例子:
    1、表达式的使用:

    <!--  连接数据库信息 单独封装成一个集合  -->
    <util:properties id="db">
        <prop key="driverClassName">oracle.jdbc.OracleDriver</prop>
        <prop key="url">jdbc:oracle:thin:@127.0.0.1:1521:xe</prop>
        <prop key="username">system</prop>
        <prop key="password">123456</prop>
    </util:properties>
    <!-- 配置一个数据源  -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="#{db.driverClassName}"/>
        <property name="url" value="#{db.url}"/>
        <property name="username" value="#{db.username}"/>
        <property name="password" value="#{db.password}"/>
    </bean>
    

    2、引入其他配置文件 及 表达式的使用

    <!-- 引入其他配置文件  -->
    <util:properties id="db" location="classpath:db.properties"></util:properties>
    <!-- 配置一个数据源  -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="#{db.driverClassName}"/>
        <property name="url" value="#{db.url}"/>
        <property name="username" value="#{db.username}"/>
        <property name="password" value="#{db.password}"/>
    </bean>
    

四 组件扫面

为了简化之前的配置文件
Spring提供了一套基于注解(标注)配置文件的使用方法,使用该方法可以大大简化XML配置信息。

1、 和组件创建相关的注解

注解描述
@Component通用层组件注解
@Repository持久化层组件注解
@Service业务逻辑层组件注解
@Controller控制层组件注解

2、 组件创建及注解的使用

base-package:
指定组件扫面的开始位置,最扫描指定包及其子包下的
配置文件:

<?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-4.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
	<!-- 开启组件扫描  -->
	<context:component-scan base-package="包名"/>
</beans>

添加注解的类:

package com.test.bean;

import org.springframework.stereotype.Component;

// @Component() // 获取的值是类名首字母小写
// @Component(value="player") // 获取的值的义名字
@Component("player") // 获取的值的义名字
public class Player {
       public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getTeam() {
		return team;
	}
	public void setTeam(String team) {
		this.team = team;
	}
	public Player(String name, String team) {
		super();
		this.name = name;
		this.team = team;
	}
	public Player() {
		super();
		name="no name";
		team="no team";
	}
	private String name;
    private String team;
}

创建对象及调用:

package com.test.test;

import com.test.bean.Player;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ComponentScanTest {
	@Test
	public void test() {
	       ApplicationContext app =
				   new ClassPathXmlApplicationContext("applicationContext.xml");
	       Player player = app.getBean("player", Player.class);
	       System.out.println("player.getName(): "+player.getName());
	       System.out.println("player.getTeam(): "+player.getTeam());
	}
}

结果打印:
测试结果

3、组件扫描相关的其他注解(标注)

  • @Scrop : 控制bean的作用域,与之前 bean 标签中scope 属性完全相同
  • @PostConstructor :初始化方法, 和之前的init-method 属性相同
  • @PreDestroy :对象销毁之前调用的方法, 和之前的destroy-method 属性相同

4、和组件装配(配置)相关的注解(标注)

  • @Value :注入简单值,复杂值需要结合 #{key} 表达式
  • @AutoWired :可以加在 成员变量、 set方法、带参构造方法上 优先采用类型注入 找不到则启用名字查找 使用**@Qualifier(“名字”) **来指定名字查找
  • @Resource :可以加载成员变量、set方法上,并且 这个标注 是java 语言库中的,优先使用名字查找 找不到启用类型查找,还可以使用name属性指定名字
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值