IOC相关(一)
Ioc(Inversion of Control)控制反转
传统的对象引用是采用“new 对象”的形式,例如,Book book = new Book,每次引用都需要重新创建,耦合性高。控制反转则是由主动创建转换为外部(IOC容器)自动创建,将对象交给外部容器管理,就自动实现了对象的创建,只需要引用即可。这就是控制反转。
这些被创建或者管理的对象就是统称为Bean。
DI(Dependency Injection)依赖注入
在容器中建立bean与bean之间的关系的整个过程,就是依赖注入:
例如:
public class UserService {
private UserDao userDao;
public void addUserService() {
userDao.addUserDao();
System.out.println("UserService add!");
}
// 属性需要set方法才能注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
UserService需要注入userDao属性,就需要先定义他们为Bean,才能建立联系。
<!-- 1,配置bean对象,交给spring容器管理-->
<bean class="com.wlb.Dao.UserDao" id="userDao1"/>
<!-- 2,配置bean属性,依赖注入-->
<bean class="com.wlb.service.UserService" id="userService">
<!-- 属性的注入-->
<property name="userDao" ref="userDao1"/>
</bean>
Bean的基础配置
1,name属性,取别名,可以跟id一样被其他bean引用
2,作用范围,scope属性,默认为单例模式(singleton),可以直接复用bean的类型,避免多次创建浪费,对象的创建可以直接用。多例为(prototype)
适合用单例:表现层对象,业务层对象,数据层对象,工具对象
适合用多例:域对象
例如:
<bean class="com.wlb.service.UserService" id="userService" scope="prototype">
UserService userService = applicationContext.getBean("userService", UserService.class);
UserService userService1 = applicationContext.getBean("userService", UserService.class);
System.out.println(userService);
System.out.println(userService1);
实例化Bean:(传统 Book book = new Book())
1,构造方法:spring创建Bean的时候,默认调用的是对象的无参构造方法,上述都是这种方法构建的。
2,使用静态工厂实例化Bean。(很少使用)
3,实例工厂初始化Bean,(了解)
4,使用FactoryBean()实例化bean。需要掌握。
bean工厂类,创建
public class BeanFactory implements FactoryBean<BookService> {
// 设置返回对象的类型
public BookService getObject() throws Exception {
return new BookServiceImpl();
}
//返回对象的字节码对象
public Class<?> getObjectType() {
return BookService.class;
}
// 默认是单例模式
public boolean isSingleton() {
return true;
}
}
配置文件:
<bean class="com.wlb.factory.BeanFactory" id="beanFactory"/>
默认是单例模式
依赖注入的方式:(就是用方法往类里面传值)
1,普通方法(setter注入)
简单类型:
//创建setter方法
public class UserDao {
private int age;
private String name;
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void addUserDao() {
System.out.println("my name is " + name + "," +age+"岁.");
}
}
配置属性,用value配置简单类型
<bean class="com.wlb.Dao.UserDao" id="userDao">
<property name="age" value="13"/>
<property name="name" value="李四"/>
</bean>
引用类型:(参考上文注入方法)
2,构造器注入
简单类型:
构造方法:
public class UserDao {
private int age;
private String name;
public UserDao(int age, String name) {
this.age = age;
this.name = name;
}
public void addUserDao(){
System.out.println(name+age);
}
}
注入类型:方法有三种
<!-- 方法一:-->
<!-- <constructor-arg name="name" value="zhangsan"/>-->
<!-- <constructor-arg name="age" value="13"/>-->
<!-- 方法二-->
<!-- <constructor-arg index="0" value="13"/>-->
<!-- <constructor-arg index="1" value="wln"/>-->
<!-- 方法三-->
<!-- <constructor-arg type="int" value="3"/>-->
<!-- <constructor-arg type="java.lang.String" value="ss"/>-->
引用类型:
构建构造方法
public class UserDao {
private BookDao bookDao;
public UserDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void addUserDao(){
System.out.println("add UserDao!");
}
public void addBookDao(){
bookDao.addBookDao();
}
}
依赖注入:
<bean class="com.wlb.Dao.UserDao" id="userDao">
<!-- 1,通过构造方法注入类型-->
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
自动装配
<bean class="com.wlb.Dao.UserDao" id="userDao" autowire="byName">
<bean class="com.wlb.Dao.UserDao" id="userDao" autowire="byType">
两者主要区别为byType会主动去寻找setter方法中的setBookDao
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
中的bookDao类型,要求该类型的Bean是唯一的,推荐。
而ByName中,必须保证容器中有这个bean的名字,也就是上面例子中,配置xml中必须有id=“bookDao”的类型,耦合性高,不推荐
一般来说,构造器注入和setter注入的优先级都比自动注入高,且不能有简单类型的自动装配,因为没必要。