为什么会出现ioc
- 我们开发一个Java程序,本质上就是各个Java实例对象之间相互配合,相互协作,彼此依赖,支撑着整个Java程序的良好运行。
- 而在这样的程序中,对象之间的耦合关系是无法避免的,也是必要的,这是协同工作的基础。
- 但是随着应用程序规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系,因此,对于系统的分析和设计,将面临更大的挑战。对象之间耦合度过高的系统,必然会出现牵一发而动全身的情形。
- 为了解决这个问题,ioc控制反转思想应运而生。
IOC思想
- Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
- 传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转,而反转则是由容器来帮忙创建及注入依赖对象;因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转。
- 有了IoC后,对象a依赖对象b时直接找spring要对象b即可,直接使用b即可无需关系b是怎么来的,对象与对象之间是 松散耦合,易于维护。
- 如果没有ioc,对象a依赖对象b时,对象b的创建管理调用全部由a负责,会造成程序复杂 耦合度高,不易于维护。
控制反转IOC与依赖注入DI的区别
- 控制反转是容器来帮忙创建及注入依赖对象。
- 依赖注入是组件之间依赖关系由容器在运行期决定,即由容器动态的将某个依赖关系注入到组件之中。
- 依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。
IOC的底层实现
- IOC利用了工厂设计模式的思想和反射的技术。
- 容器在创建对象时,首先会读配置文件,获取一个类的全路径名,然后根据全路径名利用反射技术创建类的实例对象保存到容器中。
IOC的缺点
- 由于IOC容器生成对象是通过反射方式,在运行效率上有一定的损耗。如果你要追求运行效率的话,就必须对此进行权衡。
- 具体到IOC框架产品(比如:Spring)来讲,需要进行大量的配制工作,比较繁琐,对于一些小的项目而言,客观上也可能加大一些工作成本。
依赖注入的几种方式
- 构造方法方式 将UserDaoJdbc通过constructor-arg标签注入到UserService的某个有参数的构造方法
<!-- 注册userService -->
<bean id="userService" class="com.lyu.spring.service.impl.UserService">
<constructor-arg ref="userDaoJdbc"></constructor-arg>
</bean>
<!-- 注册jdbc实现的dao -->
<bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>
- set方法的方式 spring会将name值的每个单词首字母转换成大写,然后再在前面拼接上"set"构成一个方法名,然后去对应的类中查找该方法,通过反射调用,实现注入。
<!-- 注册userService -->
<bean id="userService" class="com.lyu.spring.service.impl.UserService">
<property name="userDao" ref="userDaoMyBatis"></property>
</bean>
<!-- 注册mybatis实现的dao -->
<bean id="userDaoMyBatis" class="com.lyu.spring.dao.impl.UserDaoMyBatis"></bean>
- 基于注解的方式
@Resource:java的注解,默认以byName的方式去匹配与属性名相同的bean的id,如果没有找到就会以byType的方式查找,如果byType查找到多个的话,使用@Qualifier注解指定某个具体名称的bean。
@Autowired:spring注解,默认是以byType的方式去匹配类型相同的bean
依赖注入相关的注解
- 创建bean实例的注解
@Component 使用在类上用于实例化bean并注入
@Controller 使用在控制层类上用于实例化bean
@Service 使用在业务层类上用于实例化bean
@Repository 使用在数据层类上用于实例化bean - bean属性注入的注解
@Autowired 使用在类成员上用于依赖注入
@Qualifier 结合@Autowired一起使用,用于根据名称依赖注入
@Resource 相当于@Autowired+@Qualifier,根据名称依赖注入
@Value 注入普通属性(string或基本数据类型)
@Scope 标注bean的作用范围
依赖注入示例
@Component(value="customer") //如果不加value,名称默认为类名:customerDaoImpl
public class Customer {
}
@Component(value="customer")
public class Customer {
@Value("${user}")
private String user;
@Value("${password}")
private String password;
}
@Service(value="customerService")
public class CustomerService {
@Autowired //表示自动注入 它会自动查找需要的bean
@Qualifier("customer") //根据bean的id进行注入,如果bean实例唯一,可以省略
private CustomerDao customerDao;
}
@Service(value="customerService")
public class CustomerService {
@Resource(name="customerDao") //按照名称进行装配
private CustomerDao customerDao;
}
除此之外还有一些新注解
- @Configuration 用于指定当前类是spring配置类,当创建容器会从该类加载,用于替代spring的xml配置文件
- @ComponentScan 用于指定初始化容器扫描的包,用于替代xml中组件扫描
- @Bean 使用在方法上,表示该方法返回值存储到spring容器
- @Import 用于导入其他配置类