java入门小白,文章内容仅代表个人理解,不保证其正确性。
学习javaWEB到一定阶段开始接触框架,绕不开的当属spring框架,而spring框架的核心之一就是IOC,对于初学者来说这两个概念真的不容易理解,直到现在可能我的有些理解都还有错误,本人刚学习java两个月左右,仅从个人角度出发谈一谈对IOC的理解。文章偏理论,主要讲原理,涉及少量具体实现代码。
spring的核心组件主要有三个:Bean、Context和Core,Bean本人的简单理解就是实体类,与数据库中的数据对应的类,也可以理解为,IOC既然是容器,那么它存放的是什么呢,自然存放的是数据,就是这些类。Context是发现,创建并管理这些类之间关系的容器,即IOC。Core是spring内部发现创建并维护这些类之间关系的工具。
第一部分IOC
首先要记住的是IOC是一个容器,现在不理解没关系,要先在头脑中有一个意识,“IOC是一个容器”,IOC是什么,一搜一大把的答案,IOC就是控制反转,也可以叫做依赖注入,还是觉得很模糊,说了当没说,不要急慢慢继续往下看。1、IOC为什么会出现?它给我们带来了什么?它为我们做了哪些事?
(1)首先回想一下我们在定义类时,如果一个类要使用另一个类中的方法,按照传统方式需要先在一个类中创建另一个的对象,利用对象来调用那个类中的方法,回想一下之前写过的一些java程序代码是不是这样的。这样一来两个类就有了依赖,用专业的话说耦合性加强了,显然这不符合编程的思想。
(2)学习了spring框架之后我们学会了在配置文件中使用<bean>标签来两个有关联的类设置属性,关键术语叫做,属性注入,其实就是利用<bean>标签给类设置属性,大概的代码样式如下:
<bean id="sa" class="com.yc.A" ></bean><!--相当于创建一个A类的实例,使用id值sa就可以使用这个A类的实例,等价于A sa=new A()-->
<bean id="sb" class="com.yc.B">//等价于B sb=new B();创建对象操作
<property name="a" ref="sa"/><!-- 给“类B”的“a属性”设置一个值,属性值是sa(上面那个标签dingyilsa是A的实例)相当于调用类中的setter方法-->
<constructor-arg ref="sa"/><!-- 给类B创建一个构造函数,参数是sa(sa是A的实例) -->
</bean>
这样就在配置文件中利用bean标签实例化了两个类,并建立了两个类之间的联系,那么在测试时怎样获取两个类呢?
public class Test {
public static void main(String[] args) {
BeanFactory bf=new ClassPathXmlApplicationContext("spring-cfg.xml");//加载配置文件,引号内是放有bean标签配置的配置文件名称
B b=(B) bf.getBean("sb");//利用getBean()方法创建一个B的实例,注意此时没有用到传统的创建对象的方法,即B b=new B();
b.getA().a();//通过B的getA()方法获取一个A的实例,getA()方法返回一个A类的实例,注意此时也没有创建A类的实例,调用a()的方法
}
}
这样一来将类的实例化和类之间的依赖关系都放到了配置文件中,降低了类与类之间的耦合性,直接通过配置文件就得到了对象,可能在小项目中看不出这样做的优势,但在大型项目中优势很明显,降低了耦合性,提高了可重用性;缺点是每次都要自己去书写<bean>标签,然后加载配置文件,通过getBean()方法获取对象,非常的麻烦。接着就有了第三种方式的存在,使用注解:
(3)利用注解让spring框架自动去创建<bean>标签,开发人员只需要使用,不需要前面的设置<bean>,加载配置文件,调用getBean()方法等步骤,进一步简化了程序,那么是如何实现的呢?
只需要在要使用的类声明前加上@Autowired注解就可以了,如
@Autowired
private UserService us;//在类的内部设置声明属性
相当于“spring去帮我把当前类和其他类的依赖关系发现,创建并维护一下”,省去了大量的<bean>标签中的属性注入,即< property >设置;
在web开发中绕不开的Controller层和Service层也是使用的注解,注意此时的Controller和Service只是普通类(有时候越学到后面越容易忘记基本的东西),给类加上Controller和Service注解后相当于连<bean>节点都不用在配置文件中写了。
整个项目只需要在spring配置文件中加上支持注解的代码(支持注解的意思是,让spring自动去扫描项目,发现注解,发现有相关注解就自动设置一下<bean>标签,并为其注入属性):
<context:component-scan base-package="com.yc.*">
</context:component-scan> //扫描指定路径下的包,发现注解,并自动为其建立依赖关系;
在类中使用@service和@Controller注解,spring为我们做了两件事,一是新创建一个<bean>节点标签,二是设置<bean>的id是小写的类名。在类中的属性声明上使用@AutoWired注解相当于自动设置了<property>标签和<constructor-arg>标签
而帮我们自动去发现并创建依赖关系的这个容器就叫做IOC,回应前面说到的,IOC只是一个容器。它的出现让类与类之间的耦合性降低了,它帮我们自动建立了类与类之间的依赖关系,开发人员只需要使用,不需要手动去创建对象。
总而言之,spring框架中的IOC就是通过注解的方式简化了配置文件中<bean>节点的设置,而<bean>节点的作用就自动创建类,并给各个类通过属性注入的方式(<property>标签)建立依赖关系。开发人员只需声明和使用,不需手动new对象,而管理这些类的容器就叫做IOC。
这样一来就可以回答开头提出的三个问题,IOC为什么会出现?因为手动在一个类中建立另一个类的实例,类与类之间的耦合性太高,不利于程序的二次利用。
它给我们带来了什么?它给我们带来了程序开发的便利,开发人员不用手动创建类和手动设置类与类之间的依赖关系。
它为我们做了哪些事?在类上使用注解spring自动为我们创建<bean>节点,即创建对象。在类体中的属性前使用注解,spring自动为我们建立了类与类之间的关系,省去了<property>标签和<constructor-arg>标签,即依赖注入(说成依赖关系注入可能会更容易理解——自动建立类与类之间的依赖关系)。
最后一句,IOC就是发现类与类之间的关系,并为它们建立和维护这段关系(注意控制层、业务逻辑层、dao层Model层都是一个个类,他们之间会相互调用相应的方法,他们之间是有依赖关系的)