【附录】相对于BeanFactory ,ApplicationContext 做了哪些企业化的增强?

此文是【Spring 容器详解】的支节点。

ApplicationContext是BeanFactory的子接口,它在BeanFactory的基础上提供了大量企业级功能。相对于BeanFactory的轻量级设计,ApplicationContext是一个功能丰富的企业级容器,为Spring应用提供了完整的框架支持。

ApplicationContext相对于BeanFactory的企业化增强主要包括:

  1. 国际化支持
  2. 事件机制
  3. 资源访问
  4. 环境配置
  5. AOP支持
  6. 事务管理
  7. 缓存支持
  8. 配置属性绑定

下面通过代码示例详细介绍这些企业化增强功能。

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等)
相关推荐
爱勇宝1 小时前
第 1 章:别把“需求文档”当成真正的需求
前端·后端·程序员
IT_陈寒6 小时前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码7 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo7 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志8 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..8 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects8 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰8 小时前
一些基础和问题解决
后端
陈随易8 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN8 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp