Java中高级核心知识全面解析——常用框架(Spring中-Bean-的作用域与生命周期)

例子如下:

public class GiraffeService {
//通过的destroy-method属性指定的销毁方法
public void destroyMethod() throws Exception {
System.out.println(“执行配置的destroy-method”);
}
//通过的init-method属性指定的初始化方法
public void initMethod() throws Exception {
System.out.println(“执行配置的init-method”);
}
}

配置文件中的配置:


需要注意的是自定义的init-methodpost-method方法可以抛异常但是不能有参数。

这种方式比较推荐,因为可以自己创建方法,无需将Bean的实现直接依赖于spring的框架。

3)使用@PostConstruct和@PreDestroy注解

除了xml配置的方式,Spring 也支持用 @PostConstruct@PreDestroy 注解来指定 initdestroy 方法。这两个注解均在 javax.annotation 包中。为了注解可以生效,需要在配置文件中定义org.springframework.context.annotation.CommonAnnotationBeanPostProcessor或context:annotation-config

例子如下:

public class GiraffeService {
@PostConstruct
public void initPostConstruct(){
System.out.println(“执行PostConstruct注解标注的方法”);
}
@PreDestroy
public void preDestroy(){
System.out.println(“执行preDestroy注解标注的方法”);
}
}

配置文件:

2.实现*Aware接口 在Bean中使用Spring框架的一些对象

有些时候我们需要在 Bean 的初始化中使用 Spring 框架自身的一些对象来执行一些操作,比如获取ServletContext的一些参数,获取 ApplicaitionContext 中的 BeanDefinition的名字,获取 Bean 在容器中的名字等等。为了让 Bean 可以获取到框架自身的一些对象,Spring 提供了一组名为*Aware的接口。

这些接口均继承于 org.springframework.beans.factory.Aware 标记接口,并提供一个将由 Bean实现的set*方法,Spring通过基于setter的依赖注入方式使相应的对象可以被Bean使用。

网上说,这些接口是利用观察者模式实现的,类似于servlet listeners,目前还不明白,不过这也不在本文的讨论范围内。

介绍一些重要的Aware接口:

  • ApplicationContextAware: 获得ApplicationContext对象,可以用来获取所有Bean definition的名字。
  • BeanFactoryAware:获得BeanFactory对象,可以用来检测Bean的作用域。
  • BeanNameAware:获得Bean在配置文件中定义的名字。
  • ResourceLoaderAware:获得ResourceLoader对象,可以获得classpath中某个文件。
  • ServletContextAware:在一个MVC应用中可以获取ServletContext对象,可以读取context中的参数。
  • ServletConfigAware: 在一个MVC应用中可以获取ServletConfig对象,可以读取config中的参数。

public class GiraffeService implements ApplicationContextAware,
ApplicationEventPublisherAware, BeanClassLoaderAware, BeanFactoryAware,
BeanNameAware, EnvironmentAware, ImportAware, ResourceLoaderAware{
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("执行setBeanClassLoader,ClassLoader Name = " +
classLoader.getClass().getName());
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println(“执行setBeanFactory,setBeanFactory:: giraffe bean singleton=” + beanFactory.isSingleton(“giraffeService”));
}
@Override
public void setBeanName(String s) {
System.out.println(“执行setBeanName:: Bean Name defined in context=” + s);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println(“执行setApplicationContext:: Bean Definition Names=”

  • Arrays.toString(applicationContext.getBeanDefinitionNames()));
    }
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    System.out.println(“执行setApplicationEventPublisher”);
    }
    @Override
    public void setEnvironment(Environment environment) {
    System.out.println(“执行setEnvironment”);
    }
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
    Resource resource = resourceLoader.getResource(“classpath:spring- beans.xml”);
    System.out.println(“执行setResourceLoader:: Resource File Name=” + resource.getFilename());
    }
    @Override
    public void setImportMetadata(AnnotationMetadata annotationMetadata) {
    System.out.println(“执行setImportMetadata”);
    }
    }

3.BeanPostProcessor

上面的*Aware接口是针对某个实现这些接口的Bean定制初始化的过程,
Spring同样可以针对容器中的所有Bean,或者某些Bean定制初始化过程,只需提供一个实现 BeanPostProcessor接口的类即可。 该接口中包含两个方法,postProcessBeforeInitializationpostProcessAfterInitializationpostProcessBeforeInitialization方法会在容器中的Bean初始化之前执行, postProcessAfterInitialization方法在容器中的Bean初始化之后执行。

例子如下:

public class CustomerBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(“执行BeanPostProcessor的 postProcessBeforeInitialization方法,beanName=” + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(“执行BeanPostProcessor的postProcessAfterInitialization 方法,beanName=” + beanName);
return bean;
}
}

要将BeanPostProcessor的Bean像其他Bean一样定义在配置文件中

4.总结

所以结合第一节控制台输出的内容,Spring Bean的生命周期是这样纸的:

  • Bean容器找到配置文件中 Spring Bean 的定义。
  • Bean容器利用Java Reflection API创建一个Bean的实例。
  • 如果涉及到一些属性值 利用set方法设置一些属性值。
  • 如果Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean的名字。
  • 如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。
  • 如果Bean实现了BeanFactoryAware接口,调用setBeanFactory()方法,传入BeanFactory对象的实例。
  • 与上面的类似,如果实现了其他*Aware接口,就调用相应的方法。
  • 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行
    postProcessBeforeInitialization()方法
  • 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。
  • 如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。
  • 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessAfterInitialization()方法
  • 当要销毁Bean的时候,如果Bean实现了DisposableBean接口,执destroy()方法。
  • 当要销毁Bean的时候,如果Bean在配置文件中的定义包含destroy-method属性,执行指定的方法。

image
与之比较类似的中文版本:
image
其实很多时候我们并不会真的去实现上面说描述的那些接口,那么下面我们就除去那些接口,针对bean的单例和非单例来描述下bean的生命周期:

5.单例管理的对象

scope=”singleton”,即默认情况下,会在启动容器时(即实例化容器时)时实例化。但我们可以指定Bean节点的lazy-init=”true”来延迟初始化bean,这时候,只有在第一次获取bean时才会初始化bean,即第一次请求该bean时才初始化。如下配置:

如果想对所有的默认单例bean都应用延迟初始化,可以在根节点beans设置default-lazy-init属性为true,如下所示:

<beans default-lazy-init=“true” …>

默认情况下,Spring 在读取 xml 文件的时候,就会创建对象。在创建对象的时候先调用构造器,然后调用 init-method 属性值中所指定的方法。对象在被销毁的时候,会调用 destroy-method 属性值中所指定的方法(例如调用Container.destroy()方法的时候)。写一个测试类,代码如下:

public class LifeBean {
private String name;

总结

在清楚了各个大厂的面试重点之后,就能很好的提高你刷题以及面试准备的效率,接下来小编也为大家准备了最新的互联网大厂资料。

![在这里插入图片描述](https://upload-images.jianshu.io/upload_images/24616006-42ba72825e0525b2?imageMogr2/auto-orie 需要zi料+ 绿色徽【vip1024b】

nt/strip%7CimageView2/2/w/1240)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4b】**

nt/strip%7CimageView2/2/w/1240)

[外链图片转存中…(img-4xK4CJu9-1710352885938)]

[外链图片转存中…(img-AHYa55uL-1710352885938)]

[外链图片转存中…(img-QTvdKewK-1710352885939)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值