ApplcationContext 功能解析

本文详细介绍了Spring的ApplicationContext,包括它的扩展功能,如统一资源加载策略,使用ResourceLoader接口和ResourcePatternResolver实现不同类型的资源加载。此外,还讲解了国际化信息支持(l18n)和事件发布机制,包括ApplicationEvent和ApplicationListener的使用。同时,讨论了如何通过注解实现自动注入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1概述

applicationContext 除了拥有BeanFactory支持的所有功能。其还进一步扩展其功能主要有统一资源加载策略。国际化信息支持,容器内事件发布

主要实现

  • FileSystemXmlApplicationContext
    文件系统加载bean定义,以及相关资源的applicationContext实现

  • ClassPathXmlApplicationContext
    classpath加载bean定义以及相关资源的applicationContext实现

  • XmlWebApplicatonContext
    用于web程序的applicationcontext实现。

2 统一资源加载策略

除**file:,http:,ftp:协议前缀外,spring还扩展了其他协议,classPath:和classPath其区别在于classPath:如果能在classPath路径中找到多个则返回多个。
我们可以使用classpath:前缀让FileSystemXmlApplicationContext
从Classpath中加载配置,而不是从文件系统中加载

2.1 Resource

spring中提供resource接口作为所有资源的抽象和访问接口
resource接口根据资源的不同类型,给出了具体的实现。

  • ByteArrayResource
    将字节提供的数据进行封装,通过InputStream进行访问类型的资源,构造出byteArray-inputStream并返回。

  • ClassPathResource
    从java中的ClassPath中加载具体资源并进行封装,可以使用指定的类加载器或类对其加载

  • FileSystemResource
    对file类型的封装,可以通过文件或者url对该类型进行访问

  • UrlResource
    通过url进行具体资源查找定位的实现类

  • InputStreamResource
    将InputStream视为一种资源的Resource的实现类

2.2 ResourceLoader

ResourceLoader接口是用于资源查找和定位的接口

public interface ResourceLoader {

	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;

//根据指定资源位置,定位到具体的资源实例
	Resource getResource(String location);


	@Nullable
	ClassLoader getClassLoader();

}
2.2.1 DefaultResourceLoader

是ResourceLoader默认实现类其处理逻辑为

  • 首先检查是否以/为前缀,是,则委派给getResourceByPath来定位,其内部是构造classPathResource类型资源并返回。

  • 然后检查资源路径是否以classpath为前缀,是,则尝试构造classpathresource资源并返回

  • 否则 则会尝试通过url,根据资源路径进行定位资源,如果没有则抛出MalFormedURLException则会构造Url类型资源并返回。还是无法根据资源路径定位指定的资源则会委派给getResourceByPath来定位,其内部是构造classPathResource类型资源并返回。

其主要逻辑

if (location.startsWith("/")) {
			return getResourceByPath(location);
		}
		else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
		}
		else {
			try {
				// Try to parse the location as a URL...
				URL url = new URL(location);
				return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
			}
			catch (MalformedURLException ex) {
				// No URL -> resolve as resource path.
				return getResourceByPath(location);
			}
2.2.2 FileSystemResourceLoader

为了避免DefaultResourceLoader的getResourceBypath方法上的不正当处理,其FileSystemResourceLoader覆写了其方法,使之从**文件系统加载资源并以fileSystemResource **类型返回

其重写的方法

	protected Resource getResourceByPath(String path) {
		if (path.startsWith("/")) {
			path = path.substring(1);
		}
		return new FileSystemContextResource(path);
	}

2.2.3 ResourcePatternResolver

ResourcePatternResolver是resourceloader的扩展,其可以根据指定的资源路径匹配模式,每次返回多个resource实例。

public interface ResourcePatternResolver extends ResourceLoader {
	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

//又定义了getResources用于批量查找
	Resource[] getResources(String locationPattern) throws IOException;

}

其实现类为PathMatchingResourcePatternResolver,需要指定一个ResourceLoader,否则其内部默认使用的是defaultresourceloader。

2.3 applicationcontext 与 resource

由图可知applicationContext本身就是ResourceLoader,

2.3.1 ResourceLoader类型的注入

我们可以通过实现ResourceLoaderAware和ApplicationContextAware接口,来让自身applicationContext(ResourceLoader)注入进去。

public class TestAware implements ResourceLoaderAware {
   //实现其相应的Aware会将自身给注入进去
   private ResourceLoader resourceLoader;

   public ResourceLoader getResourceLoader() {
       return resourceLoader;
   }

   @Override
   public void setResourceLoader(ResourceLoader resourceLoader) {
       this.resourceLoader=resourceLoader;
   }

}

xml中bean的注入

   <bean id ="testAware" class="org.example.Day03.TestAware"/>

3 国际化信息支持(l18n)

对于java中的国际化信息处理,主要涉及了Locale和ResourceBundle

  • Locale
    不同的Locale代表不同的国家和地区,如Locale.CHINA代表中国,代码表示为zh_CN;zh表示语言代码,CN表示国家代码

  • ResourceBundle
    ResourceBundle用于保存特定于某个Locale的信息。,ResourceBundle管理一组信息序列,其序列有统一的basename,可以根据basename后追加语言或者地区代码进行区分

message_zh.properties
message_zh_CN.properties

我们可以通过ResourceBundle的getBundle(String basename,Loacale locale)方法取得不同的Locale对应的ResourceBundle,然后根据资源建获取相应的locale资源条目内容。

3.1 MessageSource与Applicationcontext

spring进一步抽象了国际化信息的访问接口 messageSource

public interface MessageSource {

//根据资源条目的键,信息参数和locale进行查找,未找到则返回默认的defaultMessage
	String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
//根据资源条目的键,信息参数和locale进行查找,未找到则抛出异常
String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;

//将资源条目的键,信息参数封装成MessageSourceResolvable
	String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;

}

配置文件

# message_en_US.properties中
menu.file=file({0})
menu.age=18

bean容器中需要注册 messageResource

   <bean  id ="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename">
            <value>message</value>
        </property>
    </bean>

执行

   ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        String a= applicationContext.getMessage("menu.file",new Object[]{"ww"}, Locale.US);
        System.out.println(a);

4 事件发布

javase 提供了事件发布功能的基础类,eventobject类和EventListenner接口

4.1 自定义事件发布流程

  • 自定义事件类型
  • 实现自定义事件类的时间监听器接口
  • 组合事件类和监听器,发布事件

4.2 spring容器内的事件发布

以applicationEvent形式发布事件,而容器内注册的applicationListener会被容器自动识别,负责监听容器内applicationEvent类型的事件。

4.2.1 ApplicationEvent

一个抽象类,spring提供了三个实现

  • ContextClosedEvent: 容器在即将关闭是发布的事件类型
  • ContextRefreshedEvent: 容器在初始化或刷新时发布的事件类型
  • RequestHandledEvent: web请求处理后发布的事件
4.2.2 ApplicationListener

容器内使用的自定义事件监听器接口定义,applicationcontext容器在启动时,会自动识别eventlistener类型bean定义,一旦容器内有事件发布,则将通知这些注册到容器的eventlistener

4.2.3 ApplicationContext

applicationContext除了resourceLoader接口和messageSource接口其还实现了ApplicationEventPublisher接口,担当发布者角色。
但是其将事件发布功能全部委托给了ApplicationEventMulticaster来做,因此容器在启动时会先检查是否存在,没有的话则默认初始化SimpleApplicationEventMulticaster.

4.2.4 自定义事件

创造事件本身

public class TestEvent extends ApplicationEvent {

    private String name;

    /**
     * Create a new ApplicationEvent.
     *
     * @param source the object on which the event initially occurred (never {@code null})
     */
    public TestEvent(Object source) {
        super(source);
    }
    public TestEvent(Object source,String name) {
        super(source);
        this.name=name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

创建监听器

public class SimpleTestListen implements ApplicationListener {

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof  TestEvent){
            System.out.println("tytt"+((TestEvent) event).getName());
        }
    }
}

创建发布者

public class TestPublisher implements ApplicationContextAware {
    //通过实现 ApplicationContextAware 将publisher给注入进去
    private ApplicationEventPublisher publisher;
    private List<TestListen> lists = new ArrayList<>();
    public void monitor(){
        TestEvent testEvent = new TestEvent(this,"ws");
        //重点在于发布事件
        this.publisher.publishEvent(testEvent);
    }



    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
          this.publisher=applicationContext;
    }
}

将发布者与监听器给注册到bean容器

 <bean id="listener"  class="org.example.Day03.SimpleTestListen"></bean>
    <bean id = "publisher" class="org.example.Day03.TestPublisher"></bean>

4.3 基于注解

@Autowired通过类型(byType)进行自动注入,@Qualifier可以对依赖注入做进一步的限定。
@Resource通过名字(byName)进行自动注入

其注解的原理都是实现了相应的BeanPostProcessor,因此我们需要在容器中加载相应的BeanPostProcessor,而我们可以使用<context:annotation-config>配置自动加载以上的BeanPostProcessor.<context:component-scan base-package="org.example"/>是扫描到某个类标注了相应的注解后,提取该类的信息,构成相应的beanDefinition,然后把构建完的BeanDefinition注册到容器中其默认命名为首字母小写。这样就可以免于配置bean的灾难

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值