手把手玩转Spring 之 ApplicationContextAware

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();
    }
}

控制台就会输出支付宝支付......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值