一、IOC(控制反转)
所谓的控制反转就是将对象的创建权交给Spring。对象不在由我们自己手动实例化,而是通过Spring的配置进行实例化。那么为什么要进行控制反转,是为了程序能够更好的解耦和,倘若,由于一些需求,原本底层是使用jdbc实现Dao接口的,此时,如果要求使用hibernate实现Dao接口,那么,我是不是要将项目中所有实例化jdbc的类,全部改成实例化hibernate。此时,我是不是要一个个打开项目中的文件将JdbcDaoImpl修改为HibernateDaoImpl,这样的项目耦合是不是很大,所以使用Spring就可以帮我们很好的解决这个问题。只需要修改配置文件就可以达到目的。
IOC的底层实现原理是“工厂模式”+“反射”+“配置文件”。在Spring中注入一个类,在applicationContext.xml(Spring中的核心配置)对它进行配置。
<bean id="productDao" class="demo3.ProductDaoImpl"></bean>
id可以任意取值,但是在applicationContext中要唯一,class表示注入的类,即类的全路径
通过配置文件中的类,我们便可以找到实现类。即配置文件+反射。在通过工厂模式便可以实现管理Spring中的注入类。
二、IOC的实现
(1)使用xml方式
新建applicationContext.xml文件(命名可以为applicationContext官方推荐,当然也可以不是,但在加载配置文件的时候要注意)
<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">...............................................
</beans>
控制反转就是,在applicationContext中配置bean
bean中主要有三个重要的参数,id值,class值,以及scope值。当然还有init-method和destroy-method(了解即可)的配置
id值:applicationContext中的唯一标识,id的作用不言而喻,找到实现类
class值:实现类的全路径,通过id找到该实现类
scope值:作用范围的意思
scope一共有5个参数
singleton:(默认)spring采用单例模式创建对象(常用)
prototype:spring采用多例模式创建对象(常用,在整合struts2时,要记住改为多例模式)
request:spring创建这个对象后将它存入到request范围中
session:spring创建这个对象后将它存入到session范围中
globalsession:在prolet环境下使用,所谓的prolet就是指一个系统用许多子系统,譬如百度搜索,但我登录百度账号后,我的百度云可以使用我的个人信息,我的百度知道可以使用我的个人信息。这样就是prolet环境。spring创建这个对象后将它存入到prolet环境中。
xml配置
<bean id="userDao" class="spring.dao.impl.UserDaoImpl"
scope="singleton" init-method="save" destroy-method="delete"></bean>
UserDaoImpl类
package spring.dao.impl;
import spring.dao.UserDao;
public class UserDaoImpl implements UserDao{
@Override
public void save() {
System.out.println("UserDaoImpl中的save方法执行了......");
}@Override
public void update() {
System.out.println("UserDaoImpl中的update方法执行了......");
}@Override
public void delete() {
System.out.println("UserDaoImpl中的delete方法执行了......");
}@Override
public void find() {
System.out.println("UserDaoImpl中的find方法执行了......");
}}
测试
@Test
public void test01(){//申明工厂类,加载配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");//通过ID值获取实体类
UserDao bean = (UserDao) applicationContext.getBean("userDao");//执行update方法
bean.update();
}
结果
UserDaoImpl中的save方法执行了......
UserDaoImpl中的update方法执行了......
因为,我在配置文件中设置了初始化方法init-method,所以先执行save方法。至于为什么没有执行destroy-method是因为我没有关闭
public void test01(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao bean = (UserDao) applicationContext.getBean("userDao");
bean.update();
applicationContext.close();
}
这样就会执行destroy-method方法。
(2)使用注解方式
使用注解进行控制反转,首先需要在applicationContext中开启包扫描。意思是加载配置文件的时候后,让Spring去扫描含有注解的类
xml的配置
<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:component-scan base-package="spring.dao"/>
</beans>
对于xml的配置,首先使用包扫描,需要引入context约束
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
开启包扫描
<context:component-scan base-package="spring.dao"/>
这样就可以对spring.dao下的所有类进行扫描
设置Repository表示Dao层的注解
Service表示业务层的注解
Controller表示控制层的注解
Scope表示作用范围
@Repository("userDao")
@Scope("prototype")
public class UserDaoImpl implements UserDao{@Override
public void save() {
System.out.println("UserDaoImpl中的save方法执行了......");
}@Override
public void update() {
System.out.println("UserDaoImpl中的update方法执行了......");
}@Override
public void delete() {
System.out.println("UserDaoImpl中的delete方法执行了......");
}@Override
public void find() {
System.out.println("UserDaoImpl中的find方法执行了......");
}}
测试
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext2.xml");
UserDao bean = (UserDao) applicationContext.getBean("userDao");
bean.update();
System.out.println(bean);
System.out.println("==============================");
ApplicationContext applicationContext2 = new ClassPathXmlApplicationContext("applicationContext2.xml");
UserDao bean2 = (UserDao) applicationContext.getBean("userDao");
bean2.update();
System.out.println(bean2);
结果
UserDaoImpl中的update方法执行了......
spring.dao.impl.UserDaoImpl@4034c28c
==============================
UserDaoImpl中的update方法执行了......
spring.dao.impl.UserDaoImpl@5e4c8041
从结果中可以看出bean是不等于bean2的,因为我设置的是多例模式。
关于属性注入的部分将在下面慢慢讲述