ApplicationContextAware
是Spring容器提供用于初始化Bean的一个入口,通常情况下我们所有的Bean的生命周期都是交给Spring容器去管理,如实例化,初始化,销毁等。
根据官方文档介绍,:
- 实现该接口之后,在容器启动时,BeanFactory 就是自动通知我们实现类去完成一系列操作。
- 实现该接口之后,我们可以在容器启动时,能够很便利的去获取到我们需要的Bean,当然,如果是为了设置类似于依赖Bean的话,Spring是不推荐实现该接口的,应该交给Spring去帮助我们加载依赖的Bean,如通过依赖注入
@Autowired
的方式。 - Spring 还给我们提供了一个该接口的抽象实现类,其实我们可以直接继承该抽象实现类
ApplicationObjectSupport
,完成我们的想要的功能。
ApplicationContextAware
接口定义如下:
public interface ApplicationContextAware extends Aware {
/**
* 在容器启动阶段,设置 {@link ApplicationContext},通常情况下,该方法用于初始化Bean实例。
* 该方法会在创建Bean的实例之后填充阶段调用({@link AbstractAutowireCapableBeanFactory#populateBean}),
* 但是会在Bean实例的{@code init} 之前调用
*
* @param applicationContext Spring容器
*/
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
该接口有什么用处呢?
在项目开发中,我们肯定会碰到一个接口有多个实现的情况,如何在运行时能够自动获取到对应的实现类,并完成我们的业务逻辑。而ApplicationContextAware
接口中的setApplicationContext(ApplicationContext applicationContext)
方法可以让我们获取到Spring容器对象,再通过Spring容器就可以拿到我们所有的业务Bean的实例。
如果我们只是仅仅采用if-else
的方式,最大的缺点就是扩展性太差,违背了开闭原则(对扩展开放,对修改关闭),每增加一个实现类,我们就需要去修改if-else
中的判断,当业务越来越庞大,我们就需要一直去修改这段逻辑,后果可想而知,所以我们可以通过实现该接口的方式,在容器启动阶段,自己将这些实现类管理起来,然后在运行时自动去获取到对应的实现类,就可以很好的解决这个问题。
如:现在我们有一个支付接口,可以支持多种方式的支付,包括支付宝支付,微信支付,信用卡支付。支付接口如下:
public interface PaymentApi {
/**
* 支付
*/
void pay();
/**
* 支付类型
*
* @return 支付类型
*/
PayType getPayType();
}
实现类为下:
/**
* 支付宝支付
*/
@Component
public class AliPayImpl implements PaymentApi {
@Override
public void pay() {
System.out.println("支付宝支付......");
}
@Override
public PayType getPayType() {
return PayType.ALI_PAY;
}
}
/**
* 微信支付
*/
@Component
public class WeChatPayImpl implements PaymentApi {
@Override
public void pay() {
System.out.println("微信支付......");
}
@Override
public PayType getPayType() {
return PayType.WE_CHAT;
}
}
自定义的ApplicationContextAware
如下:
/**
* 容器启动时,将所有实现了 {@link PaymentApi} 的实现类装载到 {@link #PAYMENT_MAP} 容器中,
* 我们只需要根据类型{@link PayType}就能拿到具体的实现类,从而实现一个接口多个实现动态调用
*/
@Component
public class PaymentAware implements ApplicationContextAware {
private ApplicationContext applicationContext;
/**
* 所有支付方法的实现类
*/
private static final Map<PayType, PaymentApi> PAYMENT_MAP = new HashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
// 准备 PaymentApi 的所有实现类
preparePaymentMethods();
}
private void preparePaymentMethods() {
// 获取容器中所有支付方式的实现类
Map<String, PaymentApi> paymentApiList = this.applicationContext.getBeansOfType(PaymentApi.class);
paymentApiList.forEach((key, value) -> {
PAYMENT_MAP.put(value.getPayType(), value);
});
}
public static PaymentApi getPayment(PayType type) {
return PAYMENT_MAP.get(type);
}
}
然后我们调用的时候就可以调用getPayment
拿到对应的实现类完成我们的业务逻辑,再也不用去写和修改if-else
了。
测试类如下:
public class PaymentTest {
@Test
public void testPayment() {
// 容器启动
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationContextAwareConfig.class);
// 根据类型获取到对应实现类
PaymentApi paymentApi = PaymentAware.getTransportation(PayType.ALI_PAY);
// 执行对应实现类的方法
paymentApi.pay();
}
}
控制台就会输出支付宝支付......