spring02——IOC(控制反转)、依赖注入和依赖查找

英文名:Inversion of control
定义:把对象的创建、初始化、销毁工作交给spring容器来做,由spring容器来管理对象的生命周期
1、IOC不是一种技术,只是一种开发思想,一种重要的面向对象编程的法则。可以设计出松耦合更加优良的系统程序。
2、IOC包括两部分:依赖注入(DI)和依赖查找。
3、spring 的注入:就是在实例化这个类的时候,由外部的容器来设置这个对象的值。

IOC包括依赖注入(DI)和依赖查找(依赖注入是核心)
我们可以实现只是定义,不需要进行getBean获取了

启用原有项目

我们还是使用上一次建的项目。
现在新建一个User类

package com.cbb.bean;

import java.util.List;
import java.util.Map;

/** 
 * 类描述:注入各种类型的
 * 作者: 地铁与人海
 * 创建日期:2019年3月12日
 * 修改人:
 * 修改日期:
 * 修改内容:
 * 版本号: 1.0.0   
 */

public class User {
	private int id;
	
	private String name;
	
	private List<String> scores;
	
	private Map<String, Object> info;
	
	private Car car;//汽车 注入类

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<String> getScores() {
		return scores;
	}

	public void setScores(List<String> scores) {
		this.scores = scores;
	}

	public Map<String, Object> getInfo() {
		return info;
	}

	public void setInfo(Map<String, Object> info) {
		this.info = info;
	}

	public Car getCar() {
		return car;
	}

	public void setCar(Car car) {
		this.car = car;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", scores=" + scores + ", info=" + info + ", car=" + car + "]";
	}
	
}

其中的Car的定义我们先不使用,你可以先注释掉,然后改一下我们生成的方法。
ps:一定要有setter方法,有setter方法才能注入

我们继续在applicationContext.xml中进行配置Bean

<bean id = "user" class="com.cbb.bean.User">

我们再测试使用一下,还是在BeanTest.java中

@Test
	public void IOCtest() {
		//加载spring容器
		ApplicationContext app = 
				new ClassPathXmlApplicationContext("applicationContext.xml");
		//获取springbean
		User user  = app.getBean("user", User.class);
		System.err.println(user.toString());//属性为空,这个对象不是空
	}

结果我们可以获取到对象(和上一篇的例子一样),但里面的属性为空。
所以我们现在要干的事情,就是在获取对象的时候,由外部容器来设置这个对象的值。

属性注入

属性的注入要由容器来完成,所以就要在容器中再次进行配置可以配置的选项如图:
可以配置的属性
property是我们常用的属性注入标签
支持的类型有:
在这里插入图片描述
注意:一定要有set方法才能注入
下面是使用

<bean id = "user" class="com.cbb.bean.User">
		<!--注入必须保证注入的属性要有setter方法
			通过<property>标签进行配置 
			name指哪个属性    value 是具体设置的值
		 -->
		<property name="id" value = "2"></property>
		<property name = "name" value = "jack"></property>
		<!--  -->
		<property name="scores" >
			<list>
				<value>100</value>
				<value>76</value>
			</list>
		</property>
		<property name = "info">
			<map>
				<entry key= "age" value="23"></entry>
				<entry key="school" value="五道口职业技术学院"></entry>
			</map>
		</property>
	</bean>

然后我们再运行方法,就发现可以出来我们设计的数据了。

我这还有更全的数据类型注入:
这是属性

public class Person {
private String name;
private Integer age;
private String[] strs;
private List<String> coll;
private Set<String> sets;
private Map<String,Object> mm;
}

这是配置

<bean id="person" class="com.hpe.Person">
 <property name="name" value="jack"></property>
 <property name="age" value="11"></property>
  <property name="strs">
 <array>
 <value>CCCCC</value>
 <value>DDDDD</value>
 </array>
 </property>
 <property name="coll">
 <list>
 <value>aa</value>
 <value>bb</value>
 </list>
 </property>
 <property name="sets">
 <set>
 <value>AAAA</value>
 <value>BBBB</value>
 </set>
 </property>
 <property name="mm">
 <map>
 <entry key="name" value="zhangsan"></entry>
 <entry key="tel"><value>10086</value></entry>
 </map>
 </property>
 </bean>

你们可以对应来看。

现在我们来进行注入其他类的实现。
首先,我们要注入的其他类也需要在spring容器内管理,也就是需要在applicationContext.xml里面配置
明白了只一点我们进行配置。
先写一个小汽车类

package com.cbb.bean;

/** 
 * 类描述:汽车类
 * 作者: 地铁与人海
 * 创建日期:2019年3月12日
 * 修改人:
 * 修改日期:
 * 修改内容:
 * 版本号: 1.0.0   
 */

public class Car {
	private String carName;

	public String getCarName() {
		return carName;
	}

	public void setCarName(String carName) {
		this.carName = carName;
	}

	@Override
	public String toString() {
		return "Car [carName=" + carName + "]";
	}
	
}

配置

<bean id = "myCar" class="com.cbb.bean.Car" scope="singleton">
		<property name="carName" value="宝马"></property>
	</bean>
重点

我们进行在user中进行car的注入

	<bean id = "user" class="com.cbb.bean.User">
		<!--注入必须保证注入的属性要有setter方法
			通过<property>标签进行配置 	name指哪个属性 value 是具体设置的值
		 -->
		<property name="id" value = "2"></property>
		<property name = "name" value = "jack"></property>
		<!--  -->
		<property name="scores" >
			<list>
				<value>100</value>
				<value>76</value>
			</list>
		</property>
		<property name = "info">
			<map>
				<entry key= "age" value="23"></entry>
				<entry key="school" value="五道口职业技术学院"></entry>
			</map>
		</property>
		<!-- 通过ref指向其他bean的引用 -->
		<property name="car"  ref="myCar"></property>
	</bean>

要写在上面的pplicationContext.xml`里面。
然后我们再运行一下方法,就能实现了。

Bean的作用域

  • 通过bean的scope进行配置

1、singleton:单例模式(缺省默认)(默认情况下)spring容器中只存在一个实例

2、prototype:原型模式。每次通过spring容器获取bean时,容器会创建一个新的实例进行返回

3、request:在同一次请求中,获取的是同一个实例,不同的请求获取的是不同的实例。

4、session:在同一次会话中,获取的是同一个实例,不同的会话求获取的是不同的实例。

Bean的生命周期

Spring 容器可以管理 singleton 作用域下 Bean 的生命周期,在此作用域下,Spring能够精确地知道 Bean 何时被创建,何时初始化完成,以及何时被销毁。而对于 prototyp作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给了客户端的代码管理,Spring 容器将不再跟踪其生命周期,并且不会管理那些被配置成prototype 作用域的 Bean 的生命周期

**Bean 的实例化

1、构造器实例化
Spring 容器通过 Bean 对应的默认的构造函数来实例化 Bean。
2、静态工程方式实例化
通过创建静态工厂的方法来创建 Bean 的实例

Bean的配置方式

我们要写一个mvc设计模式的项目,就需要在service层中new一个dao实现对象,在controller层中new一个service实现对象,在Test层中new一个controller层对象。

现在我们使用spring来统一管理,就只需要对对象进行定义即可。
然而我们还需要加上,是我们new的这个对象的getter和setter方法(setter方法更重要),所以就形成了下面的例子。
在这里插入图片描述
这是我们的目录结构,(不需要pojo类,就没写)
下面是各个类

package com.cbb.controller;

import com.cbb.service.UserService;

public class UserController {
	
	/*private UserService userService = new UserServiceImpl();*/
	private  UserService userService;
	
	public void login() {
		System.err.println("controller......login......");
		userService.login();
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}	
	
}
package com.cbb.dao;
public interface UserDao {

	/** 
	 * 方法描述:
	 */
	void login();
}
package com.cbb.dao.impl;

import com.cbb.dao.UserDao;
public class UserDaoImpl implements UserDao {

	@Override
	public void login() {
		System.err.println("Dao......login......");
		
	}

}
package com.cbb.service;

public interface UserService {

	/** 
	 * 方法描述:
	 */
	void login();

}
package com.cbb.service.impl;

import com.cbb.dao.UserDao;
import com.cbb.service.UserService;


public class UserServiceImpl implements UserService {
	
/*	private UserDao userDao = new UserDaoImpl();*/
	private UserDao userDao;
	
	@Override
	public void login() {
		System.err.println("service......login......");
		userDao.login();
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}	
}
package com.cbb.test;

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

import com.cbb.controller.UserController;
import com.cbb.dao.impl.UserDaoImpl;



public class SpringTest {
	@Test
	public void Test() {
		System.err.println("正常的方法");
	}
	@Test
	public void test2() {
		ApplicationContext app = 
				new ClassPathXmlApplicationContext("applicationContext.xml");
		UserController uc = app.getBean("userController", UserController.class);
		uc.login();
		//测试一下直接获取dao层的方法
		UserDaoImpl ud = app.getBean("ud", UserDaoImpl.class);
		ud.login();
	}
}
<?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.cbb.controller.UserController">
		<property name="userService" ref="userService"></property>
	</bean>
	
	<!-- 这里要写实现类,而不是接口 -->
	<bean id = "userService" class = "com.cbb.service.impl.UserServiceImpl" >
		<property name="userDao" ref="ud"></property>
	</bean>
	
	<bean id = "ud" class = "com.cbb.dao.impl.UserDaoImpl"></bean>

</beans>

上面有两处使用的是构造器实例化 ,也有两处使用的是静态工程方式实例化(其中一个是测试),你们可以找一下。
好吧,test类中使用的是金改工程方式实例化的。

使用这种方法需要注意:
1、属性注入需要有 对应的setter方法
2、注入其他类 bean要有无参构造方法

使用注解的的方式配置Bean

这是第二种配置方式
首先我们需要导入一个新的jar包
在这里插入图片描述
你们可以对比发现,多了一个aop包。
然后我们写一个配置文件
直接一句话搞定

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	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
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	
	<!-- 扫描包下的注解的组件,把他们自动的注册到springbean中 -->
	<!-- 被注解的才会被扫描 --><!-- 可以把路径写大,如:com.cbb -->
	<context:component-scan base-package="com.cbb"></context:component-scan>
	
</beans>

但注意他的功能是只有被注解的才会被扫描。

然后我们对各个类进行注解,使用的标签和作用如下
四个组件
默认bean的名字,是类名首字母小写,也可以自己定义
如图
四个组件。
然后我们还需要在定义对象的时候进行注解。
也就是用@Autowired(还有其他的)
然后我们就可以删掉类里面的get和set方法了。

如图
上面的注解也会有错误,因为UserService有可能有两个实现类。
@Qualifierd//指定bean的名字
@Resource //会根据属性的名字去查找对应的bean,如果查找不到,再根据类型进行匹配
然后就可以正常使用了。

ps:依赖查找是什么,我不太清楚,希望有大神可以帮帮我
END

猜你喜欢

转载自blog.csdn.net/qq_37989076/article/details/88606323