spring之IOC容器

1.IOC概述

spring的核心技术就是IOC和aop,先来介绍一下IOC,inversion of control的缩写,即控制反转。那么什么叫控制反转呢?先来了解一下程序耦合的概念。在软件工程中,程序的耦合指的是对象之间的依赖关系,依赖关系越强那么耦合度就越高,那么程序的独立性就很差,维护成本就越大。因此,我们要尽量减低程序之间的耦合。
那么我们怎么减低耦合呢?例如我们通过三层架构模式实现对数据库中学生信息表的增删查改,我们知道控制层会调用service业务逻辑层,而业务逻辑层又会调用持久层,这时候我们的程序耦合度就比较高,因为我们创建一个对象必须依赖例外一个对象,所以我们可以使用工厂模式解耦:即我们在创建对象时并不通过具体的new一个对象,而是先在配置文件中以key=value的形式配置,key即获取bean对象的id,value即对应的完整类名。然后通过一个工厂类加载配置文件,拿到key,value通过反射技术创建对象。这时候我们再需要创建对象只要通过id拿就可以,减低了程序之间的耦合。
代码如下:

bean.property文件:

StudentDao=dao.StudentDao
StudentService=service.StudentService

工厂类:

public class BeanFactory {
	private static Properties prop;
	//创建bean容器用来存取bean对象
	private static Map<String,Object> beans;
	static{
		beans = new HashMap<String,Object>();
		//创建Properties对象
		prop = new Properties();
		//输入流读取配置文件
		InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
		try {
			prop.load(in);
			//获取所有的bean
			Enumeration<Object> keys = prop.keys();
			//遍历keys
			while(keys.hasMoreElements()){
				String key = keys.nextElement().toString();
				String beanPath = prop.getProperty(key);
				//通过反射构造对象
				Object bean = Class.forName(beanPath).newInstance();
				//存到容器中
				beans.put(key, bean);
			}
		} catch (Exception e) {
		// TODO Auto-generated catch block
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
	/*使用单例模式进行改造
	    public static Object getBean(String beanName){
		Object bean=null;
		String beanPath = prop.getProperty(beanName);
		System.out.println(beanPath);
		//通过反射构造bean对象
		try {
			bean = Class.forName(beanPath).newInstance();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		return bean;
	}*/
	public static Object getBean(String beanName){
		return beans.get(beanName);
	}
	
}

这时候就可以直接拿bean对象:

package service;

import dao.StudentDao;
import factory.BeanFactory;

public class StudentService {
	//直接通过id获取到studentDao对象
	private StudentDao studentDao = (StudentDao) BeanFactory.getBean("StudentDao");
	public void save(){
		studentDao.save();
	}
}

理解上面解耦的过程,可以说说IOC了,简单的说IOC就是为了减低程序之间耦合性的,把我们随意创建对象的控制权交给spring来管理,因此叫做控制反转。

2. IOC入门案例

2.1 首先到入核心jar包(这里使用的是spring3.2.5版本):

及日志支持包:
在这里插入图片描述
2.2 准备目标类:之前创建该对象都是通过new,待会通过配置直接向IOC容器拿就行了。

package entity;

public class Player {

	private String name;
	private int age;
	public Player(){
		System.out.println("player对象创建了");
	}
	public void init(){
		System.out.println("执行了init方法");
	}
	public void destroy(){
		System.out.println("执行了destroy方法");
	}
}

2.3 配置XML文件:

  • 路径:可以任意,建议放在src下
  • 名称:随意
  • 添加约束:如果记不住可以收藏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">
          
           <bean id="Player" class="entity.Player" scope="singleton" init-method="init" destroy-method="destroy"></bean>
	
</beans>

我们来测试一下

package test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import entity.Player;
import entity.Team;


/*
 * 测试spring环境搭建
 */
public class Test {

	public static void main(String[] args) {
		//获取IOC容器对象
		//使用ClassPathXmlApplicationContext创建容器,在创建时就会实例化bean对象
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		Team team = (Team) ac.getBean("Team");
		Player player = (Player) ac.getBean("Player");
		System.out.println(team);
		System.out.println(player);
	}
}
这里说一下spring创建bean对象的几种方式:
第一种:使用bean的无参构造函数创建 
	<bean id="Team" class="entity.Team"></bean>
	<bean id="Player" class="entity.Player"></bean>
		第二种:通过普通工厂中的方法创建对象(通过一个类的方法创建另一个类的实例)
	<bean id="PlayerFactory" class="factory.PlayerFactory"></bean>
	<bean id="Player" factory-bean="PlayerFactory" factory-method="getPlayer"></bean>
		第三种:通过普通工厂的静态方法创建对象( 通过一个类的静态方法创建另一个类的实例)
	<bean id="Team" class="factory.PlayerFactory" factory-method="getTeam"></bean>
	
bean对象的作用域:
	通过scope属性设置:
	singleton:表示bean是单例(默认)
	prototype:表示bean是多例
	request:表示作用域web请求
	session:表示作用域websession会话
	global-sesssion:表示作用于集群环境下的session
bean的生命周期

bean对象的生命周期
单例:单例bean跟IOC容器同生共死
多例:使用时创建,长时间不用时有垃圾回收器回收

3. 依赖注入入门案例

依赖注入:把有依赖关系的类放到容器中,解析出这些类的实例,就是依赖注入。spring中提供三种方式依赖注入:通过构造方法,set方法,注解

3.1基于xml通过构造方法或set依赖注入

  • 导入jar包,跟上面的包一样

  • 准备目标类:用于测试注入基本类型数据和复杂类型数据(集合)

package entity;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class Student {

	private int id;
	private String name;
	private Date birthday;
	private String[] myArray;
	private List<String> myList;
	private Map<String,String> myMap;
	private Set<String> mySet;
	private Properties myProp ;
	
	public Student(int id, String name, Date birthday, String[] myArray,
			List<String> myList, Map<String, String> myMap, Set<String> mySet,
			Properties myProp) {
		super();
		this.id = id;
		this.name = name;
		this.birthday = birthday;
		this.myArray = myArray;
		this.myList = myList;
		this.myMap = myMap;
		this.mySet = mySet;
		this.myProp = myProp;
	}
	
	
	public void setName(String name) {
		this.name = name;
	}
	public void setId(int id) {
		this.id = id;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	public void setMyArray(String[] myArray) {
		this.myArray = myArray;
	}
	public void setMyList(List<String> myList) {
		this.myList = myList;
	}
	public void setMyMap(Map<String, String> myMap) {
		this.myMap = myMap;
	}
	public void setMySet(Set<String> mySet) {
		this.mySet = mySet;
	}
	public void setMyProp(Properties myProp) {
		this.myProp = myProp;
	}
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", birthday="
				+ birthday + ", myArray=" + Arrays.toString(myArray)
				+ ", myList=" + myList + ", myMap=" + myMap + ", mySet="
				+ mySet + ", myProp=" + myProp + "]";
	}
	
}
  • 配置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="Student" class="entity.Student">
		<constructor-arg name="id" value="1101"></constructor-arg>
		<constructor-arg name="name" value="狗娃"></constructor-arg>
		<constructor-arg name="birthday" ref="Date"></constructor-arg>
	</bean>
	-->           
    <bean name="Date" class="java.util.Date"></bean>
           
    <!-- 依赖注入:通过set方法注入 -->       
    <bean id="Student" class="entity.Student">
    	<property name="id" value="1102"></property>
    	<property name="name" value="狗蛋"></property>
    	<property name="birthday" ref="Date"></property>
    	<!-- 复杂类型的注入(集合) -->
    	<property name="mySet">
    		<set>
    			 <value>aaa</value>
    			 <value>bbb</value>
    			 <value>ccc</value>
    		</set>
    	</property>
    	<property name="myMap">
    		<map>
    			<entry key="a" value="aaa"></entry>
    			<entry key="b" value="bbb"></entry>
    			<entry key="c" value="ccc"></entry>
    		</map>
    	
    	</property>
    </bean>
    
           
           
</beans>
  • 测试:
package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import entity.Student;

/*
 * 依赖注入测试类
 */
public class Test {

	public static void main(String[] args) {
		//获取到IOC容器对象
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		Student student = (Student) ac.getBean("Student");
		System.out.println(student);
		
	}
}

3.2 基于注解的依赖注入

这里通过模拟对数据库student的增删查改说明

  • 导包:在前面包的基础上导入spring-context-3.2.5.RELEASE.jar
    在这里插入图片描述
  • 准备类
    实体类:
package entity;

import org.springframework.stereotype.Component;
@Component
public class Student {

	private int id;
	private String name;
	public Student(){
		
	}
}

持久层dao:

package dao;

import org.springframework.stereotype.Repository;

/*
 * 持久层
 */
@Repository(value="dao")
public class StudentDao implements IStudentDao{

	public void save(){
		System.out.println("保存了1111111");
	}
}

业务逻辑层service:

@Service
public class StudentService {

	//@Autowired
	//@Qualifier(value="dao2")
	@Resource(name="dao2")
	private IStudentDao dao;
	public void save(){
		dao.save();
	}
}
  • 通过xml文件开开启注解扫描(需要先导入context约束)
<?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">
        
        <!-- 使用IOC注解步骤:
        	1.导入context命名空间
        	2.开启注解扫描
        	3.使用注解
        -->
        <context:component-scan base-package="service"></context:component-scan>
        <context:component-scan base-package="dao"></context:component-scan>
       
          
</beans>
  • 测试:
public class App {

	private static StudentService service;
	public static void main(String[] args) {
		//创建容器对象
		ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
		service = (StudentService) ac.getBean("studentService");
		service.save();
	}
}

解释一下注解的意思:
业务逻辑层
用于生成对象的注解:

  • Component:实例化当前类,并将对象放入IOC容器中。默认id是第一个字母小写的该类名
    下面三个注解与Component注解作用一样,只是为了使三层结构更加清晰

  • Controler:表现层

  • Service:业务逻辑层

  • Repository:持久层
    用于注入数据的注解:

  • Autowired:自动按照类型注入,在IOC容器中只有唯一的bean对象类型和要注入的对象类型一致时,注入成功。

  • 当容器中有多个bean对象匹配时则按照bean的id(key)与要注入的对象变量名匹配

  • Qualifier:与类注入注解Autowired配合使用,可以指定注入bean的id(key)

  • Resource:直接按照bean的id注入,可以独立使用

上面三个注解只能住bean类型的,复杂(集合)类型的只能通过xml配置注入。

  • value:用于注入基本类型,String类型。在value属性中可以写spel(sprin中的EL表达式)

用于作用域的注解:

  • scope:跟xml配置一样,有singleton(单例),prototype(多例)
发布了13 篇原创文章 · 获赞 0 · 访问量 145
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 游动-白 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览