【附录】相对于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等)
相关推荐
小奏技术17 分钟前
从零到一打造一款提升效率的IDEA插件-根据java doc自动生成枚举代码
后端·intellij idea
PetterHillWater1 小时前
Kimi-K2模型真实项目OOP重构实践
后端·aigc
Moonbit1 小时前
月报 Vol.02:新增条件编译属性 cfg、#alias属性、defer表达式,增加 tuple struct 支持
后端·程序员·编程语言
Ray661 小时前
AviatorScript 表达式引擎
后端
右手嘚温暖2 小时前
SpringMvc的原理深度剖析及源码解读
spring·开源·mvc
回家路上绕了弯2 小时前
深度理解 Lock 与 ReentrantLock:Java 并发编程的高级锁机制
java·后端
期待のcode3 小时前
SpringAOP
java·开发语言·spring
Captaincc3 小时前
TRAE 首场 Meetup:8月16日,期待与你在北京相聚
前端·后端·trae
肩塔didi3 小时前
用 Pixi 管理 Python 项目:打通Conda 和 PyPI 的边界
后端·python·github