IoC即控制反转,简单的说就是以前你要使用一个对象,需要在代码中new一个出来,而现在你要使用,IoC容器会帮你new出来。可以这样理解,以前你是独自一个人,想要使用什么都要自己动手获得后再使用,而现在你有了一个保姆,你想要用什么的时候,直接和保姆说一声,它就会帮你准备好。通过IoC能大大降低耦合度。
依赖注入的三种方式:
-
构造器注入:构造器注入即是将依赖的对象作为构造函数的参数。这种注入方式的优点就是,对象在构造完成之后,即已进入就绪状态,可以马上使用。缺点就是,当依赖对象比较多的时候,构造方法的参数列表会比较长。而通过反射构造对象的时候,对相同类型的参数的处理会比较困难,维护和使用上也比较麻烦。
People(PeopleWork pw,PeopleStudy ps){ this.pw=pw; this.ps=ps }
-
Setter注入:对于javabean来说,是通过setXXX和getXXX方法来进行属性的访问的,setter注入和这种差不多。。因为方法可以命名,所以setter方法注入在描述性上要比构造方法注入好一些。另外,setter方法可以被继承,允许设置默认值。
privatePeopleWork pw; private PeopleStudy ps; public void setPeopleWork(PeopleWork pw){ this.pw=pw; } Public void setPeopleStudy(PeopleStudy ps){ this.ps=ps; }
-
接口注入: -。- 很遗憾...貌似没接触过...
IoC Service Provider的职责
IoC Service Provider的职责相对来说比较简单,主要有两个:业务对象的构建管理和业务对象间的依赖绑定。
Spring的IoC容器
Spring提供了两种容器类型:
1、IoC容器——BeanFactory
基础类型IoC容器,提供完整的IoC服务支持。如果没有特殊指定,默认采用延迟初始化策略(lazy-load)。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需要的资源有限。对于资源有限,并且功能要求不是很严格的场景,BeanFactory是比较合适的IoC容器选择。
2、IoC容器——ApplicationContext
ApplicationContext在BeanFactory的基础上构建,是相对比较高级的容器实现,除了拥有BeanFactory的所有支持,ApplicationContext还提供了其他高级特性,比如事件发布、国际化信息支持等。ApplicationContext所管理的对象,在该类型容器启动之后,默认全部初始化并绑定完成。所以,相对于BeanFactory来说,ApplicationContext要求更多的系统资源,同时,因为在启动时就完成所有初始化,容器启动时间较之BeanFactory也会长一些。在那些系统资源充足,并且要求更多功能的场景中,ApplicationContext类型的容器是比较合适的选择。
BeanFactory和Application之间的关系:
IoC Service Provider 如何管理对象间的依赖关系
-
直接编码方式:
-
配置文件方式:
接下来以BeanFactory来讲的对象注册与依赖绑定方式的内容同样适用于ApplicationContext,但是ApplicationContext能用的BeanFactory就不一定了。
-
直接编码方式:实际上不管是什么方式,最终都是到达编码这一个步骤的。这一步骤可以简单的描述为:定义bean->注册bean->注入依赖的bean
Man.java
public class Man{ public void say() { System.out.println("I am a man"); } }
PService.java
public class PService { public PService(Man man) { this.man = man; } private Man man; public Man getMan() { return man; } public void setMan(Man man) { this.man = man; } public void say(){ man.say(); } }
MyTest.java
Import ....省略... public class MyTest { public static void main(String[] args) { DefaultListableBeanFactory beanRegistry=new DefaultListableBeanFactory(); BeanFactory beanfactory=(BeanFactory)bindViaCode(beanRegistry); PService pservice=(PService)beanfactory.getBean("pservice"); pservice.say(); } public static BeanFactory bindViaCode(BeanDefinitionRegistry registry){ AbstractBeanDefinition man=new RootBeanDefinition(Man.class); AbstractBeanDefinition pservice=new RootBeanDefinition(PService.class); //将bean注册到容器中... registry.registerBeanDefinition("man",man); registry.registerBeanDefinition("pservice",pservice); //通过构造器注入 ConstructorArgumentValues argValues=new ConstructorArgumentValues(); argValues.addIndexedArgumentValue(0, man); pservice.setConstructorArgumentValues(argValues); //通过setter方式注入 MutablePropertyValues propertyValues=new MutablePropertyValues(); propertyValues.addPropertyValue(new PropertyValue("man",man)); pservice.setPropertyValues(propertyValues); return (BeanFactory)registry; } }
-
配置文件方式:
配置文件格式包括:Properties文件和XML文件。实际上配置文件的方式也是和编码方式息息相关的,只不过多了些步骤。对于配置文件的方式来说,是通过BeanDefinitionReader接口的实现类(对于Properties文件来说是PropertiesBeanDefinitionReader类,对于XML文件来说是XmlBeanDefinitionReader类)来解析配置文件的信息,然后将解析出来的信息按照编码方式的步骤进行。(不过大家应该都用的是xml吧...至少我是没用过Properties的)
Beans.xml
<bean id="man" class="Man" /> <bean id="pservice" class="PService"> <property name="man" ref="man"/> </bean>
MyTest1.java
public class MyTest1 { public static void main(String[] args) { BeanFactory beanfactory=new XmlBeanFactory(new ClassPathResource("beans.xml")); PService pservice=(PService)beanfactory.getBean("pservice"); pservice.say(); } }
3、注解方式
Man.java
@Component public class Man{ public void say() { System.out.println("I am a man"); } }
PService.java
@Component public class PService { public PService(Man man) { this.man = man; } public PService() { super(); } @Autowired private Man man; public Man getMan() { return man; } public void setMan(Man man) { this.man = man; } public void say(){ man.say(); } }
Beans.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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="org.pig.test"/> </beans>
<context:component-scan/>会到指定的包(package)下面扫描标注有@Component的类,如果
找到,则将它们添加到容器进行管理,并根据它们所标注的@Autowired为这些类注入符合条件的依
赖对象。
Mytest2.java
public class MyTest2 { public static void main(String[] args) { ApplicationContext app=new ClassPathXmlApplicationContext("beans.xml"); PService p=(PService)app.getBean("PService"); p.say(); } }