【附录】相对于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等)
相关推荐
北城以北888833 分钟前
Spring定时任务与Spring MVC拦截器
spring boot·spring·mvc
Victor35641 分钟前
Netty(20)如何实现基于Netty的WebSocket服务器?
后端
缘不易41 分钟前
Springboot 整合JustAuth实现gitee授权登录
spring boot·后端·gitee
Kiri霧1 小时前
Range循环和切片
前端·后端·学习·golang
WizLC1 小时前
【Java】各种IO流知识详解
java·开发语言·后端·spring·intellij idea
Mr.朱鹏1 小时前
SQL深度分页问题案例实战
java·数据库·spring boot·sql·spring·spring cloud·kafka
星星不打輰1 小时前
SSM项目--SweetHouse 甜蜜蛋糕屋
java·spring·mybatis·ssm·springmvc
Victor3561 小时前
Netty(19)Netty的性能优化手段有哪些?
后端
爬山算法1 小时前
Netty(15)Netty的线程模型是什么?它有哪些线程池类型?
java·后端
白宇横流学长2 小时前
基于SpringBoot实现的冬奥会科普平台设计与实现【源码+文档】
java·spring boot·后端