Spring高级程序设计 3 spring 控制反转(笔记)

本文详细阐述了Spring框架中控制反转(IoC)与依赖注入(DI)的概念,包括它们的核心原理、类型及其在Spring中的实现。文章还介绍了依赖查找的两种类型:依赖拖拽和上下文依赖查找(CDL),以及构造方法依赖注入和设置方法依赖注入的区别。此外,文章对比了基于Spring的依赖注入与XML Bean Factory的不同,讨论了bean实例化的模式(如单例和原型)以及如何合理选择实例化模式。最后,文章提供了关于依赖解析、自动装配、依赖检查和bean继承的相关信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring高级程序设计
第3章 控制反转

1、控制反转和依赖注入
2、控制反转类型
3、Spring中的控制反转
4、基于Spring的依赖注入



1控制反转和依赖注入
控制反转(IoC)。依赖注入(DI)。
实际上依赖注入是控制反转的一种特殊形式。

控制反转和依赖注入的核心目标是提供一个更为简单的机制去规定和组件之间的依赖关系(他通常被称作为对象的协助者),并在他们的生命周期中管理这些依赖。
一个需要某些特定依赖的组件通常被称为依赖对象或者目标。控制反转提供的服务使一个组件能够在他的生命周期中访问他的依赖和服务,使用这个这种方法与他的依赖进行交互,这是一件非常美妙的事情。
大体来说,控制反转可以分为两个子类型:依赖注入和依赖查找。这些字类型又能划分成控制反转服务的若干具体实现。以此定义我们可以清楚的知道,当我们谈论依赖注入时我们总是在谈论控制反转,反之则不然。




2控制反转类型


依赖查找有两种类型:依赖拖拽和上下文依赖查找(CDL)。
依赖注入两种类型:构造方法依赖注入和设置方法依赖注入。

依赖拖拽示例:
  1. /**
  2. * 控制反转--依赖查找--依赖拖拽
  3. * @author partner4java
  4. *
  5. */
  6. publicclassDependencyPullDemo {
  7. publicstaticvoidmain(String[] args) {
  8. BeanFactory beanFactory = getBeanFactory();
  9. MessageService messageService = (MessageService) beanFactory.getBean("service");
  10. messageService.execute();
  11. }
  12. privatestaticBeanFactory getBeanFactory(){
  13. DefaultListableBeanFactory beanFactory =newDefaultListableBeanFactory();
  14. BeanDefinitionReader reader =newPropertiesBeanDefinitionReader(beanFactory);
  15. reader.loadBeanDefinitions(newClassPathResource("/META-INF/spring/ioc-pull-context.properties"));
  16. returnbeanFactory;
  17. }
  18. }

上下文依赖查找(CDL):
在某些方面跟依赖拖拽相似,但是上下文依赖查找中,查找的过程是在容器管理的资源中进行的,而不是从集中注册表中,并且通常是作用在某些设置点上。
  1. /**
  2. * 控制反转--依赖查找--上下文依赖查找(CDL)
  3. * @author partner4java
  4. *
  5. */
  6. publicclassContextualizedDependencyLookupDemo {
  7. privatestaticSet<ManagedComponent> components =newHashSet<ManagedComponent>();
  8. privatestaticclassMessageServiceComponentimplementsManagedComponent {
  9. privateMessageService messageService;
  10. publicvoidlookup(BeanFactory beanFactory) {
  11. this.messageService = (MessageService) beanFactory.getBean("service");
  12. }
  13. publicvoidrun(){
  14. this.messageService.execute();
  15. }
  16. }
  17. publicstaticvoidmain(String[] args) {
  18. BeanFactory beanFactory = getBeanFactory();
  19. MessageServiceComponent messageServiceComponent =newMessageServiceComponent();
  20. registerCompontent(messageServiceComponent);
  21. allowComponentsToLookup(beanFactory);
  22. messageServiceComponent.run();
  23. }
  24. privatestaticvoidallowComponentsToLookup(BeanFactory beanFactory){
  25. for(ManagedComponent component:components){
  26. component.lookup(beanFactory);
  27. }
  28. }
  29. privatestaticvoidregisterCompontent(ManagedComponent managedComponent){
  30. components.add(managedComponent);
  31. }
  32. privatestaticBeanFactory getBeanFactory(){
  33. DefaultListableBeanFactory beanFactory =newDefaultListableBeanFactory();
  34. BeanDefinitionReader reader =newPropertiesBeanDefinitionReader(beanFactory);
  35. reader.loadBeanDefinitions(newClassPathResource("/META-INF/spring/ioc-pull-context.properties"));
  36. returnbeanFactory;
  37. }
  38. }


构造方法依赖注入:
在构造方法依赖注入中,组件的依赖从他们的构造方法中提供。组件声明一个或一组构造方法,将他们的依赖作为参数,控制反转容器就会降依赖在组件实例化时传给他。

设置方法依赖注入:
在设置方法依赖注入中,控制反转容器通过JavaBean风格的设置方法为组件注入依赖。一个组件的设置方法向反转容器公开一组依赖。





4基于Spring的依赖注入

XmlBeanFactoryDemo:

XmlBeanFactory源于DefaultListableBeanFactory且简单的扩展了他,利用XmlBeanDefinitionReader进行自动配置。
  1. publicclassXmlBeanFactoryDemo {
  2. publicstaticvoidmain(String[] args) {
  3. XmlBeanFactory bf =newXmlBeanFactory(newClassPathResource("/META-INF/spring/beanfactorydemo2-context.xml"));
  4. Oracle oracle = (Oracle) bf.getBean("oracle");
  5. System.out.println("Meaning of life is "+ oracle.defineMeaningOfLife());
  6. }
  7. }

对比:
  1. DefaultListableBeanFactory bf =newDefaultListableBeanFactory();
  2. BeanDefinitionReader reader =newPropertiesBeanDefinitionReader(bf);
  3. reader.loadBeanDefinitions(newClassPathResource("/META-INF/spring/helloworld-context.properties"));





bean的实例化模式:
默认情况下,Spring中所有的bean均为单例。也就是Spring只维护一个单独的bean实例,所有的依赖对象都是用同一个实例,并且所有对BeanFactory.getBean(XXX)方法的调用都返回相同的实例。

配置文件:
  1. <?xml version="1.0"encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd">
  7. <bean id="messageCon1"class="cn.partner4java.singleton.MessageCon1"></bean>
  8. <bean id="messageCon2"class="cn.partner4java.singleton.MessageCon2"></bean>
  9. </beans>

测试:
  1. publicclassMessageCon1 {
  2. privateString message ="box";
  3. publicvoidsysMessage(String message){
  4. if(message !=null){
  5. this.message = message;
  6. }
  7. System.out.println(this.message);
  8. }
  9. }
  10. /**
  11. * 证明了单例,返回的是同一个对象,就是同一个内存指针,一个改变了公共变量,另一个就会获取到
  12. */
  13. publicstaticvoidtestMessageCon1(){
  14. BeanFactory beanFactory = getBeanFactory();
  15. MessageCon1 messageCon11 = (MessageCon1) beanFactory.getBean("messageCon1");
  16. messageCon11.sysMessage("hello world");
  17. MessageCon1 messageCon12 = (MessageCon1) beanFactory.getBean("messageCon1");
  18. messageCon12.sysMessage(null);
  19. if(messageCon11 == messageCon12){
  20. System.out.println("相等");
  21. }else{
  22. System.out.println("不相等");
  23. }
  24. //后台打印:
  25. //hello world
  26. //hello world
  27. //相等
  28. }

总结:所以,是不是发现了很严重的问题,交给spring的bean只要是默认的sington模式都不要有全局变量。


非单例实例化模式:
prototype:每次调用getBean()方法都返回一个bean的新实例。
request:每次在Web应用中调用getBean()方法将为每一个Http请求返回bean的唯一实例。此行为只在WebApplicationContext和他的子接口中实现。
session:每次调用getBean()方法将为每个Http Session返回bean的唯一实例。跟request一样,此作用范围只在WebApplicatoinContext和他的子接口中有效。
global session:每次在portlet上下文中调用getBean()方法将为全局Http Session返回bean的唯一实例。跟request和session一样,此实例化方式只被WebApplicationContext和他的子接口所支持。


prototype测试:
  1. publicclassMessageCon3 {
  2. privatestaticString message ="box";
  3. publicvoidsysMessage(String message){
  4. if(message !=null){
  5. this.message = message;
  6. }
  7. System.out.println(this.message);
  8. }
  9. }
  1. <?xml version="1.0"encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd">
  7. <bean id="messageCon1"class="cn.partner4java.singleton.MessageCon1"scope="prototype"></bean>
  8. <bean id="messageCon3"class="cn.partner4java.singleton.MessageCon3"scope="prototype"></bean>
  9. </beans>
  1. publicstaticvoidtestMessageCon1(){
  2. BeanFactory beanFactory = getBeanFactory();
  3. MessageCon1 messageCon11 = (MessageCon1) beanFactory.getBean("messageCon1");
  4. messageCon11.sysMessage("hello world");
  5. MessageCon1 messageCon12 = (MessageCon1) beanFactory.getBean("messageCon1");
  6. messageCon12.sysMessage(null);
  7. if(messageCon11 == messageCon12){
  8. System.out.println("相等");
  9. }else{
  10. System.out.println("不相等");
  11. }
  12. //后台打印:
  13. //hello world
  14. //box
  15. //不相等
  16. }
  17. /**
  18. * 即使设置了scope="prototype",static的全局变量也是个麻烦事
  19. */
  20. publicstaticvoidtestMessageCon3(){
  21. BeanFactory beanFactory = getBeanFactory();
  22. MessageCon3 messageCon31 = (MessageCon3) beanFactory.getBean("messageCon3");
  23. messageCon31.sysMessage("hello world");
  24. MessageCon3 messageCon32 = (MessageCon3) beanFactory.getBean("messageCon3");
  25. messageCon32.sysMessage(null);
  26. if(messageCon31 == messageCon32){
  27. System.out.println("相等");
  28. }else{
  29. System.out.println("不相等");
  30. }
  31. //后台打印:
  32. //hello world
  33. //hello world
  34. //不相等
  35. }


选择一种实例化模式:
单例适用:

无状态的共享对象:当有一个无状态且关联很多依赖的对象时,使用单例。如果无状态的差别,你就不需要做同步处理,当某个依赖对象在工作中需要使用这个bean时,你就不需要创建新的实例。
只读状态共享对象:这跟前一点相似,但是有一些只读的状态,比如说一个只读的属性。这种情况下,你仍然不需要做同步处理,因此为每一个请求创建bean的实例只会增加额外的开销而已。
共享状态的共享对象:如果你有一个必须共享状态的bean,单例便是理想选择。这种情况下,你需要确保状态写的同步吹尽量原子化。
具有可读状态的高吞吐量对象:如果某一个bean在你的应用程序中被大量的使用,你可能会发现保持单例并且对bean状态的所有写访问进行同步会比持续的创建上百个bean实例具有更好的性能。使用此方法时,在不牺牲连贯性的前提下尽量保持同步的原子性。当应用程序在一个较大的时间跨度内创建了大量的实例,或者当你的共享对象只有少量可写状态,再或者当创建新实例花销太大时,你会发现这个方法尤其有用。
使用非单例:
具有可写状态的对象:如果你的bean有大量的可写状态,你会发现用以同步的成本比创建新实例来处理依赖对象的每一个请求的成本要高。
具有私有状态的对象:有时,依赖对象需要一个包含私有状态的bean以便他们能够同其他依赖此bean的对象区分开来独立运行。在这样的情况下,单例显然是不合适的。


解析依赖:
  1. <?xml version="1.0"encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd">
  7. <bean id="b"class="com.apress.prospring2.ch03.beandependency.B"depends-on="a"/>
  8. <bean id="a"class="com.apress.prospring2.ch03.beandependency.A"/>
  9. </beans>


bean的自动装配:
  1. <?xml version="1.0"encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd">
  7. <bean id="foo"class="com.apress.prospring2.ch03.autowiring.Foo"/>
  8. <bean id="bar"class="com.apress.prospring2.ch03.autowiring.Bar"/>
  9. <bean id="byName"autowire="byName"class="com.apress.prospring2.ch03.autowiring.Target"/>
  10. <bean id="byType"autowire="byType"class="com.apress.prospring2.ch03.autowiring.Target"/>
  11. <bean id="constructor"autowire="constructor"class="com.apress.prospring2.ch03.autowiring.Target"/>
  12. <bean id="autodetect"autowire="autodetect"class="com.apress.prospring2.ch03.autowiring.Target"/>
  13. </beans>

或者注解:
@Autowired

(不过,我还是一般会明确的指明依赖哪些具体的bean。)



依赖检查:
Simple方法检查是否所有属性或者内建类型都有值。使用这种方法,Spring不会对其他类型的属性做检查。
objects方法检查所有simple方法没有检查到的属性,比如一个int一个Foo类型,他就会检查这个没有被simple检查到的Foo类型。
all方法也就是执行上面两张检查。
  1. <?xml version="1.0"encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd">
  7. <bean id="target1"class="com.apress.prospring2.ch03.dependencycheck.SimpleBean"
  8. dependency-check="simple">
  9. <property name="someInt"value="1"/>
  10. </bean>
  11. <bean id="target2"class="com.apress.prospring2.ch03.dependencycheck.SimpleBean"
  12. dependency-check="objects">
  13. <property name="nestedSimpleBean"ref="nestedSimpleBean"/>
  14. </bean>
  15. <bean id="target3"class="com.apress.prospring2.ch03.dependencycheck.SimpleBean"
  16. dependency-check="all">
  17. <property name="nestedSimpleBean"ref="nestedSimpleBean"/>
  18. <property name="someInt"value="1"/>
  19. </bean>
  20. <bean id="nestedSimpleBean"class="com.apress.prospring2.ch03.dependencycheck.SimpleBean"/>
  21. </beans>





bean的继承:
  1. <?xml version="1.0"encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd">
  7. <bean id="parent"class="com.apress.prospring2.ch03.inheritance.SimpleBean"abstract="true">
  8. <property name="name"value="Jan Machacek"/>
  9. </bean>
  10. <bean id="bean1"class="com.apress.prospring2.ch03.inheritance.SimpleBean"parent="parent">
  11. <property name="age"value="28"/>
  12. </bean>
  13. <bean id="bean2"class="com.apress.prospring2.ch03.inheritance.SimpleBean"parent="parent"/>
  14. </beans>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值