JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

Java 中高级核心知识全面解析 (1),Java 开发实战

wys521 2024-11-14 19:26:03 精选教程 16 ℃ 0 评论

配置文件:


<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" 
/>

复制代码

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 一样定义在配置文件中


<bean class="com.giraffe.spring.service.CustomerBeanPostProcessor"/>

复制代码

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属性,执行指定的方法。



与之比较类似的中文版本:



其实很多时候我们并不会真的去实现上面说描述的那些接口,那么下面我们就除去那些接口,针对 bean 的单例和非单例来描述下 bean 的生命周期:

5.单例管理的对象

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


<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" lazy-init="true"/>

复制代码


如果想对所有的默认单例 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; 
  
  public LifeBean(){ 
    System.out.println("LifeBean()构造函数"); 
  }
  
  public String getName() { 
    return name; 
  }
  
  public void setName(String name) { 
    System.out.println("setName()"); 
    this.name = name; 
  }
  
  public void init(){ 
    System.out.println("this is init of lifeBean"); 
  }
  
  public void destory(){ 
    System.out.println("this is destory of lifeBean " + this); 
  } 
}

复制代码


life.xml 配置如下:


<bean id="life_singleton" class="com.bean.LifeBean" scope="singleton" 
init-method="init" destroy-method="destory" lazy-init="true"/>

复制代码


测试代码:


LifeBean()构造函数 
this is init of lifeBean 
com.bean.LifeBean@573f2bb1 
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1

复制代码

6.非单例管理的对象

scope=”prototype” 时,容器也会延迟初始化 bean,Spring 读取 xml 文件的时候,并不会立刻创建对象,而是在第一次请求该 bean 时才初始化(如调用 getBean 方法时)。在第一次请求每一个 prototype 的 bean 时,Spring 容器都会调用其构造器创建这个对象,然后调用 init-method 属性值中所指定的方法。对象销毁的时候,Spring 容器不会帮我们调用任何方法,因为是非单例,这个类型的对象有很多个,Spring 容器一旦把这个对象交给你之后,就不再管理这个对象了。


为了测试prototype bean的生命周期 life.xml 配置如下:


<bean id="life_prototype" class="com.bean.LifeBean" scope="prototype" 
init- method="init" destroy-method="destory"/>

复制代码


测试程序:


public class LifeTest { 
  @Test 
  public void test() { 
    AbstractApplicationContext container = new ClassPathXmlApplicationContext("life.xml"); 
    LifeBean life1 = (LifeBean)container.getBean("life_singleton"); 
    System.out.println(life1); 
    
    LifeBean life3 = (LifeBean)container.getBean("life_prototype"); 
    System.out.println(life3); 
    container.close(); 
  } 
}

复制代码


运行结果:


LifeBean()构造函数 
this is init of lifeBean 
com.bean.LifeBean@573f2bb1 
LifeBean()构造函数 
this is init of lifeBean 
com.bean.LifeBean@5ae9a829 
……




# 本次面试答案,以及收集到的大厂必问面试题分享:


![字节跳动超高难度三面java程序员面经,大厂的面试都这么变态吗?](https://static001.geekbang.org/infoq/1f/1ffb14002e1ff2c719722161e68c94c5.jpeg)


**[资料领取方式:戳这里即可免费下载](https://gitee.com/vip204888/java-p7)**

复制代码



















作者:JVM调优资料

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表