
 
文章目录
- Instantiate(实例化)
- Populate properties(填充属性)
- BeanNameAware's setBeanName()
- BeanFactoryAware's setBeanFactory()
- ApplicationContextAware's setApplicationContext()
- Pre-initialization BeanPostProcessors
- InitializingBean's afterPropertiesSet()
- Call custom init-method
- Post-initialization BeanPostProcessors
 
虽然关于Spring中Bean的创建过程的资料很多,但却很少说为什么要划分这些阶段,以及这些阶段划分处理后在开发中可以用来做什么。通过GPT,这里给出了各个阶段的作用,并通过例子帮助理解。
假设我们正在开发一个电子商务系统,其中包含一个OrderService来处理订单。我们将逐步展示每个阶段如何在这个服务的生命周期中发挥作用。
Instantiate(实例化)
public class OrderService {
    private ProductRepository productRepository;
    private UserRepository userRepository;
    private PaymentGateway paymentGateway;
    private OrderRepository orderRepository;
    // 其他属性和方法
}
在这个阶段,Spring 仅仅创建了 OrderService 的一个空实例。这是必要的第一步,因为它为后续的配置和自定义提供了基础。
Populate properties(填充属性)
@Autowired
public void setProductRepository(ProductRepository productRepository) {
    this.productRepository = productRepository;
}
@Autowired
public void setUserRepository(UserRepository userRepository) {
    this.userRepository = userRepository;
}
@Autowired
public void setPaymentGateway(PaymentGateway paymentGateway) {
    this.paymentGateway = paymentGateway;
}
@Autowired
public void setOrderRepository(OrderRepository orderRepository) {
    this.orderRepository = orderRepository;
}
在这个阶段,Spring 注入所有必要的依赖。这个阶段的重要性在于它允许我们灵活地配置依赖关系。例如,我们可以轻松地在测试环境中注入模拟对象,而在生产环境中注入实际实现,而无需修改 OrderService 的代码。
BeanNameAware’s setBeanName()
public class OrderService implements BeanNameAware {
    private String serviceName;
    @Override
    public void setBeanName(String name) {
        this.serviceName = name;
    }
    public void logOrderProcess(Order order) {
        Logger.info("[" + serviceName + "] Processing order: " + order.getId());
    }
}
这个阶段允许 OrderService 知道自己在 Spring 容器中的名称。在本例中,我们使用它来增强日志信息,使得在分布式系统中更容易追踪订单处理过程。
BeanFactoryAware’s setBeanFactory()
public class OrderService implements BeanFactoryAware {
    private BeanFactory beanFactory;
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
    public void processOrder(Order order) {
        // 根据订单类型动态选择合适的支付处理器
        PaymentProcessor processor = (PaymentProcessor) beanFactory.getBean(order.getPaymentMethod() + "PaymentProcessor");
        processor.process(order.getPayment());
    }
}
这个阶段使 OrderService 能够访问 BeanFactory,从而实现了动态选择支付处理器的功能。这种灵活性对于处理不同类型的支付方式(如信用卡、PayPal、银行转账等)非常有用。
ApplicationContextAware’s setApplicationContext()
public class OrderService implements ApplicationContextAware {
    private ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
    public void initializeService() {
        Environment env = context.getEnvironment();
        String region = env.getProperty("app.region");
        if ("US".equals(region)) {
            // 使用美国特定的税收计算逻辑
        } else if ("EU".equals(region)) {
            // 使用欧盟特定的税收计算逻辑
        }
    }
}
通过 ApplicationContext,OrderService 可以访问环境配置,从而根据不同的地区应用不同的业务逻辑,如税收计算方式。
Pre-initialization BeanPostProcessors
这个阶段允许我们在 Bean 的其他初始化方法之前修改 Bean 或其代理。这对于需要在初始化之前进行的设置或修改特别有用。
例子:安全检查和审计日志
@Component
public class SecurityAuditBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof TransactionService) {
            TransactionService service = (TransactionService) bean;
            // 在bean初始化之前进行安全检查
            if (!SecurityContext.isInitialized()) {
                throw new SecurityException("Security context must be initialized before TransactionService");
            }
            // 添加审计日志
            AuditLogger.log("TransactionService is being initialized");
            
            // 返回一个代理对象,用于后续的方法调用
            return Proxy.newProxyInstance(
                bean.getClass().getClassLoader(),
                bean.getClass().getInterfaces(),
                new SecurityAuditInvocationHandler(service)
            );
        }
        return bean;
    }
}
这个例子展示了如何在 TransactionService 初始化之前进行安全检查和审计日志记录。这种操作必须在其他初始化步骤之前进行,以确保系统的安全性。
InitializingBean’s afterPropertiesSet()
这个方法在所有属性设置完成后调用,适合用于基于这些属性的初始化逻辑。
例子:连接池初始化
public class TransactionService implements InitializingBean {
    @Autowired
    private DataSource dataSource;
    
    private Connection connection;
    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化数据库连接
        this.connection = dataSource.getConnection();
        
        // 设置连接属性
        this.connection.setAutoCommit(false);
        this.connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
        
        // 验证连接
        if (!this.connection.isValid(5000)) {
            throw new IllegalStateException("Failed to establish a valid database connection");
        }
    }
}
这个方法确保在 TransactionService 使用之前,数据库连接已经正确设置和验证。这种初始化逻辑依赖于已注入的 dataSource,因此必须在属性填充之后执行。
Call custom init-method
自定义初始化方法提供了更大的灵活性,允许开发者定义特定的初始化逻辑,而不需要实现 InitializingBean 接口。
例子:缓存预热
public class TransactionService {
    @Autowired
    private TransactionRepository repository;
    
    private Cache<String, Transaction> transactionCache;
    @PostConstruct
    public void initCache() {
        // 初始化缓存
        this.transactionCache = CacheBuilder.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build();
        // 预热缓存
        List<Transaction> recentTransactions = repository.getRecentTransactions(100);
        for (Transaction tx : recentTransactions) {
            this.transactionCache.put(tx.getId(), tx);
        }
    }
}
这个自定义初始化方法用于设置和预热缓存。这种操作不适合放在 afterPropertiesSet() 中,因为它是特定于应用的逻辑,而不是通用的初始化。
Post-initialization BeanPostProcessors
这个阶段允许我们在 Bean 完全初始化后进行最终的修改或增强。
例子:事务管理和性能监控
@Component
public class TransactionManagementBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof TransactionService) {
            return Proxy.newProxyInstance(
                bean.getClass().getClassLoader(),
                bean.getClass().getInterfaces(),
                new TransactionManagementInvocationHandler((TransactionService) bean)
            );
        }
        return bean;
    }
}
class TransactionManagementInvocationHandler implements InvocationHandler {
    private final TransactionService target;
    private final PerformanceMonitor performanceMonitor;
    TransactionManagementInvocationHandler(TransactionService target) {
        this.target = target;
        this.performanceMonitor = new PerformanceMonitor();
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.isAnnotationPresent(Transactional.class)) {
            return executeInTransaction(method, args);
        }
        return method.invoke(target, args);
    }
    private Object executeInTransaction(Method method, Object[] args) throws Throwable {
        TransactionStatus status = null;
        try {
            status = TransactionManager.begin();
            long start = System.nanoTime();
            Object result = method.invoke(target, args);
            long end = System.nanoTime();
            TransactionManager.commit(status);
            performanceMonitor.record(method.getName(), end - start);
            return result;
        } catch (Exception e) {
            if (status != null) {
                TransactionManager.rollback(status);
            }
            throw e;
        }
    }
}
这个后处理器在 TransactionService 完全初始化后添加了事务管理和性能监控功能。这必须在最后执行,以确保它能捕获到所有可能的方法调用,包括在之前阶段添加的方法。
后面四个阶段看上去可以合在一起,但它们也有各自的重要性:
- Pre-initialization BeanPostProcessors 用于在任何初始化发生之前进行必要的检查或修改。
- InitializingBean’s afterPropertiesSet() 用于基于注入的依赖进行初始化。
- Custom init-method 提供了一种更灵活的方式来定义特定于应用的初始化逻辑。
- Post-initialization BeanPostProcessors 用于在 Bean 完全准备好之后添加额外的行为或增强。
这种分层方法允许开发者在 Bean 生命周期的不同点进行干预,提供了极大的灵活性和可扩展性。它使得框架和应用代码可以清晰地分离关注点,同时仍然允许它们在必要时进行交互。这种设计使得 Spring 能够支持各种复杂的场景,同时保持代码的模块化和可维护性。


















