spring Ioc和DI相关

一,容器相关spring

Ioc(控制反转)的核心是DI(依赖注入),为了提供一种简单的方式设置组件依赖项(对象协做者),并在整个生命周期中管理这些依赖项。缓存

概念:mybatis

1.依赖对象:须要弄些依赖对象的组件,或者叫目标对象。app

控制反转的类型:函数

1.依赖注入:优先使用spa

(1)构造函数注入:在构造函数中设置须要的依赖项,也就是带参数的构造函数。若是没有依赖项没法建立对象。prototype

注意一下如何选择构造函数就能够,好比能够指定参数类型。线程

(2)setter依赖注入:提供专门的setter方法设置依赖项。能够在没有依赖项的时候建立对象,而后经过setter方法设置依赖项。代理

@Autowired能够注释在方法(包括构造函数)上,容器会自动给参数设置依赖,根据参数名称。xml

(3)字段注入

@Autowried

private Inspiration inspirationBean;  最经常使用方式。

@value注解能够给方法参数设置初始值。

(4)查找方法注入

动态获取依赖项,能够解决单例引用非单例的状况。使用CGLIB动态代理实现。

原理:核心是使用<lookup-method>或者@Lookup,以注解方法为例。首先使用@Scope("prototype")改变依赖项的做用域为非单例,而后在目标bean中设置一个返回空的方法,并使用@Lookup注释

这样在调用这个方法的时候spring就会动态的去获取依赖项。注意容器中的bean默认都是单例模式。

(5)方法替换

动态的替换bean上的任意方法,而无需改变源代码。使用CGLIB动态代理实现。

原理:核心是使用<replaced-method name='被替换方法名称' replacer='替换bean'>,其中replacer是实现了MethodReplacer接口的类,并注册为bean。

相关说明:

   a.若是组件建立以前必须其余组件先建立就使用构造函数注入,其余的通常使用setter注入。

   b.注意组件和配置的区别,接口中通常会这种不少配置方法,而不会提供依赖项。

public interface NewsletterSender(){

      void setSmtpServer(String smtpServer);

      String getSmtpServer();

      void setFromAddress(String fromAddress);

      String getFromAddress();

      void send();

}

上面接口前四个都是配置方法,为最后一个方法提供配置,通常放到接口中能够定义出改接口的业务逻辑。可是,不要把特定的组件放到接口中,放到子类中进行声明设置。

组件和配置的区别:

(1)配置参数是被动的,通常是由其余函数调用。

(2)配置参数一般是信息,而不是组件

(3)配置参数一般是简单值或者简单值的集合。

c.setter注入能够在不建立父组件的状况下修改依赖项

2.依赖查找:

(1)依赖拉取:从JNDI注册表中拉取Bean,容器中的bean都在某个注册表中注册,获取依赖项的时候从注册表中查找。

(2)上下文依赖查找:直接从容器中获取,而不是从注册表中。组件都实现特定接口,该接口有一个特定方法能够获取到当前组件。

二:spring中的应用

1.依赖注入的核心BeanFactory接口,bean是组件。BeadFacotry管理bean的整个生命周期。

2.应用程序必须建立一个实现了BeanFactory接口的实例(经常使用的是ApplicationContext,须要实现BeanDefinitionReader接口,才能从配置中获取bean配置信息),并使用bean和依赖信息进行配置(bean配置由实现了BeanDefinition接口的实例表示,bean配置不只存储bean自己信息还有它依赖的bean的信息,一般配置信息放到外部,好比xml或者property中分别对应不一样的类进行加载)。

示例:

(1)

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();//建立beanfactory

XmlBeanDefinitionReadder rdr = XmlBeanDefinitionReader(factory);//建立bean配置加载类

rdr.loanBeanDefinitions(new ClassPathResource('spring/xml-bean-factory-config.xml'));//加载bean配置。

 (2)GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();

ctx.load('spring/xml-bean-factory-config.xml');//跟上面相比省掉了第二步。

3.使用Java配置

当应用第三方库,好比mybatis,的时候一般须要建立不少固定的bean,通常这些都不会在改变,这种状况可使用Java配置。

配置类使用@Configuration注解,并包含@Bean注解的方法,这些方法由Spring Ioc 容器直接调用来实例化bean。bean名称与用于建立它的方法的名称相同

获取配置类中的bean须要使用

ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);

获取bean配置还有其余方式:@ComponentScan(basePackages={"com.apress.prospring5.ch3.annotation"})  @ImportResource(locations = {"classpath:spring/app-context-xml.xml"});

4.经过使用SpEL,Spring能够访问任何Spring管理的bean和属性

@Value("#{bean.property}")
5.ApplicationContext能够嵌套,也就是能够声明多个容器,并设置父子关系。并能相互使用对方容器中的bean。

6.@Autowired 若是设置的是一个集合类型对象,Spring会尝试将当前ApplicationContext中全部该类型的对象都注入进来,可能会致使意外的依赖项被注入。而若是没有改类型的bean,会抛出异常。

正确方式:

(1)@Resource(name="map")

(2)@Autowired

       @Qualifier("map")

上面的两种方式能够明确注入的bean名称,避免注入其余的依赖项。

7. bean做用域

(1)单例做用域

(2)原型做用域

(3)请求做用域:针对每一个HTTP请求实例化一个bean

(4)会话做用域:针对每一个HTTP会话(可能有多个请求)实例化一个bean

(5)全局会话做用域:应用程序的全部Portlet之间共享。

(6)线程做用域:每一个线程实例化一个bean

(7)自定义做用域:实现org.springframwork.beans.factory.config.Scope接口

 8.bean依赖顺序设置

若是在配置中没有体现一个bean使用其余的bean,而是在代码中须要调用,那么spring会没法感知到,从而有可能形成bean没法被调用。针对这个使用注解@DependsOn("bean名称");

9.自动装配模式

(1)byName模式:根据名称进行注入

(2)byType模式:根据类型进行注入

(3)构造函数模式:跟byType功能上相同,都是根据类型,只是使用构造函数而不是setter来执行注入。并且匹配的是参数最多的构造函数。

(4)默认模式:自动在构造函数和byType模式之间选择。

说明:

(1)自动装配必须保证bean是惟一的,不然会报org.springframework.beans.factory.NoSuchBeanDefinitionException异常。

(2)若是确实有多个相同的类型bean的时候,可使用@Qualifier("bean名称")来指定具体的bean。一般这个注解跟在@Autowired后面。

  

核心问题:

1.如何解决循环依赖。

bean建立过程:

(1)createBeanInstance:实例化,其实也就是调用对象的 构造方法实例化对象
(2)populateBean:填充属性,这一步主要是多bean的依赖属性进行填充
(3)initializeBean:调用spring xml中的init 方法。
三级缓存: 
singletonFactories : 单例对象工厂的cache 
earlySingletonObjects :提早暴光的单例对象的Cache 
singletonObjects:单例对象的cache
 
原理:缓存的使用是从下到上一次查找,若是在singletonObjects中找不到(说明尚未建立),而后就去earlySingletonObjects中去查找,若是仍是找不到就到singletonFactories中查找(这个缓存存放的是createBeanInstance建立出来的对象,其中属性为空和init方法未调用,能够理解为一个空壳,可是bean已经有了,而且能够区分出来),这里面必定会获取到,而后从这个缓存中删除,放到earlySingletonObjects中去。
 
注意:spring只能解决属性循环依赖,没法解决构造函数循环依赖
相关文章
相关标签/搜索