Spring 核心技术之一 IoC

29 篇文章 1 订阅

什么是IoC

      IoC:(Inversion of Control的缩写),控制反转,本来由应用程序管理的对象之间的依赖关系,现在交给了容器管理,即交给了容器管理

IoC的作用或好处

      以前没用框架时,如在敲机房用三层的时候,如果B层调D层,我们需要手动在B层找到D层的对象,并创建。但用了spring用,我们只需把这些关系配置到配置文件中,程序运行时,容器就自动的去找D层的对象并创建了,我们直接用就可以了。好处:减少了代码中的耦合,将耦合推迟到了配置文件中,发生了变化也更容易控制

IoC是如何实现的

      Spring的Ioc容器主要使用DI(依赖注入)的方式实现的,不需要主动进行对象的查找,定位,和创建,这些全由容器管理(注入的方向:由容器向类中注入)

DI注入的方式

1. 构造方法

      通过使用构造方法将对象注入进来,拿B层和D层举例:

      spring的配置文件如下:

<bean id="userDao4Mysql" class="com.bjpowernode.spring.dao.UserDao4MySqlImpl" />
<bean id="userManager" class="com.bjpowernode.spring.manager.UserManagerImpl">
     <constructor-arg ref="userDao4Mysql" />
</bean>

      B层代码:

private UserDao userDao;    
public UserManagerImpl(UserDao userDao) {
    this.userDao = userDao;
}

      【 注意事项】

  • 这样IoC容器在创建B对象时的同时,也找到D类并创建D对象了(应为B的构造函数的参数是D)
  • 当只有一个构造方法时并且参数类型和注入的bean类型匹配,那就会注入到该构造方法中

2.setter方法

      spring的配置文件如下:

    <bean id="userDao4Mysql" class="com.bjpowernode.spring.dao.UserDao4MySqlImpl" />
    <bean id="userManager" class="com.bjpowernode.spring.manager.UserManagerImpl">
        <property name="userDao" ref="userDao4Mysql" />
    </bean>

      B层代码如下:

private UserDao userDao;
public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
}

      【注意事项】

  • 使用setter时,spring会将name值的每个单词首字母转换为大写,然后再在前面拼接上set构成一个方法名,然后去对应的类中查找该方法,通过反射调用,实现注入,所以<bean>的id属性值至于类中set方法名有关,与声明的属性无关
  • 通过set方法注入属性,spring会通过默认的空参构方法来实例化对象,如果在写中写了一个有参的构造方法,必须要显示的声明一下无参的构造方法,否则spring无法实例化对象
    有关注入的方式,可参考该文章:http://blog.csdn.net/a909301740/article/details/78379720

如何从IoC中取得对象

//通过读取配置文件,取得BeanFactory
BeanFactory factory = new 
ClassPathXmlApplicationContext("applicationContext.xml");
//通过调用BeanFactory的getBean()方法取得对象
UserManager userManager = (UserManager)factory.getBean("userManager");
//直接就可以使用对象了,如调用对象的方法
userManager.方法()


配置文件讲解

1.延迟加载

      spring默认在创建BeanFactory时,将配置文件中所有的对象实例化并进行注入,但可以采用将default-lazy-init设为true,默认是false:

<beans >
    default-lazy-init="true"
</beans>

      这样实例化对象就会被延迟,知道真正使用该对象时,还可以可以针对具体的模块在相应的bean里面使用lazy-init 属性,lazy-init 比default-lazy-init的优先级高
      为什么要延迟加载那,如果你的项目中用到多个spring文件时,启动spring时会加快启动时间,因为不用实例化对象了

2.scope属性的取值

  scope设置从IoC容器取得的对象是否同一个,有两个属性值:

  • singleton:默认值,每次调用getBean()向IoC容器中取得的对象是相同的
  • prototype:每次调用getBean()向IoC容器中取得的对象是不同的
<bean id="bean1" class="com.bjpowernode.spring.Bean" scope="prototype">

多配置文件的读取

      spring支持多配置文件,读取方式有两种:

  • 使用数组方式
String[] configLocations = new String[]{"applicationContext-beans.xml","applicationContext-editor.xml"};
BeanFactory factory= new ClassPathXmlApplicationContext(configLocations);

      这里只有2个,这样写还行,但是当有10个,100个配置文件时也这样写吗,显然不是办法,可以采用下面这种方式

  • 使用*通配符(前提:配置文件命名方式要有规律)
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext-*.xml");

      但这样报错了:INFO [org.springframework.core.CollectionFactory] - JDK 1.4+ collections available
      解决办法:?????

减少spring配置文件

1.abstract属性

      当多个类中有相同属性时(且属性值相同),如何按一般情况,我们在配置文件中配置<bean>时,每个<bean>都有相同的内容,这时我们可以通过<bean>标签将公共的部分提取出来,然后指定<bean>标签的abstract属相为true;然后在其它<bean>标签中指定其parent,如下示例

<bean id="AbstractBean" abstract="true">
    <property name="id" value="100"/>
    <property name="name" value="zhangsan"/>
    <property name="sex" value="nan"/>
</bean>
<bean id="bean3" class="com.bjpowernode.spring.Bean3" parent="AbstractBean"/>
<bean id="bean4" class="com.bjpowernode.spring.Bean4" parent="AbstractBean">
    <property name="age">
        <value>90</value>
    </property>
</bean>


2.自动装配模式

      所谓的装配就是:创建应用对象之间协作关联关系的行为,这也是DI依赖注入的本质。所谓自动装配,就是应用程序自动去协作它们之间的关系,不用再手动的配置,具体表现在:不用再在<property>标签中写<ref>了,spring设置了五种匹配方式:

  1. no:这是Spring框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在bean定义中用标签明确的设置依赖关系
  2. byName:该选项可以根据bean名称设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的名称自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错
  3. byType:该选项可以根据bean类型设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的类型自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错
  4. constructor:造器的自动装配和byType模式类似,但是仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。

  5. autodetect:该模式自动探测使用构造器自动装配或者byType自动装配。首先,首先会尝试找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如果在bean内部没有找到相应的构造器或者是无参构造器,容器就会自动选择byTpe的自动装配方式。
    如果 Bean1中引用Bean2,Bean3,Bean4了,配置中要映射它们之间的关系,配置文件如下的代码,就不要写了:

<bean id="bean1" class="com.bjpowernode.spring.Bean1">
    <property name="bean2" ref="bean2" />
    <property name="bean3" ref="bean3" />
    <property name="bean4" ref="bean4" />
</bean> 

      不过要在<beans>标签中要声明自动装配:

<beans
           default-autowire="装配类型">
<bans>

      下面我主要讲2中,因为其它两种与byType有相同之处:
      byName:寻找和属性名相同的bean,若找不到,则装不上

<beans
           default-autowire="byName">
<bans>

      寻找过程:目标对象中的属性会根据名称(set后面的单词,所以改变属性的值没影响,只要set后面的名字一致即可)在整个Spring环境中查找标签的id属性值,如果有相同的,那么获取到这个对象,实现关联。整个Spring环境:表示所有的spring配置文件中查找,那么id不能有重复的


      byType:寻找和属性类型相同的bean,若找不到,则装不上

<beans
           default-autowire="byType">
<bans>

      寻找过程:从Spring环境中获取目标对象时,目标对象中的属性会根据类型在整个spring环境中查找标签的class属性值。如果有相同的,那么获取这个对象,实现关联。所以<bean>标签完全不用写id属性,因为它是根据类型装配的,真个spring中,必须保证类型单一,否则,spring就不知道到底加载哪个bean了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 24
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值