1. 什么是IoC和DI
IoC:控制反转是个设计原则,自定义的程序可以从通用框架接受控制流
DI:依赖注入,是一个技术实现,一个对象可以提供另一个对象的依赖。比如利用组合关系引入另外的对象,其实就是依赖注入
Spring框架拥有一个IoC容器,负责对象创建,装配,配置,管理整个生命周期,直到完全销毁。IoC容器通过依赖注入,也就是DI管理beans。
2 IoC之自定义程序接受Bean控制流
SpringContext负责bean的依赖注入,主要通过以下三种方式:
- Set方法
- 构造方法
- Autowired(原理下篇文章讲解)
上文提到IoC可以让自定义程序从通用框架接受控制流。下面我们就看看如何在自定义程序中获取bean的控制流。
- 实现InitializingBean接口,其中afterPropertiesSet方法会在BeanFactory对bean属性设置完后回调
- 实现DisposableBean接口,其中destory()方法会在销毁前进行回调
上面两种方式可以实现,但是不建议使用,因为和spring框架的bean实现耦合比较紧
另外一种,通过配置文件属性 init-method 和 destroy-method实现。
在springboot中,也可以利用Annotations实现,@PostConstruct, @PreDestroy Annotations,举例如下:
@PostConstruct
private void init() {
signer = new SvsSign();
try {
signer.initSignCertAndKey(this.getClass().getResource(bigGooseCardRsaPrivateKey).getPath(),
bigGooseCardRsaPrivateKeyPw);
} catch (Exception e) {
e.printStackTrace();
}
}
Bean初始化方法的执行顺序:Constructor-----postConstruct(看名字就是在构造方法之后)--afterPropertiesSet----initMethod(自己定义的方法,肯定最后)
InitSequenceBean: constructor
InitSequenceBean: postConstruct
InitSequenceBean: afterPropertiesSet
InitSequenceBean: init-method
3 Aware接口
Spring
的依赖注入的最大亮点就是你所有的Bean
对Spring
容器的存在是没有意识的。即你可以将你的容器替换成别的容器,例如Goggle Guice
,这时Bean
之间的耦合度很低。
但是在实际的项目中,我们不可避免的要用到Spring
容器本身的功能资源,这时候Bean
必须要意识到Spring
容器的存在,才能调用Spring
所提供的资源,这就是所谓的Spring
Aware
。其实Spring
Aware
本来就是Spring
设计用来框架内部使用的,若使用了Spring
Aware
,你的Bean
将会和Spring
框架耦合
举例子如下:
package com.puhui.goosecard.web.utils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class AwareService implements BeanNameAware, ResourceLoaderAware {//①
private String beanName;
private ResourceLoader loader;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {//②
this.loader = resourceLoader;
}
@Override
public void setBeanName(String name) {//③
this.beanName = name;
}
public void outputResult() {
System.out.println("Bean的名称为:" + beanName);
Resource resource =
loader.getResource("classpath:org/light4j/sping4/senior/aware/test.txt");
try {
System.out.println("ResourceLoader加载的文件内容为: " + IOUtils.toString(resource.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出结果如下:
4 总结
- Spring框架中的bean对于IoC容器是无感知的,你定义的bean甚至可以更换IoC容器,比如google的guice。
- 如果需要bean感知spring的IoC容器,那么就需要实现Aware接口