是什么?
控制反转,是一种思想,为什么说是反转呢?在以前service调用dao,需要自己new Dao一个对象出来,而反转之后将创建对象的权力交给spring容器,由spring容器来装配和管理对象的创建。
有什么好处?
Bean装配创建对象实例
spring ioc容器将bean对象创建好并传递给使用者的过程叫做bean的装配。Spring由三种创建对象的方式,分别是默认方式,实例工厂,静态工厂,一般常用默认方式
默认方式
配置文件:
<bean id="userService" class="com.monkey1024.service.UserServiceImpl"></bean>
测试类:
@Test
public void newType(){
//读取spring配置文件并创建bean
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
StudentService studentService=(StudentService) context.getBean("studentService");
studentService.study();
}
bean作用域
使用spring ioc容器为我们创建对象的时候,可以设定该对象的作用域,默认是单例的。
singleton: 单态模式。即在一个Spring ioc容器中,使用 singleton 定义的 Bean 是单例的,只有一个实例。默认为单例的。
prototype: 原型模式。即每次使用 getBean 方法获取的同一个bean的实例都是一个新的实例。
request:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例。
session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 实例。
application:在一个web应用中会产生一个bean实例,就相当于在一个ServletContext中只有该bean的实例。
websocket:在一个websocket中会产生一个bean实例。
依赖注入
spring ioc容器初始化好bean的实例对象之后,让bean与bean之间以配置文件组织在一起,而不是以硬编码的方式耦合在一起。spring里面常用的注入方式有两种,setter方法注入,构造方法注入。
setter方法: 当spring 容器创建userService对象时,检测到引用着dao,所以会创建userDao对象,然后通过set方法注入userService中
application.xml配置文件
<bean id="userService" class="com.monkey1024.service.UserServiceImpl">
<property name="userDao" ref="userDaoId"/>
</bean>
<bean id="userDaoId" class="com.monkey1024.dao.UserDaoImpl"/>
serviceImpl:实现类,里面添加UserDao的变量,并创建setter和getter方法:
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Override
public void addUser() {
//以前如果需要使用UserDao对象的时候,需要在这里创建对象
//userDao = new UserDaoImpl();
//使用spring之后,由spring为我们创建对象
userDao.addUser();
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
创建测试方法
@Test
public void testDI() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.addUser();
}
构造方法注入
修改之前的UserServiceImpl,添加构造方法
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Override
public void addUser() {
//以前如果需要使用UserDao对象的时候,需要在这里创建对象
//userDao = new UserDaoImpl();
//使用spring之后,由spring为我们创建对象
userDao.addUser();
}
/**
* 构造注入
* @param userDao
*/
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
}
将applicationContext文件修改如下,如果构造方法有多个参数的话,就配置多个constructor-arg标签,要保证该标签中name的顺序跟构造方法里面参数的顺序一致:
<bean id="userService" class="com.monkey1024.service.impl.UserServiceImpl">
<constructor-arg name="userDao" ref="userDaoId"/>
</bean>
<bean id="userDaoId" class="com.monkey1024.dao.impl.UserDaoImpl"/>
基于注解的依赖注入
随着bean的增多,spring的配置文件肯定会越来越臃肿,因此spring引入了注解。在类上使用注解@Repository、@Service、@Controller 该注解中的内容用来指定该bean的id,使用注解实现依赖注入的话,就不需要在applicationContext.xml中注册bean了,添加一个文件扫描器即可:
<!--文件扫描器-->
<context:component-scan base-package="com.monkey1024"/>
@Service
public class UserServiceImpl implements UserService {
// 据类型进行注入,查找UserDao的对象注入进来
@Autowired
private UserDao userDao;
@Override
public void addUser() {
//以前如果需要使用UserDao对象的时候,需要在这里创建对象
//userDao = new UserDaoImpl();
//使用spring之后,由spring为我们创建对象
userDao.addUser();
}
}
@Test
public void testDI() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.addUser();
}