IoC控制反转机制

以下内容是我边学边写的,可能会有理解不透彻或者错误的情况,但我尽量让初学者能明白,至少能有个基本认知。

IoC全称是Inversion of Control,中文翻译为控制反转,在刚开始接触到spring的时候对这个名词很陌生,在看了一些教程之后开始有了自己初步的理解。

这里有个问题就是控制指的是对什么的控制?我的理解是对java中的class的实例即对象的控制权。在以前写JavaEE时创建对象用new运算符,这个对象是受我们控制的,我们需要决定在哪里创建这个对象等。而在spring里面不需要我们这样做,spring里面将对象称作bean(这句话只是一个表达,不严谨),spring的IoC容器负责对这些bean进行管理,包括什么时候创建,什么时候销毁等,而当我们需要某个对象时只需在容器里面得到该对象,然后使用该对象,其余的我们都不需要管。这样就相当于我们把对对象的控制权转让出去了,这就是反转的含义。

控制反转也叫做依赖注入(DI,dependency injection),这其实是实现控制反转的方法。什么是依赖?当一个对象需要另一个对象一起工作才能完成它的功能时我们就称前者对后者有依赖关系。所谓注入,指的是IoC容器在运行期间动态地将某种依赖关系注入到对象当中,获得依赖对象的过程由自身管理变成了IoC容器主动注入。

同时spring是面向接口的,当用户得到一个对象时其实该对象的类型是接口类型(在多态中我们知道,实际的类型其实是某个实现类),这样对于不关心具体怎么实现而只关心有哪些方法可以使用的用户来说是有好处的,而且也隐藏了实现细节,方便了对代码的维护,这些在JavaSE中接口的作用已经知道了。

org.springframework.context.ApplicationContext就代表了IoC容器,这其实是一个接口,它的实现类有ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext两种。

那么我们是怎样得到某个对象的呢?既然对象是一个bean,那么我们就必须知道这个bean对应的是哪一个类,因此在xml配置文件中一个bean必须要有class属性,形式如下:<bean class="some class"></bean>,当然我们更常用的时再给每个bean添加一个id属性,这样就可以通过这个id得到该bean。在我们需要某一个bean时可以调用org.springframework.context.support.ClassPathXmlApplicationContext这个类的getBean(id)方法。

关于bean的内容有很多,我一点一点写。

1,如何对bean所对应的对象的对象成员进行赋值呢?这在spring中称之为注入,有两种方式,设值注入和构造注入,分别对应的是利用set方法赋值和利用构造函数传参赋值。代码如下:注释部分为构造注入。

<bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">
       		<property name="injectionDAO" ref="injectionDAO"></property>
       </bean>

		<!-- <bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">
        	<constructor-arg name="injectionDAO" ref="injectionDAO"></constructor-arg>
        </bean> -->
        
        <bean id="injectionDAO" class="com.imooc.ioc.injection.dao.InjectionDAOImpl"></bean>

该代码表示在com.imooc.ioc.injection.service.InjectionServiceImpl这个类里面有一个对象成员,名字叫做injectionDAO,它的类型是com.imooc.ioc.injection.dao.InjectionDAOImpl。注意name属性值必须与类中成员变量的名字相同,ref属性值必须与成员变量的bean的id值相同。配置完xml文件后就需要在com.imooc.ioc.injection.service.InjectionServiceImpl这个类里面添加set方法和有参数的构造方法。注意两种注入方式不能同时使用,同时设值注入需要有默认的构造函数。如果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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd" 
        default-autowire="constructor">
        
        <bean id="autoWiringService" class="com.imooc.autowiring.AutoWiringService" ></bean>
        
        <bean class="com.imooc.autowiring.AutoWiringDAO" ></bean>
	
 </beans>
我们发现少了property或者是constructor-arg,而多了default-autowire,这就是使用了自动装配,我们不用再显式地写哪个property或者哪个constructor-arg ref哪个类,若设置default-autowire为byname,则会自动地根据属性的名字和bean id之间的对应查找bean并注入依赖关系, 如果存在多个则报错,找不到就不执行;若为byType,则根据属性的类查找class的值也是这个类的bean并且注入,如果存在多个则报错,找不到就不执行;若为Constructor,其实也是和byType通过类型查找,不过它作用的是构造函数的参数,而不是该类的对象成员。

2,bean的作用域。通过设置scope属性值可以设置作用域。代码如下:

<!-- 默认的scope是singleton -->
        <bean id="beanScope" class="com.imooc.bean.BeanScope" scope="prototype"></bean>
我只了解singleton和prototype两种。singleton即单例,表示在一个IoC容器内只存在一个对象,用两次getBean()方法得到的都是对同一个对象的引用;prototype表示每一次请求都会创建一个新的实例,用两次getBean()方法得到的都是是不同对象的引用。

3,下面我想介绍一下以上两点的另外一种实现方法,注解annotation。在Spring提供注解以前都用的是xml配置文件,而且配置文件中内容很多,使用注解可以大大减少配置文件的内容,且由于注解是直接写在java代码里的,这减少了java和xml的耦合度。不过我个人认为注解较难理解,所以我推荐先学习xml配置的方法,弄懂原理和执行过程之后再使用注解减少代码量。

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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd" >
        
        <context:component-scan base-package="com.imooc.beanannotation"></context:component-scan>
        
 </beans>
表示扫描com.imooc.beanannotation这个包下的类时,遇到有@Component注解或者它的子注解@Repository,@Service,@Controller的类时会自动注册bean,这样就不用我们写<bean></bean>标签了。那么id又该如何确定呢?如果我们在注解后面明确表示比如@Component("some name"),这样id就是括号里面的内容,如果没有明确表示的话,则默认的是将类名的首字母小写,来表示id。

我们可以设置拦截器,自定义扫描规则,而不是在com.imooc.beanannotation下面所有有那些注解的类下都扫描,比如可以指定不扫描@Service注解;也可以自定义id命名策略,不过这些我就不懂了。。。

scope怎么通过注解实现呢?我们可以直接在类上面加上@Scope注解,默认为singleton,@Scope("prototype")可以改变作用域。也可以自定义作用域,我同样也不懂。。。
。。。未完待续


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值