Spring生命周期简介与具体应用
程序员文章站
2022-12-20 14:55:16
Spring对Bean进行实例化(相当于程序中的new Xx())Spring将值和Bean的引用注入进Bean对应的属性中如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()方法(实现BeanNameAware主要是为了通过Bean的引用来获得Bean的ID,一般业务中是很少有用到Bean的ID的)如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanDactory(BeanFactory bf)方法并把.....
- Spring对Bean进行实例化(相当于程序中的new Xx())
- Spring将值和Bean的引用注入进Bean对应的属性中
- 如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()方法(实现BeanNameAware主要是为了通过Bean的引用来获得Bean的ID,一般业务中是很少有用到Bean的ID的)
- 如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanDactory(BeanFactory bf)方法并把BeanFactory容器实例作为参数传入。(实现BeanFactoryAware 主要目的是为了获取Spring容器,如Bean通过Spring容器发布事件等)
- 如果Bean实现了ApplicationContextAware接口,Spring容器将调用setApplicationContext(ApplicationContext ctx)方法,把应用上下文作为参数传入.
(作用与BeanFactory类似都是为了获取Spring容器,不同的是Spring容器在调用setApplicationContext方法时会把它自己作为setApplicationContext 的参数传入,而Spring容器在调用setBeanFactory前需要程序员自己指定(注入)setBeanFactory里的参数BeanFactory ) - 如果Bean实现了BeanPostProcess接口,Spring将调用它们的postProcessBeforeInitialization(预初始化)方法(作用是在Bean实例创建成功后对进行增强处理,如对Bean进行修改,增加某个功能)
- 如果Bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet方法,作用与在配置文件中对Bean使用init-method声明初始化的作用一样,都是在Bean的全部属性设置成功后执行的初始化方法。
- 如果Bean实现了BeanPostProcess接口,Spring将调用它们的postProcessAfterInitialization(后初始化)方法
(作用与6的一样,只不过6是在Bean初始化前执行的,而这个是在Bean初始化后执行的,时机不同 ) - 如果是单例的bean,则将该bean放入singleTonOnject池中,下一次再用的时候直接取
- 经过以上的工作后,Bean将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁
- 如果Bean实现了DispostbleBean接口,Spring将调用它的destory方法,作用与在配置文件中对Bean使用destory-method属性的作用一样,都是在Bean实例销毁前执行的方法。
在其中:
4能获取BeanFactory(DefaultListableBeanFactory),5能获取ApplicationContext(DefaultListableBeanFactory)
你会发现,他们获取的都是同一个!
@Component
public class BeanFactoryUtil implements BeanFactoryAware {
private static BeanFactory beanFactory;
public static BeanFactory getBeanFactory() {
return beanFactory;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
System.out.println("调用了setBeanFactory");
setFactory(beanFactory);
}
private static void setFactory(BeanFactory bf) {
beanFactory = bf;
}
}
@SpringBootTest
class BeanFactoryUtilTest {
@Test
void getBeanFactory() {
System.out.println("===========" + BeanFactoryUtil.getBeanFactory().getClass().getSimpleName());
}
}
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(@NotNull ApplicationContext context) {
System.out.println("调用了setApplicationContext");
setContext(context);
}
private static void setContext(@NotNull ApplicationContext ac) {
context = ac;
}
public static ApplicationContext getContext() {
return context;
}
}
@SpringBootTest
class ApplicationContextUtilTest {
@Test
void getContext() {
System.out.println("===========" + ApplicationContextUtil.getContext().getClass().getSimpleName());
}
}
这个DefaultListableBeanFactory可以理解为整个spring IOC容器的始祖
6和8的话能做一个bean实例化之后的操作,比如动态代理:
public interface BeanPostProcessor {
// 这个方法会在bean实例化后,调用初始化方法之前执行
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
// 这个方法会在bean实例化后,调用初始化方法之后执行
// 这里的before和after是相对于初始化方法的调用
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
我们知道往往大哥注解就可以让一个普通的类在运行时期变成动态代理类,比如说@Transcational
本来是一个普通的bean,然后在运行期的某个时刻就变成了动态代理bean,有可能就是BeanPostProcessor做了这方面的事情
我们查看BeanPostProcessor的实现类:
发现有一个实现类好像和我们的aop有关:AbstractAutoProxyCreator
差不多就是这个意思,判断某个bean是否需要被代理,需要被代理的就会动态代理创建出来,
其中:
/**
* 如果子类将bean标识为一个要代理的bean,则使用配置的拦截器创建一个代理。
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
/**
* 必要时包装给定的bean,如果他资格被代理。
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
最终动态代理在createProxy方法中proxyFactory.getProxy(getProxyClassLoader())执行
这里有BeanPostProcessor的一个小应用可以看看:Spring源码分析(五) – Spring中的BeanPostProcessor
其他详细的使用就不在这里介绍了
本文地址:https://blog.csdn.net/qq_39327985/article/details/107357290
推荐阅读
-
PHP与MongoDB简介|安全|M+PHP应用实例详解
-
Spring AOP 实现原理与 CGLIB 应用
-
Spring AOP简介与底层实现机制——动态代理
-
Spring生命周期简介与具体应用
-
web应用安全框架选型:Spring Security与Apache Shiro
-
JAVAEE——宜立方商城09:Activemq整合spring的应用场景、添加商品同步索引库、商品详情页面动态展示与使用缓存
-
bean装载到Spring应用上下文的生命周期
-
Spring Security原理与应用
-
字符设备驱动开发 Linux 设备号 字符设备驱动开发步骤 open 函数调用流程 设备号的组成 设备号的分配 Linux 应用程序对驱动程序的调用 字符设备注册与注销 实现设备的具体操作函数
-
Spring中bean的作用域与生命周期