Spring中BeanFactory和ApplicationContext

本文深入探讨Spring框架中的BeanFactory和ApplicationContext,讲解两者之间的区别及应用场景,介绍基于类注解的配置方式,以及ApplicationContextAware接口的使用方法。

 

 

BeanFactory和ApplicationContext


Spring通过一个配置文件描述Bean和Bean之间的依赖关系,利用Java反射功能实例化Bean,并建立Bean之间的依赖关系。

Spring的IOC容器在完成这些底层工作的基础上,还提供了Bean实例缓存、生命周期管理、Bean实例代理、时间发布、资源装载等高级服务。

BeanFactory是Spring框架最核心的接口,它提供了高级IOC的配置机制。

ApplicationContext建立在BeanFactory的基础上,提供了更多面向应用的功能, 它提供了国际化支持和框架事件体系。

我们一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文,但有时候为了行文方便,我们也将ApplicationContext称为Spring容器。

对于BeanFactory 和 ApplicationContext的用途:

  1. BeanFactory是Spring框架的基础设施,面向Spring本身
  2. ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都可以直接使用Application而非底层的BeanFactory.

 

概述


Application由BeanFactory派生而来,提供了更多面向实际的功能。

在BeanFactory中,很多功能都需要以编程的形式实现,但是在Application中则可以通过配置的方式实现。

ApplicationContext类体系结构
Application继承了HierachicalBeanFactory和ListableBeanFactory接口,在此基础上,还通过其他接口扩展了BeanFactory的功能。

这些接口如下:

ApplicationEventPublisher:让容器拥有发布应用上下文事件的功能,包括容器的启动事件、关闭事件等。
MessageSource:为应用提供i18N国际化消息访问的功能
ResourcePatternResolver:加载资源,可以通过带前缀的Ant风格的资源文件路径装载Spring的配置文件
LifeCycle:该接口提供start()和stop()方法,主要用于控制异步处理的过程,以达到管理和控制JMX、任务调度等目的
 

è¿éåå¾çæè¿°

è¿éåå¾çæè¿°
ConfigurableApplicationContext扩展于ApplicationContext,主要新增了两个方法 refresh()和close(),让Application具有启动、刷新、关闭应用上下文的能力。

在应用上下文关闭的情况下,refresh可以启动上下文,在启动的情况下可以清楚缓存并重新装载配置信息。 close方法这可以关闭上下文。

以上内容了解即可

 

ApplicationContext初始化

è¿éåå¾çæè¿°

è¿éåå¾çæè¿°

在获取ApplicationContext实例后,我们就可以像BeanFactory那样调用getBean(beanName)返回Bean了。

ApplicationContext的初始化和BeanFactory初始化有一个重大区别

BeanFactory在初始化容器时,并没有实例化Bean,直到第一次访问某个Bean时才实例化目标Bean。 
ApplicationContext会在初始化应用上下文时就实例化所有单实例的Bean。

因此,ApplicationContext的初始化时间会比BeanFactory的时间稍微长一些,不过稍后的调用则没有“第一次惩罚”的问题。

 

ApplicationContext两个主要实现类


ClassPathXmlApplicationContext
FileSystemXmlApplicationContext

è¿éåå¾çæè¿°

Plane.java和bean-plane.xml请参考 
http://blog.youkuaiyun.com/yangshangwei/article/details/74910935#t3

ClassPathXmlApplicationContext


package com.xgj.master.ioc.beanfactory;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ClassPathXmlApplicationTest {

    public static void main(String[] args) {

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
            "classpath:com/xgj/master/ioc/beanfactory/bean-plane.xml");
        Plane plane = (Plane) applicationContext.getBean("plane");
        plane.introduce();

    }

}

如果配置文件放在在类路径下,则优先考虑使用ClassPathXmlApplication实现类

对于 ClassPathXmlApplicationContext 来讲:

new ClassPathXmlApplicationContext(
            "classpath:com/xgj/master/ioc/beanfactory/bean-plane.xml");

等同于

new ClassPathXmlApplicationContext(
            "com/xgj/master/ioc/beanfactory/bean-plane.xml");
 

FileSystemXmlApplicationContext


package com.xgj.master.ioc.beanfactory;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class FileSystemXmlApplicationTest {

    public static void main(String[] args) {
        ApplicationContext app = new FileSystemXmlApplicationContext(
                "file:D:/workspace/workspace-jee/HelloSpring/Spring4-char2/src/com/xgj/master/ioc/beanfactory/bean-plane.xml");
        Plane plane = (Plane) app.getBean("plane");
        plane.introduce();
    }


}

如果配置文件放在文件系统路径下,则优先考虑使用FileSystemXmlApplication实现类

对于FileSystemXmlApplication来讲,

"file:D:/workspace/workspace-jee/HelloSpring/Spring4-char2/src/com/xgj/master/ioc/beanfactory/bean-plane.xml"

等同于

"D:/workspace/workspace-jee/HelloSpring/Spring4-char2/src/com/xgj/master/ioc/beanfactory/bean-plane.xml"

运行结果: 

è¿éåå¾çæè¿°
加载一组配置文件
初始化配置文件时,还可以指定一组配置文件,Spring会自动对多个配置文件在内存中“整合”成一个配置文件。

举例: 
我们新增一个Car类,和Plane中的属性方法一致,增加一个配置文件bean-car.xml,和bean-plane.xml中的结构一致。

è¿éåå¾çæè¿°

ClassPathXmlApplicationContext加载一组资源文件

//两种写法  
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] {
                "com/xgj/master/ioc/beanfactory/bean-plane.xml", "com/xgj/master/ioc/beanfactory/bean-car.xml" });


ApplicationContext ctx2 = new ClassPathXmlApplicationContext(
                "com/xgj/master/ioc/beanfactory/bean-plane.xml", "com/xgj/master/ioc/beanfactory/bean-car.xml");

Plane plane2 = (Plane) ctx2.getBean("plane");
Car car = (Car) ctx2.getBean("car");

plane2.introduce();
car.introduce();

FileSystemXmlApplicationContext加载一组资源文件

// 加载多组资源文件
ApplicationContext ctx = new FileSystemXmlApplicationContext(
                "file:D:/workspace/workspace-jee/HelloSpring/Spring4-char2/src/com/xgj/master/ioc/beanfactory/bean-plane.xml",
                "file:D:/workspace/workspace-jee/HelloSpring/Spring4-char2/src/com/xgj/master/ioc/beanfactory/bean-car.xml");

Plane plane2 = (Plane) ctx.getBean("plane");
Car car = (Car) ctx.getBean("car");

plane2.introduce();
car.introduce();

运行结果:

è¿éåå¾çæè¿°

基于类注解的配置方式


Spring支持基于类注解的配置方式,主要来源于Spring的子项目JavaConfig。 目前JavaConfig已经成为Spring核心框架的一部分。

这里只是简单的演示用法,后续更新详情。

è¿éåå¾çæè¿°

一个标注了@Configuration注解的POJO即可提供Spring所需要的配置信息。

代码如下:

Beans.java 配置信息提供类

package com.xgj.spring4.chapter4.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration // @Configuration表示是一个配置信息提供类
public class Beans {

    @Bean(name = "plane") // ͨ定义一个Bean,通过name指定bean的名称
    public Plane createPlane() {
        Plane plane = new Plane();
        plane.setBrand("F35");
        plane.setColor("GREY");
        plane.setMaxSpeed(800);
        return plane;
    }

}
Plane.java

package com.xgj.spring4.chapter4.configuration;

public class Plane {

    private String brand;
    private String color;
    private int maxSpeed;

    ...
    省略setter/getter方法

    public void introduce(){
        System.out.println("Plane brand:" + brand + " ,Color:" + color + ",maxSpeed:" + maxSpeed);
    }
}

AnnotationConfigApplicationTest.java 测试:

package com.xgj.spring4.chapter4.configuration;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AnnotationConfigApplicationTest {

    public static void main(String[] args) {

        // ͨ通过一个带有@Configuration的POJO装载Bean的配置
        ApplicationContext ctx = new AnnotationConfigApplicationContext(Beans.class);

        Plane plane = ctx.getBean("plane", Plane.class);

        plane.introduce();
    }

}
运行结果:

è¿éåå¾çæè¿°

解析:

Spring为基于注解类的配置提供了专门的ApplicationContext实现类:AnnotationConfigApplication。

AnnnotationConfigApplication将加载Beans.class中的Bean定义并调用Beans.class中的方法实例化Bean,启动并装载Bean。

 

ApplicationContextAware 的作用

ApplicationContextAware 通过它Spring容器会自动把上下文环境对象调用ApplicationContextAware接口中的setApplicationContext方法。

我们在ApplicationContextAware的实现类中,就可以通过这个上下文环境对象得到Spring容器中的Bean。

  看到—Aware就知道是干什么的了,就是属性注入的,但是这个ApplicationContextAware的不同地方在于,实现了这个接口的bean,当spring容器初始化的时候,会自动的将ApplicationContext注入进来: 
使用方法如下:

1.实现ApplicationContextAware接口:


import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.co.ayz.rpc.registry.ServiceRegistry;

public class RpcServer implements ApplicationContextAware{

    private ApplicationContext context;

        @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        // TODO Auto-generated method stub
        context = applicationContext;       
    }   
     //获得applicationContext
    public static ApplicationContext getApplicationContext() {
        //assertContextInjected();
        return context;
    }    
    public static void clearHolder(){
        context=null;
    }
    //获取Bean
    public static <T> T getBean(Class<T> requiredType){
        //assertContextInjected();
        return (T) getApplicationContext().getBean(requiredType);
    }
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name){
        assertContextInjected();
        return (T) getApplicationContext().getBean(name);
    }    
    //判断application是否为空
    public static void assertContextInjected(){
        Validate.isTrue(context==null, "application未注入 ,请在springContext.xml中注入SpringHolder!");
    }
}

因为我们在做开发的时候,并不是说在每一个地方都能将属性注入到我们想要的地方去的,比如在Utils使用到dao,我们就不能直接注入了,这个时候就是我们需要封装springContext的时候了,而ApplicationContextAware就起了关键性的作用。

原文:https://blog.youkuaiyun.com/yangshangwei/article/details/74937778

 

 

 

 

 

 

 

 

 

 

 

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值