控制反转IOC(Inversion Of Control),是一种包装技术类型,它本身不属于新的内容,说的再简单一点:所有对象的实例化的处理操作都不再需要关键字new了(反射机制)。
那么为什么现在的代码之中需要编写控制反转的操作呢?为了更好的解释这个问题,下面编写一个实际的程序分析。
如果员工出差,那么员工所需要做的核心处理——办理核心的操作业务,出差的目的,但是发现要想实现这个目的现在有了困难,所有的一切都要求由用户自己来负责处理。
那么这样的操作形式就好比是最早自己手工编写代码的时候必须明确的处理关键字new一样。
范例:传统的代码问题
package org.lks.demo;
interface Fruit{
public void eat();
}
class Apple implements Fruit{
@Override
public void eat() {
System.out.println("eat apple");
}
}
public class TestDemoA {
public static void main(String[] args) {
Fruit fruit = new Apple();
fruit.eat();
}
}
但是现在的问题在于耦合度加深了,因为某一个接口必须要与一个子类产生关联。
如果中间出现了代理公司,那么整个操作的过程之中,员工只需要自己去跟代理公司操作就可以完成所有与出差有关的业务处理,但是前提:用户依然需要关注代理公司的处理过程。
范例:就好比代码之中使用了工厂设计模式
package org.lks.demo;
interface Fruit{
public void eat();
}
class Apple implements Fruit{
@Override
public void eat() {
System.out.println("eat apple");
}
}
class Factory{
public static Fruit getFruit(){
return new Apple();
}
}
public class TestDemoA {
public static void main(String[] args) {
Fruit fruit = Factory.getFruit();
fruit.eat();
}
}
加入工厂设计之后最大的优点在于整个的代码在操作的过程之中只会与工厂类发生耦合,把工厂类想象为代理公司,这个代理公司需要由开发者明确的使用。
现在的“管理部门”就属于整个代码的运行容器,只要在这个容器里面运行的操作都可以得到相应的辅助操作支持。那么这就属于IOC的操作,所有的辅助控制都交由容器完成。
在项目中添加Spring支持,在添加的过程之中会询问是否需要一个核心的处理文件——applicationContext.xml文件。
添加完Spring框架支持后的关键就在于Spring到底该如何处理呢?
范例:定义操作接口
package org.lks.demo;
public interface IFruit {
public void eat();
}
而随后不再提供有工厂的操作类,因为Spring本身就属于一个工厂类。在工作之中就不应该出现工厂类。
范例:修改applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<bean id="apple" class="org.lks.demo.AppleImpl"/>
</beans>
随后下面要通过特定的模式启动Spring容器。
范例:找到Apple类对象
package org.lks.demo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestFruit {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
IFruit fruit = ctx.getBean("apple", AppleImpl.class);
fruit.eat(); //只关心核心的业务操作方法
}
}
整个代码操作过程之中你无法发现工厂设计模式的明确使用,因为所有的工厂都由Spring帮助用户自动处理了,而且在applicationContext.xml文件配置的信息内容,都在Spring容器启动的时候默认的实例化好了所有的对象,用的时候根据id名称取出即可。
而在编写的代码过程之中也使用到了几个类:
1、ApplicationContext类(org.springframework.context.ApplicationContext
,应用上下文类)
(1)所有在applicationContext.xml文件中配置的信息都需要通过此类读取才可以。
(2)常用方法:public <T> T getBean(String name, Class<T> requiredType) throws BeansException
|————取得指定名称的Bean对象,并且设置泛型为指定操作的Bean类型,避免向下转型;
(3)最早的操作:public Object getBean(String name) throws BeansException
,有向下转型,所以不使用。
2、现在由于资源的控制文件可能在任意位置上,例如:CLASSPATH中或者是在文件磁盘中,那么就必须使用相关的子类:org.springframework.context.support.ClassPathXmlApplicationContext
(在CLASSPATH中读取资源文件);
所有在Spring中配置的<bean>
元素都表示在Spring容器启动的时候自动进行初始化,所以在使用这个对象的之前已经准备好供用户操作的实例对象。
如果现在有更严格的配置也可以将接口配置上去(一般没什么用)。
范例:更完善的配置形式
<bean id="fruit" class="org.lks.demo.IFruit" abstract="true"></bean>
<bean id="apple" class="org.lks.demo.AppleImpl" parent="fruit"/>
由于接口是抽象的,那么就表示接口对象不会进行实例化。而在编写apple
元素的时候加上的parent
实际上也只是一个说明而已,本身没有什么意义。