Bean的生命周期
Spring Ioc容器负责管理对象,包含创建、注入、销毁等。
程序员在使用的时候,可以通过相应的方法来获取想要的对象。
上图是Bean的生命周期,Bean是IOC管理的java对象。
相比于正常的对象生命周期,Bean的生命周期多出了几个重要环节。
Aware接口
获取Bean对象的一种方式
spring提供了各种Aware接口,咱们的bean只要实现了Aware接口,那么就可以获取相应的资源。
@Component
public class ApplicationContextProvide implements ApplicationContextAware {
private ApplicationContext mApplicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
mApplicationContext = applicationContext;
}
}
Aware接口和@AutoWired区别
@AutoWired是获取bean的基本方法,具体用法在实战部分
Aware接口是系统预先定义的
BeanPostProcessor接口
提供在Bean对象实例化完成后,对Bean的一次操作机会,是容器级别的。
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
当一个BeanPostProcessor实现类注册到IOC容器后,这个IOC容器创建的所有Bean都会执行BeanPostProcessor中定义的两种方法。
@Component
public class BeanPostProcess implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ApplicationContextProvide) {
((ApplicationContextProvide) bean).init();
}
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return null;
}
}
多个BeanPostProcessor的实现类可以用@Order注解来安排顺序
@Order注解是用在类上面的
bean初始化方法
- 构造函数
- 在指定方法上面实现@PostConstruct和@PostDestroy来指定
@Component
public class ApplicationContextProvide implements ApplicationContextAware {
public String initObject;
@PostConstruct
public void init() {
initObject = "start init";
}
}
- 实现InitializingBean接口,重写afterPropertiesSet方法
- init-method 需要在配置文件中配置才能使用
上述方法按从上到下优先级由高到低。
总结
Bean被实例化后,会先把相关的依赖进行注入,这个时候一个完整的对象已经出来了。
接着BeanPostProcessor会遍历所有的对象,我们可以处理想要处理的对象,同时,spring也会查看每个bean对象是否被initAnnotationType/destroyAnnotationType注释,如果有的话,就把相应的方法加入到init/destroy队列中。
然后根据相应的作用域,判断何时产生bean。
Bean作用域
Bean的作用域由@Scope指定
- 单例模式 Singleton
- 原型 Prototype
- 请求 request
- 会话 session
- globalsession
可以直接用@Scope("singleton")或者ConfigurableListableBeanFactory.SCOPE_SINGLETON
指定Scope的Bean
@Component
@Scope("prototype")
public class BeanScopeTest {
public String beanName;
}
不同Scope的Bean的测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class BeanScopeTestTest {
@Autowired
private ApplicationContext applicationContext;
@Autowired
private BeanScopeTest bean2;
@Test
public void testScope() {
BeanScopeTest bean = applicationContext.getBean(BeanScopeTest.class);
BeanScopeTest bean1 = applicationContext.getBean(BeanScopeTest.class);
boolean isEquals = (bean == bean1);
assertEquals(false, isEquals);
}
}
Bean实战
spring 3.x的javaConfig项目,允许我们用注解的方式来定义Bean,但是也支持xml方式的配置,下面我们来试下Bean相关的注解。
注册bean
bean的配置分为三种
- 自动配置
需要搭配组件扫描@ComponentScan来发现需要自动注册的bean
只需要在类上添加@Serviec @Controller @Repository @Component 等注解即可,其中@Component是没有特殊意义的bean的注册注解。 - javaConfig显示配置
@Configuration
public class BeanConfigration {
@Bean
public BeanScopeTest getBeanConfig() {
return new BeanScopeTest();
}
}
- xml配置
@Bean注解的扩展
相同类型的bean,指定不同的名字来区分对象
@Configuration
public class BeanConfigration {
@Bean(name = "japanese")
public User getJapanese() {
User user = new User();
user.name = "小日本";
return user;
}
@Bean(name = "british")
public User getBritish() {
User user = new User();
user.name = "英国人";
return user;
}
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class BeanConfigrationTest {
@Resource(name = "japanese")
private User japanese;
@Resource(name = "british")
private User british;
@Test
public void getBeanConfig() {
assertEquals("小日本", japanese.name);
assertEquals("英国人", british.name);
}
}
使用bean
我们可以使用@AutoWired和@Resource来进行Bean的注入。
@AutoWired
@AutoWired是Spring自己的注解
@AutoWired是默认是根据类型来进行注入的,可以配合@Qualifier注解来指定名字进行注入
@AutoWired可以作用在属性、方法、构造函数上
@Resource
@Resource是JavaEE的注解
@Resource默认是根据名字来进行注入的
@Resource的装配顺序有兴趣的话可以自行查找