1. What
IOC (Inversion Of Control,控制反转)与DI(Dependency Injecion,依赖注入)
用于对象间解耦,如在以前若对象A依赖B则需要在A中负责B的创建初始化等工作,现在有了IOC容器(如Spring的)专门负责对象的创建等生命周期的管理,A中只要声明一个B对象就可使用而不再需要负责初始化B(@Autowired等)。“反转”体现在A获得依赖对象B的过程由之前的主动行为变成了被动行为,即获得依赖对象的过程“反转了”。
IOC主要通过DI(Dependency Injection,依赖注入)实现,而DI在实现上主要是通过反射完成的,通过反射动态创建对象。
依赖注入的方式:
构造器注入
setter注入
注解注入:@Autowired、@Resource等用于引用对象的注入,@Value用于基本类型的的注入
循环依赖问题可以通过setter延迟注入解决:循环依赖使得实例化Bean时因对彼此的依赖满足不了,从而实例化失败;通过延迟注入使得注入时Bean已经创建了,从而可注入成功。
IOC与DI的区别:
IOC表示对象的创建等生命周期由特定容器如Spring容器管理。"instantiating objects (beans)"
DI表示对象所依赖的其他“合作者”(其他对象)由容器负责注入到当前对象中。可能是创建对象时注入,也可能是用到依赖的对象时注入。"wiring up of collaborators (or dependencies)"
2. Spring IOC过程分析
三部分组成:
类定义:定义普通的POJO。
元数据定义:关于所要创建的Bean的一些元数据信息。定义方式有三种:xml、java注解、java代码。
创建和关联Bean:Spring容器将根据元数据信息及POJO创建出一系列Bean,并进行管理。
主要过程:
定位Bean元数据:可在classpath、filesystem、network等位置;Bean可通过XML(beans、bean元素等)、注解(Congifuration、Bean注解等)、Java代码三种方式定
加载Bean元数据:读入后创建成BeanDefinition
注册:根据BeanDefinition创建Bean对象并注册到IOC容器(即ApplicationContext)。注意并不是一定都立马创建实例,未被用到的会延迟到等被使用时再创建。
依赖注入:对Bean中依赖其他Bean实例的属性赋值(AbstractAutoWireCapableBeanFactory.populateBean)
Spring IOC容器、Context、BeanFactory可以理解为同一个东西:Context和BeanFactory为对容器概念的实现,只不过前者为读容器内容,而后者可以读写容器内容。
BeanFactory体系:
Bean体系:Spring中Bean对象用BeanDefinition描述
BeanDefinition包含如下信息:
-
-
A package-qualified class name: typically, the actual implementation class of the bean being defined.
-
Bean behavioral configuration elements, which state how the bean should behave in the container (scope, lifecycle callbacks, and so forth).
-
References to other beans that are needed for the bean to do its work. These references are also called collaborators or dependencies.
-
Other configuration settings to set in the newly created object — for example, the size limit of the pool or the number of connections to use in a bean that manages a connection pool.
-
BeanDefinition解析器:
IOC容器体系:
3. Spring Core(IOC Container)doc阅记
官方文档链接:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html
目录:
3.1 Customizing the Nature of a Bean
顺序:
bean Instantiate
BeanPostProcessor.postProcessBeforeInitialization
bean Initialize
BeanPostProcessor.postProcessBeforeInitialization
@PostConstruct
InitializingBean.afterPropertiesSet
@Bean[initMethod]
bean destroy
@PreDestroy
DisposableBean.destroy
@Bean[destroyMethod]
3.1.1 LifeCycle Callback - Bean initialization/destroy callback
定义某个Bean创建完和销毁前的操作,三种方式:
在Bean内通过注解指定方法:@PostConstruct、@PreDestroy
Bean实现特定接口:InitializingBean.afterPropertiesSet、DisposableBean.destroy
通过@Bean属性指定方法:initMethod、destroyMethod
The Spring container guarantees that a configured initialization callback is called immediately after a bean is supplied with all dependencies. Thus, the initialization callback is called on the raw bean reference, which means that AOP interceptors and so forth are not yet applied to the bean. A target bean is fully created first and then an AOP proxy (for example) with its interceptor chain is applied.
示例:
1 @Configuration 2 class CustomBeanLifecycle { 3 4 @Bean(initMethod = "myInit", destroyMethod = "myDestroy") 5 public AdminModel getAdminModel() { 6 return new AdminModel(); 7 } 8 9 // The Spring container guarantees that a configured initialization callback is 10 // called immediately after a bean is supplied with all dependencies. Thus, the 11 // initialization callback is called on the raw bean reference, which means that 12 // AOP interceptors and so forth are not yet applied to the bean. 13 public static class AdminModel implements InitializingBean, DisposableBean { 14 // 15 public void myInit() { 16 System.err.println(this + " @Bean[initMethod]"); 17 } 18 19 public void myDestroy() { 20 System.err.println(this + " @Bean[destroyMethod]"); 21 } 22 23 // 24 @Override 25 public void afterPropertiesSet() throws Exception { 26 System.err.println(this + " InitializingBean.afterPropertiesSet"); 27 } 28 29 @Override 30 public void destroy() throws Exception { 31 System.err.println(this + " DisposableBean.destroy"); 32 } 33 34 // 35 @PostConstruct 36 public void p1() { 37 System.err.println(this + " PostConstruct1"); 38 } 39 40 @PostConstruct 41 public void p2() { 42 System.err.println(this + " PostConstruct2"); 43 } 44 45 @PreDestroy 46 public void d1() { 47 System.err.println(this + " @PreDestroy1"); 48 } 49 50 @PreDestroy 51 public void d2() { 52 System.err.println(this + " @PreDestroy2"); 53 } 54 } 55 } 56 57 58 59 //启动时输出: 60 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe PostConstruct1 61 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe PostConstruct2 62 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe InitializingBean.afterPropertiesSet 63 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe @Bean[initMethod] 64 65 //kill 9时输出 66 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe @PreDestroy1 67 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe @PreDestroy2 68 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe DisposableBean.destroy 69 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe @Bean[destroyMethod]
当三种方式都存在时,为按上述所列三种方式的优先级;优先级高的initaialization callback、destroy callback先执行。如上述示例创建和销毁时的输出分别如下:
//启动时输出: com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe PostConstruct1 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe PostConstruct2 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe InitializingBean.afterPropertiesSet com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe @Bean[initMethod] //kill 9时输出 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe @PreDestroy1 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe @PreDestroy2 com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe DisposableBean.destroy com.marchon.learn.store.config.CustomBeanLifecycle$AdminModel@264f18fe @Bean[destroyMethod]
当三种方式指定的initaialization callback方法名有重时,重名方法只会执行一次;destroy callback同理。
3.1.2 LifeCycle Callback - ApplicationContext start/shutdown callback
详情参阅该文档。
3.1.3 LifeCycle Callback - BeanPostProcessor callback
用于指定在Bean initialization前后做的动作(已经instantiate但尚未initailize),可见其比前面介绍的callback更早被调用。
对所有Bean都有效,即在每个Bean实例化前后都会调用BeanPostProcessor中指定的方法;
scope为per-container(即application);
可以有多个BeanPostProcessor,可以给其指定优先级,将按优先级调用;
The
BeanPostProcessor
interface defines callback methods that you can implement to provide your own (or override the container’s default) instantiation logic, dependency resolution logic, and so forth.The post-processor gets a callback from the container both before container initialization methods (such as
InitializingBean.afterPropertiesSet()
or any declaredinit
method) are called, and after any bean initialization callbacks.
示例:
@Bean public MyBeanPostProcessor getMyBeanPostProcessor() { return new MyBeanPostProcessor(); } // The BeanPostProcessor interface defines callback methods that you can // implement to provide your own (or override the container’s default) // instantiation logic, dependency resolution logic, and so forth. // public static class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {//在每个Bean Initialization前将执行此方法 System.err.println(beanName + " BeanPostProcessor.postProcessBeforeInitialization"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {//在每个Bean Initialization后将执行此方法 System.err.println(beanName + " BeanPostProcessor.postProcessAfterInitialization"); return bean; } }
应用:可借此来扩展或修改Spring容器的功能,如:
BeanValidationPostProcessor、MethodValidationPostProcessor等对Bean做验证。
@Autowired、@Value、@Resource、@Inject等注解就是由BeanPostProcessor的实现类AutowiredAnnotationBeanPostProcessor处理的。故若自定义了BeanFactory并覆盖默认实现,则这些注解可能就不生效了。CommonAnnotationBeanPostProcessor类似。
3.1.4 LifeCycle Callback - BeanFactoryPostProcessor callback
BeanFactoryPostProcessor与BeanPostProcessor类似,区别:
BeanPostProcessor是在Bean instantiate之后在接下来的initialize前后执行
BeanFactoryPostProcessor是在Bean instantiate前后执行,此时任何Bean都尚未instantiate。
可见BeanFactoryPostProcessor比BeanPostProcessor更早被调用。此外,BeanFactoryPostProcessor中的方法只会被执行一次(在所有Bean instantiate之前)。
作用:
用于修改Bean Definition(此时所有Bean Definition都已load到BeanFactory,但都未创建出Bean)。典型应用是Spring中配置文件的解析,如PropertySourcesPlaceholderConfigurer、PropertyResourceConfigurer、PropertyOverrideConfigurer
BeanFactoryPostProcessor
operates on the bean configuration metadata. That is, the Spring IoC container lets aBeanFactoryPostProcessor
read the configuration metadata and potentially change it before the container instantiates any beans
用于往容器添加Bean(手动注册Bean),示例:
法1:通过BeanFactoryPostProcessor手动添加Bean
public static class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { beanFactory.registerSingleton("myTestObj", new Object());//手动注册手动创建的对象到Spring容器,作为一个Bean。其他地方可以@Autowired取该Bean System.err.println(this + " BeanFactory PostProcessor beanFactory is " + beanFactory); } }
法2:直接通过通过ApplicationContext注入
ApplicationContext ctx = SpringApplication.run(new Class<?>[] { StoreMain.class }, args); System.err.println(ctx);// org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext String customBeanName = "myBeanA"; ((DefaultListableBeanFactory) ((ConfigurableApplicationContext) ctx).getBeanFactory()).registerBeanDefinition( customBeanName, BeanDefinitionBuilder.genericBeanDefinition(Object.class).getRawBeanDefinition());// 通过Application获取BeanFactory从而注入Bean System.err.println(ctx.getBean(customBeanName));// java.lang.Object@1e14ed59,读取到的注入的Bean
3.2 Aware Interfaces
作用:可以理解成一种设计模式,使得Bean能收到容器的通知,从而在Bean内部能够获得自身或外部的某些信息。Bean只要实现Aware接口就能收到对应的通知。
示例:ApplicationContextAware、BeanNameAware、ApplicationContextAware、MessageSourceAware等等。示例:
@Configuration class CustomBeanLifecycle { /** 以下为Aware(通知)模式 demo */ @Bean(name = "studentZhang") public StudentModel getStudetnModel() { return new StudentModel(); } public static class StudentModel implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanClassLoaderAware { @Override public void setBeanName(String name) { System.err.println(this + " beanName is " + name);//输出为 studentZhang } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.err.println(this + " applicationContext is " + applicationContext); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.err.println(this + " beanFactory is " + beanFactory); } @Override public void setBeanClassLoader(ClassLoader classLoader) { System.err.println(this + " classLoader is " + classLoader); } } }
Note again that using these interfaces ties your code to the Spring API and does not follow the Inversion of Control style. As a result, we recommend them for infrastructure beans that require programmatic access to the container.
原理:对于一个Bean,如果是想了某Aware接口,则Spring容器会自动调用Bean实例中该接口的方法,从这角度看实际上相当于注册了个回调函数。
缺点及解决:使用这些接口违反了“IOC”原则——相当于由Bean负责设置依赖的对象。解决:可以不使用这些接口,而是直接通过Autowired等注入,如 @Autoweired private ApplicationContext ctx;
3.3 Annotation-based Container Configuration
@Configuration、@Bean、@Import、@Scope、@Lazy、@DependsOn、@ComponentScan。@ComponentScan用于指定扫描策略如路径等。
@PostConstruct、@PreDestroy
@Autowired、@Value、@Resource、@Primary、@Qualifiers
@Component、@Controller、@RestController、@Service、@Repository等(所谓sterotype annotation),被这些修饰的类会被自动扫描为Bean,可通过@ComponentScan useDefaultFilters=false禁用默认行为
详情可参阅该文档最后一部分:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-annotation
3.4 Java-based Container Configuration
AnnotationConfigApplicationContext、AnnotationConfigWebApplicationContext
4. 参考资料
(推荐阅读官方文档,写得比较全面易懂)
https://blog.csdn.net/ivan820819/article/details/79744797 (什么是IOC/DI)
https://blog.csdn.net/javazejian/article/details/54561302(Spring IOC使用)
https://www.cnblogs.com/ITtangtang/p/3978349.html(Spring IOC源码解读)
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html(Spring IOC官方文档)