此文是【Spring 容器详解】的支节点。
ApplicationContext是BeanFactory的子接口,它在BeanFactory的基础上提供了大量企业级功能。相对于BeanFactory的轻量级设计,ApplicationContext是一个功能丰富的企业级容器,为Spring应用提供了完整的框架支持。
ApplicationContext相对于BeanFactory的企业化增强主要包括:
- 国际化支持
- 事件机制
- 资源访问
- 环境配置
- AOP支持
- 事务管理
- 缓存支持
- 配置属性绑定
下面通过代码示例详细介绍这些企业化增强功能。
1. 国际化支持 (i18n)
1.1 MessageSource接口
java
public interface MessageSource {
String getMessage(String code, Object[] args, String defaultMessage, Locale locale);
String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;
MessageFormatResolvable resolveCode(String code, Locale locale);
}
// ApplicationContext默认实现
public class ApplicationContextExample {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取国际化消息
String message = context.getMessage("user.welcome", new Object[]{"张三"}, Locale.CHINESE);
System.out.println(message); // 输出:欢迎,张三!
String englishMessage = context.getMessage("user.welcome", new Object[]{"John"}, Locale.ENGLISH);
System.out.println(englishMessage); // 输出:Welcome, John!
}
}
1.2 国际化配置文件
properties
# messages_zh.properties
user.welcome=欢迎,{0}!
user.login=用户登录
user.logout=用户登出
# messages_en.properties
user.welcome=Welcome, {0}!
user.login=User Login
user.logout=User Logout
1.3 配置国际化
xml
<!-- applicationContext.xml -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
2. 事件机制 (Event System)
2.1 ApplicationEvent和ApplicationListener
java
// 自定义事件
public class UserRegisteredEvent extends ApplicationEvent {
private final String username;
private final String email;
public UserRegisteredEvent(Object source, String username, String email) {
super(source);
this.username = username;
this.email = email;
}
public String getUsername() { return username; }
public String getEmail() { return email; }
}
// 事件监听器
@Component
public class UserEventListener implements ApplicationListener<UserRegisteredEvent> {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
System.out.println("用户注册事件: " + event.getUsername() + ", 邮箱: " + event.getEmail());
// 发送欢迎邮件
sendWelcomeEmail(event.getEmail());
// 记录用户注册日志
logUserRegistration(event.getUsername());
}
private void sendWelcomeEmail(String email) {
System.out.println("发送欢迎邮件到: " + email);
}
private void logUserRegistration(String username) {
System.out.println("记录用户注册日志: " + username);
}
}
// 发布事件
@Component
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void registerUser(String username, String email) {
// 用户注册逻辑
System.out.println("注册用户: " + username);
// 发布用户注册事件
UserRegisteredEvent event = new UserRegisteredEvent(this, username, email);
eventPublisher.publishEvent(event);
}
}
2.2 事件发布和监听
java
public class EventSystemExample {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
// 注册用户,会触发事件
userService.registerUser("张三", "zhangsan@example.com");
// 输出:
// 注册用户: 张三
// 用户注册事件: 张三, 邮箱: zhangsan@example.com
// 发送欢迎邮件到: zhangsan@example.com
// 记录用户注册日志: 张三
}
}
3. 资源访问 (Resource Access)
3.1 Resource接口体系
java
public interface Resource extends InputStreamSource {
boolean exists();
boolean isReadable();
boolean isOpen();
boolean isFile();
URL getURL() throws IOException;
File getFile() throws IOException;
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
// 各种Resource实现
public class ResourceAccessExample {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 1. 类路径资源
Resource classpathResource = context.getResource("classpath:config.properties");
System.out.println("类路径资源: " + classpathResource.getFilename());
// 2. 文件系统资源
Resource fileResource = context.getResource("file:/path/to/file.txt");
System.out.println("文件资源: " + fileResource.getFilename());
// 3. URL资源
Resource urlResource = context.getResource("https://example.com/api/data");
System.out.println("URL资源: " + urlResource.getDescription());
// 4. 相对路径资源
Resource relativeResource = context.getResource("relative/path");
System.out.println("相对路径资源: " + relativeResource.getFilename());
}
}
3.2 资源加载器
java
public class ResourceLoaderExample {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取ResourceLoader
ResourceLoader resourceLoader = context;
// 加载配置文件
Resource configResource = resourceLoader.getResource("classpath:application.properties");
// 读取配置内容
try (InputStream is = configResource.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println("配置: " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4. 环境配置 (Environment)
4.1 Environment接口
java
public interface Environment extends PropertyResolver {
String[] getActiveProfiles();
String[] getDefaultProfiles();
boolean acceptsProfiles(String... profiles);
boolean acceptsProfiles(Profiles profiles);
}
// 环境配置示例
public class EnvironmentExample {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Environment env = context.getEnvironment();
// 获取激活的Profile
String[] activeProfiles = env.getActiveProfiles();
System.out.println("激活的Profile: " + Arrays.toString(activeProfiles));
// 获取默认Profile
String[] defaultProfiles = env.getDefaultProfiles();
System.out.println("默认Profile: " + Arrays.toString(defaultProfiles));
// 检查是否接受某个Profile
boolean acceptsDev = env.acceptsProfiles("dev");
System.out.println("是否接受dev Profile: " + acceptsDev);
// 获取系统属性
String javaVersion = env.getProperty("java.version");
System.out.println("Java版本: " + javaVersion);
// 获取环境变量
String path = env.getProperty("PATH");
System.out.println("PATH环境变量: " + path);
}
}
4.2 Profile配置
java
@Configuration
public class AppConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
return new DriverManagerDataSource("jdbc:h2:mem:devdb");
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
return new DriverManagerDataSource("jdbc:mysql://localhost:3306/proddb");
}
@Bean
@Profile("test")
public DataSource testDataSource() {
return new DriverManagerDataSource("jdbc:h2:mem:testdb");
}
}
// 激活Profile
public class ProfileActivationExample {
public static void main(String[] args) {
// 方式1:通过系统属性
System.setProperty("spring.profiles.active", "dev");
// 方式2:通过环境变量
// export SPRING_PROFILES_ACTIVE=dev
// 方式3:通过代码
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev");
context.register(AppConfig.class);
context.refresh();
// 根据Profile创建不同的Bean
DataSource dataSource = context.getBean(DataSource.class);
System.out.println("数据源类型: " + dataSource.getClass().getSimpleName());
}
}
5. AOP支持 (Aspect-Oriented Programming)
5.1 AOP配置
java
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
@Bean
public LoggingAspect loggingAspect() {
return new LoggingAspect();
}
}
// 切面类
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
System.out.println("执行方法: " + className + "." + methodName);
}
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("方法 " + methodName + " 执行完成,返回值: " + result);
}
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "error")
public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
String methodName = joinPoint.getSignature().getName();
System.out.println("方法 " + methodName + " 执行异常: " + error.getMessage());
}
}
// 服务类
@Service
public class UserService {
public String getUserInfo(String userId) {
System.out.println("获取用户信息: " + userId);
return "用户信息: " + userId;
}
public void updateUser(String userId) {
System.out.println("更新用户: " + userId);
if ("error".equals(userId)) {
throw new RuntimeException("更新用户失败");
}
}
}
5.2 AOP使用示例
java
public class AopExample {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class);
UserService userService = context.getBean(UserService.class);
// 正常执行
String result = userService.getUserInfo("123");
// 异常执行
try {
userService.updateUser("error");
} catch (Exception e) {
// 异常会被切面捕获
}
// 输出:
// 执行方法: UserService.getUserInfo
// 获取用户信息: 123
// 方法 getUserInfo 执行完成,返回值: 用户信息: 123
// 执行方法: UserService.updateUser
// 更新用户: error
// 方法 updateUser 执行异常: 更新用户失败
}
}
6. 事务管理 (Transaction Management)
6.1 事务配置
java
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
// 事务服务
@Service
@Transactional
public class TransactionalUserService {
@Autowired
private UserDao userDao;
@Autowired
private EmailService emailService;
@Transactional(rollbackFor = Exception.class)
public void createUserWithEmail(String username, String email) {
try {
// 创建用户
userDao.createUser(username, email);
// 发送欢迎邮件
emailService.sendWelcomeEmail(email);
System.out.println("用户创建成功: " + username);
} catch (Exception e) {
System.out.println("用户创建失败,事务回滚: " + e.getMessage());
throw e; // 抛出异常触发回滚
}
}
@Transactional(readOnly = true)
public String getUserInfo(String username) {
return userDao.getUserInfo(username);
}
}
6.2 事务使用示例
java
public class TransactionExample {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(TransactionConfig.class);
TransactionalUserService userService = context.getBean(TransactionalUserService.class);
// 正常事务
try {
userService.createUserWithEmail("张三", "zhangsan@example.com");
} catch (Exception e) {
System.out.println("事务执行失败");
}
// 只读事务
String userInfo = userService.getUserInfo("张三");
System.out.println("用户信息: " + userInfo);
}
}
7. 缓存支持 (Caching)
7.1 缓存配置
java
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new ConcurrentMapCache("users"),
new ConcurrentMapCache("orders")
));
return cacheManager;
}
}
// 缓存服务
@Service
public class CachedUserService {
@Cacheable(value = "users", key = "#username")
public String getUserInfo(String username) {
System.out.println("从数据库查询用户: " + username);
// 模拟数据库查询
return "用户信息: " + username + " (从数据库查询)";
}
@CacheEvict(value = "users", key = "#username")
public void updateUser(String username) {
System.out.println("更新用户: " + username);
// 更新后清除缓存
}
@CachePut(value = "users", key = "#username")
public String refreshUserInfo(String username) {
System.out.println("刷新用户信息: " + username);
return "用户信息: " + username + " (已刷新)";
}
}
7.2 缓存使用示例
java
public class CacheExample {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(CacheConfig.class);
CachedUserService userService = context.getBean(CachedUserService.class);
// 第一次调用,会查询数据库
String userInfo1 = userService.getUserInfo("张三");
System.out.println(userInfo1);
// 第二次调用,从缓存获取
String userInfo2 = userService.getUserInfo("张三");
System.out.println(userInfo2);
// 更新用户,清除缓存
userService.updateUser("张三");
// 再次调用,重新查询数据库
String userInfo3 = userService.getUserInfo("张三");
System.out.println(userInfo3);
// 输出:
// 从数据库查询用户: 张三
// 用户信息: 张三 (从数据库查询)
// 用户信息: 张三 (从数据库查询)
// 更新用户: 张三
// 从数据库查询用户: 张三
// 用户信息: 张三 (从数据库查询)
}
}
8. 配置属性绑定 (Configuration Properties)
8.1 配置属性类
java
@ConfigurationProperties(prefix = "app")
@Component
public class AppProperties {
private String name;
private String version;
private Database database = new Database();
private Email email = new Email();
// getter和setter方法
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public Database getDatabase() { return database; }
public void setDatabase(Database database) { this.database = database; }
public Email getEmail() { return email; }
public void setEmail(Email email) { this.email = email; }
public static class Database {
private String url;
private String username;
private String password;
// getter和setter方法
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
public static class Email {
private String host;
private int port;
private String username;
private String password;
// getter和setter方法
public String getHost() { return host; }
public void setHost(String host) { this.host = host; }
public int getPort() { return port; }
public void setPort(int port) { this.port = port; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
}
8.2 配置文件
yaml
# application.yml
app:
name: My Application
version: 1.0.0
database:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: password
email:
host: smtp.gmail.com
port: 587
username: myapp@gmail.com
password: mypassword
8.3 配置属性使用
java
@Configuration
@EnableConfigurationProperties
public class AppConfig {
@Bean
public DataSource dataSource(AppProperties appProperties) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(appProperties.getDatabase().getUrl());
dataSource.setUsername(appProperties.getDatabase().getUsername());
dataSource.setPassword(appProperties.getDatabase().getPassword());
return dataSource;
}
@Bean
public JavaMailSender mailSender(AppProperties appProperties) {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(appProperties.getEmail().getHost());
mailSender.setPort(appProperties.getEmail().getPort());
mailSender.setUsername(appProperties.getEmail().getUsername());
mailSender.setPassword(appProperties.getEmail().getPassword());
return mailSender;
}
}
// 使用配置属性
@Component
public class AppInfoService {
@Autowired
private AppProperties appProperties;
public void printAppInfo() {
System.out.println("应用名称: " + appProperties.getName());
System.out.println("应用版本: " + appProperties.getVersion());
System.out.println("数据库URL: " + appProperties.getDatabase().getUrl());
System.out.println("邮件服务器: " + appProperties.getEmail().getHost());
}
}
ApplicationContext的继承体系
java
BeanFactory (根接口)
↓
HierarchicalBeanFactory (支持父子容器)
↓
ConfigurableBeanFactory (可配置的BeanFactory)
↓
AutowireCapableBeanFactory (支持自动装配)
↓
AbstractBeanFactory (抽象实现)
↓
DefaultListableBeanFactory (默认实现)
↓
ApplicationContext (企业级容器接口)
↓
ConfigurableApplicationContext (可配置的ApplicationContext)
↓
AbstractApplicationContext (抽象实现)
↓
具体实现类 (ClassPathXmlApplicationContext, AnnotationConfigApplicationContext等)