Spring
Spring是整个Java体系最核心的框架,没有之一。
核心类图结构
ApplicationContext
- ApplicationEventPublisher:提供了一种机制,用于通知应用程序中感兴趣的部分有关其执行过程中发生的特定事件。
- ListableBeanFactory:是Spring框架中的一个接口,它继承了BeanFactory接口,是一个具有列表查询能力的Bean工厂。
- HierarchicalBeanFactory:是Spring框架中的另一个接口,它扩展了BeanFactory接口。
- ResourcePatternResolver:是 Spring Framework 中的一个接口,用于以资源位置模式的格式解析资源。
- MessageSource:处理国际化资源的组件,用于支持国际化(i18n)和本地胡(l1On)。
- EnvironmentCapable:是 Spring Framework 中的一个接口,用于表示一个对象是否具备获取环境(Environment)的能力。
- FunctionalInterface:是 Java 8 引入的一个新的接口类型,它是一个特殊的接口,只能有一个抽象方法(可以有默认方法和静态方法),用于支持函数式编程。
- BeanFactory:是 Spring 框架的核心接口之一,主要负责对Bean的配置和管理功能,具体的创建功能是由子类来实现注入的。
- ResourceLoader:Spring Framework 中的一个接口,用于加载资源(Resource)的抽象。
BeanFactory
它是 Spring IoC(Inversion of Control,控制反转)容器的基础。IoC 容器负责管理和组装应用程序中的对象(也称为 Bean)。
在 Spring 中,BeanFactory 提供了以下主要功能:
-
实例化对象:BeanFactory 负责根据配置元数据(通常是 XML 或注解)来实例化 Java 对象,这些对象被称为 Beans。它将对象的创建和初始化过程与应用程序代码解耦,使得对象的创建更加灵活和可配置。
-
Bean 的配置管理:BeanFactory 负责管理 Bean 的配置元数据。这些元数据定义了 Bean 的类型、依赖关系和其他属性。配置元数据可以通过 XML 配置文件、Java 注解或 Java 代码进行指定。
-
依赖注入(Dependency Injection):BeanFactory 通过依赖注入的方式自动解析和设置 Bean 之间的依赖关系。依赖注入消除了硬编码的依赖关系,使得组件之间的协作更加灵活和可维护。
-
单例和原型模式管理:BeanFactory 可以管理单例(Singleton)和原型(Prototype)两种类型的 Bean。单例 Bean 在容器中只有一个实例,而原型 Bean 每次被请求时都会创建一个新的实例。
-
生命周期管理:BeanFactory 负责管理 Bean 的生命周期,它在需要的时候创建 Bean、初始化 Bean、调用 Bean 的初始化回调方法,并在容器关闭时销毁 Bean。
BeanFactory 接口定义了一些常用的方法,允许应用程序通过 Bean 名称或类型来访问和管理这些 Bean。常见的实现类包括 DefaultListableBeanFactory 和 XmlBeanFactory。
-
DefaultListableBeanFactory 是 Spring 框架默认的 BeanFactory 实现,支持基于 XML 配置和注解的 Bean 定义( class,scope, 初始化、销毁等信息)。
-
XmlBeanFactory 是较早的实现,它从 XML 配置文件中读取 Bean 定义并实例化相应的 Bean。不过在较新版本的 Spring 中,推荐使用DefaultListableBeanFactory 或者更高级的容器,如 ApplicationContext。
MessageSource
它提供了一种机制,允许应用程序通过统一的接口访问不同语言环境下的文本消息,从而使应用程序可以根据用户的语言偏好显示相应的文本信息。
在国际化和本地化的场景中,不同地区和语言可能有不同的语言、日期格式、货币符号等。通过使用 MessageSource,开发者可以将这些本地化的文本消息抽象出来,而不必硬编码到应用程序代码中,从而方便地实现多语言支持。
主要定义下面方法:
String getMessage(String code, Object[] args, String defaultMessage, Locale locale);
String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
其中,code 是消息的唯一标识符,args 是替换消息中占位符的参数数组,defaultMessage 是在找不到指定消息时的默认文本。locale 参数用于指定所需的语言环境。
Spring 中的 MessageSource 通常由 ResourceBundleMessageSource 或ReloadableResourceBundleMessageSource 等实现类来支持,这些实现类可以从属性文件(通常是 .properties 文件)或者其他资源中加载本地化消息。
简单的示例:
- 在属性文件中定义不同语言环境的消息(例如 messages_en.properties 和 messages_fr.properties):
- messages_en.properties:
greeting=Hello!
- messages_fr.properties:
greeting=Bonjour!
- 创建一个 Spring Bean,并注入 MessageSource:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.stereotype.Component; import java.util.Locale; @Component public class GreetingService { private final MessageSource messageSource; @Autowired public GreetingService(MessageSource messageSource) { this.messageSource = messageSource; } public void printGreeting(Locale locale) { String greeting = messageSource.getMessage("greeting", null, "Default Greeting", locale); System.out.println(greeting); } }
- 在应用程序中使用 GreetingService:
在上面的示例中,GreetingService 中的 printGreeting 方法会根据传入的 locale 参数获取对应的消息。如果指定的消息未找到,将会返回默认的消息(“Default Greeting”)。import org.springframework.context.annotation.AnnotationConfigApplicationContext; import java.util.Locale; public class MainApp { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); GreetingService greetingService = context.getBean(GreetingService.class); greetingService.printGreeting(Locale.US); // Output: Hello! greetingService.printGreeting(Locale.FRENCH); // Output: Bonjour! context.close(); } }
总结
通过 MessageSource,我们可以轻松实现多语言支持,使得应用程序可以根据不同用户的语言偏好提供合适的本地化文本信息。
ResourcePatternResolver
它是 Spring 核心框架的一部分,提供了一种方便的方式来定位资源,例如文件、类路径资源、URL 等,基于给定的模式。
Spring Framework 提供了多种 ResourcePatternResolver 接口的实现,以支持不同的资源定位策略。其中一些常用的实现包括:
-
PathMatchingResourcePatternResolver:这是在 Spring 应用程序中最常用的实现。它可以使用 Ant 风格的路径匹配模式来解析资源,例如 classpath*:com/example/**/*.xml,用于查找 com/example/ 包及其子包中的所有 XML 文件。
-
ServletContextResourcePatternResolver:此实现特定于 Web 应用程序,并允许您相对于 ServletContext 来解析资源。
-
FileSystemResourcePatternResolver:此解析器允许您使用文件系统路径来解析资源,在需要处理类路径之外的资源时很有用。
ResourcePatternResolver 接口提供了几种资源解析的方法,例如 getResources(String locationPattern) 可以获取与指定模式匹配的资源列表,getResource(String location) 可以根据位置获取单个资源等。
Spring 应用程序中使用 ResourcePatternResolver 的示例:
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import java.io.IOException;
public class ResourceResolverExample {
public static void main(String[] args) {
// 创建资源解析器
PathMatchingResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
try {
// 使用 Ant 风格的模式解析资源
Resource[] resources = resourceResolver.getResources("classpath*:com/example/**/*.xml");
// 处理资源
for (Resource resource : resources) {
System.out.println("资源:" + resource.getFilename());
// 在此处处理资源
}
} catch (IOException e) {
// 处理异常
e.printStackTrace();
}
}
}
ApplicationEventPublisher
它是 Spring 的事件驱动编程模型的一部分,可以在Sring应用程序中发布一些事件,对于订阅该特定类型的事件的的相关组件都可以订阅这些事件。允许 Spring 应用程序内的组件以松散耦合的方式进行通信和交互,通过事件来实现。
- 创建一个事件类
// 创建一个事件类
import org.springframework.context.ApplicationEvent;
public class CustomEvent extends ApplicationEvent {
public CustomEvent(Object source) {
super(source);
}
// 根据需要添加自定义属性和方法。
}
- 创建一个事件发布者
// 创建一个事件发布者
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
public class CustomEventPublisher implements ApplicationEventPublisherAware {
private ApplicationEventPublisher eventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void doSomethingAndPublishEvent() {
// 做一些重要的事情...
// 创建并发布事件
CustomEvent customEvent = new CustomEvent(this);
eventPublisher.publishEvent(customEvent);
}
}
- 创建一个事件监听器
// 创建一个事件监听器:
import org.springframework.context.ApplicationListener;
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
// 在这里处理自定义事件
// 当事件被发布时,该方法将被调用。
}
}
- 将监听器和发布器注入到容器中
<bean id="customEventPublisher" class="com.example.CustomEventPublisher" />
<bean id="customEventListener" class="com.example.CustomEventListener" />
ListableBeanFactory
ListableBeanFactory还提供了一些用于查询和获取Bean的扩展方法,使得可以方便地获取容器中的所有Bean或按条件进行Bean的查找。
主要的方法包括:
-
getBeanDefinitionCount(): 返回容器中注册的Bean定义的数量。
-
getBeanDefinitionNames(): 返回容器中所有注册的Bean的名称列表。
-
getBeanNamesForType(Class<?> type): 根据给定的类型返回对应的Bean名称列表。
-
getBeansOfType(Class type): 返回容器中给定类型的Bean实例的映射,其中Key为Bean名称,Value为对应的Bean实例。
这些方法使得开发人员可以很方便地根据类型或名称来获取容器中的Bean,而不需要手动遍历整个Bean定义列表。
示例:
假设我们有以下的两个Bean类,使用注解的示例:
@Component
public class User {
// ...
}
@Component
public class Product {
// ...
}
然后,我们可以通过ListableBeanFactory来获取容器中的所有Bean或按类型获取Bean:
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainApp {
public static void main(String[] args) {
ListableBeanFactory context = new AnnotationConfigApplicationContext(MainApp.class);
// 获取容器中所有Bean的名称
String[] beanNames = context.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.println("Bean Name: " + beanName);
}
// 按类型获取Bean
Map<String, User> users = context.getBeansOfType(User.class);
for (Map.Entry<String, User> entry : users.entrySet()) {
System.out.println("User Bean Name: " + entry.getKey());
}
}
}
HierarchicalBeanFactory
HierarchicalBeanFactory定义了一种层次结构,可以用于组织和管理多个BeanFactory实例,从而构建更复杂的容器结构。
在Spring中,HierarchicalBeanFactory接口主要用于以下两种场景:
- 层次性的Bean查找:如果有多个BeanFactory层次相嵌套,可以通过层次性的Bean查找来从一个容器中查找Bean,如果找不到,则会递归地向上级容器查找,直到找到或者到达根容器。
- 属性覆盖:层次性的BeanFactory允许子容器覆盖父容器中的Bean定义。在子容器中可以定义一个与父容器相同ID的Bean定义,从而覆盖父容器中的对应Bean。
通常情况下,ApplicationContext接口实现了HierarchicalBeanFactory接口,因此,ApplicationContext可以利用HierarchicalBeanFactory提供的功能。
如何使用层次性的BeanFactory:
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class MainApp {
public static void main(String[] args) {
// 创建父容器,并加载配置文件beans-parent.xml
HierarchicalBeanFactory parentBeanFactory = new XmlBeanFactory(new ClassPathResource("beans-parent.xml"));
// 创建子容器,并加载配置文件beans-child.xml
XmlBeanFactory childBeanFactory = new XmlBeanFactory(new ClassPathResource("beans-child.xml"), parentBeanFactory);
// 在子容器中获取名为"user"的Bean
User user = (User) childBeanFactory.getBean("user");
// 调用User的方法
user.greet();
}
}
EnvironmentCapable
是一个表示应用程序当前运行环境的接口。它可以用于获取配置属性、激活的配置文件、配置文件的属性值等。Spring 应用程序可以有多个不同的环境,例如开发、测试、生产环境等,并且根据不同环境进行配置和运行。
EnvironmentCapable 接口定义了一个方法:
Environment getEnvironment();
实现该接口的类需要提供这个方法的具体实现,以返回一个 Environment 实例。通过实现此接口,对象可以获取与应用程序配置相关的环境信息,并相应地调整其行为。
示例:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.Environment;
public class EnvironmentExample {
public static void main(String[] args) {
// 创建并初始化 Spring 应用程序上下文
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取环境信息
Environment environment = context.getEnvironment();
// 获取配置属性值
String propertyValue = environment.getProperty("app.name");
System.out.println("应用程序名称:" + propertyValue);
}
}
ResourceLoader
它是 Spring 的资源加载机制的核心接口,提供了一种统一的方式来获取不同类型的资源,如文件、类路径资源、URL 等。
ResourceLoader 接口定义了一个方法:
Resource getResource(String location);
实现该接口的类需要提供这个方法的具体实现,以根据给定的资源位置(location)加载相应的资源。Resource 是 Spring 框架中另一个重要的接口,它代表一个可访问的资源,可以是文件、类路径资源、URL 等。
Spring 提供了多个实现 ResourceLoader 接口的类,包括:
- DefaultResourceLoader: 默认的资源加载器,用于加载资源,支持类路径资源、文件系统资源等。
- ClassPathResourceLoader: 用于加载类路径资源。
- ServletContextResourceLoader: 用于在 Web 应用程序中加载 ServletContext 资源。
- UrlResourceLoader: 用于加载 URL 资源。
- 其他自定义的实现类,根据需要加载其他类型的资源。
在 Spring 应用程序中,通常通过 ResourceLoader 来加载资源,以获得更灵活的资源管理和访问方式。这样可以使代码与具体的资源位置解耦,并且能够轻松地在不同环境中切换资源的加载方式。
以下是一个简单的示例,展示如何使用 ResourceLoader 接口加载资源:
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.DefaultResourceLoader;
public class ResourceLoaderExample {
public static void main(String[] args) {
// 创建资源加载器
ResourceLoader resourceLoader = new DefaultResourceLoader();
// 加载资源
Resource resource = resourceLoader.getResource("classpath:example.txt");
// 判断资源是否存在
if (resource.exists()) {
// 处理资源
// ...
} else {
System.out.println("资源不存在。");
}
}
}