2

ApplicationContext

上下文,这是一个比BeanFactory功能更加强大的容器,但是具体ApplicationContext都有些什么强大的功能呢?一起来看看吧。

clipboard.png

其实看ApplicationContext所继承的接口,就能明白都有些什么功能,这里说一说我觉得比较重要的一个功能——ApplicationEventPublisher:程序事件发布。

监听容器启动

通俗来说就是我这个容器运行时会发布一些事件,然后我们可以对这些容器发布的事件进行监听。

@Component
public class TestListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        System.out.println("我是一个监听程序启动的方法");
    }
}

@ComponentScan("com.mengyunzhi.spring")
public class Application {

    public static void main(String []args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
    }
}

ApplicationListener,函数式接口,用于监听某个继承自ApplicationEvent类型的事件,当该事件发布时,执行我们实现的onApplicationEvent方法。

除了我们使用的事件ContextRefreshedEvent容器初始化或刷新之外,还有ContextClosedEvent容器即将关闭,RequestHandledEvent 请求处理后发布的事件。

clipboard.png

运行结果:

clipboard.png

监听器执行顺序

可以实现Spring提供的Ordered接口,实现其生命的getOrder方法,返回的值越小表示执行越靠前。

clipboard.png

@Component
public class TestListener implements ApplicationListener<ContextRefreshedEvent>, Ordered {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        System.out.println("我是一个监听程序启动的方法");
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

@Component
public class NewListener implements ApplicationListener<ContextRefreshedEvent>, Ordered {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        System.out.println("我是一个新的监听方法");
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}

运行结果:

clipboard.png

自动装配

Autowired

熟悉不过的自动装配,@Autowired注解的本质是根据Bean的类型进行装配,就是旧版本Spring中的ByType方式。

@Autowired
private TestService testService;

声明需要一个TestService类型的对象,然后Spring会在上下文中寻找符合条件的Bean,并未我们注入进来。

Qualifier

而如果一个接口有多个实现,在上下文中就会有多个符合该条件的Bean,所以我们就需要对注入的Bean进行ByName声明,根据Bean的名称进行注入。使用注解@Qualifier进行根据名称的装配。

现在实现类上为该组件声明一个名称,或者在xml配置中为该Bean配置名称。

@Service("TestServiceImpl")
public class TestServiceImpl implements TestService {

    @Override
    public void show() {
        System.out.println("我是TestServiceImpl, TestService的实现");
    }
}

@Service("NewTestServiceImpl")
public class NewTestServiceImpl implements TestService {

    @Override
    public void show() {
        System.out.println("我是NewTestServiceImpl, 也是TestService的实现");
    }
}

clipboard.png

运行结果:

clipboard.png

Primary

如果我们一个接口有多个实现类,但是98%的业务环境下都需要注入我们的NewTestServiceImpl实例,我们不愿意写那么多的Qualifier,所以我们可以声明某个类为Primary而被优先注入。极少数情况下需要别的实例的话再去Qualifier声明。

@Primary
@Service("NewTestServiceImpl")
public class NewTestServiceImpl implements TestService {

    @Override
    public void show() {
        System.out.println("我是NewTestServiceImpl, 也是TestService的实现");
    }
}

运行结果:

clipboard.png

Bean的方法

某些业务环境,可能一个Bean在执行完构造函数之后还不能被使用,还需要执行一些初始化操作,毕竟优雅的代码应该把对象的构造与初始化分开。

@Service
public class NewTestServiceImpl implements TestService {

    @PostConstruct
    public void init() {
        System.out.println("我是init方法,我初始化NewTestServiceImpl");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("我是destroy方法,我销毁NewTestServiceImpl");
    }
}

使用@PostConstruct标注在对象创造之后执行的初始化操作,使用@PreDestroy标注在对象销毁之前执行的销毁逻辑。

ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
((AnnotationConfigApplicationContext) context).close();

运行结果:

clipboard.png


张喜硕
2.1k 声望423 粉丝

浅梦辄止,书墨未浓。