ApplicationContext
上下文,这是一个比BeanFactory
功能更加强大的容器,但是具体ApplicationContext
都有些什么强大的功能呢?一起来看看吧。
其实看ApplicationContext
所继承的接口,就能明白都有些什么功能,这里说一说我觉得比较重要的一个功能——ApplicationEventPublisher
:程序事件发布。
监听容器启动
通俗来说就是我这个容器运行时会发布一些事件,然后我们可以对这些容器发布的事件进行监听。
@Component
public class TestListener implements ApplicationListener {
@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
请求处理后发布的事件。
运行结果:
监听器执行顺序
可以实现Spring
提供的Ordered
接口,实现其生命的getOrder
方法,返回的值越小表示执行越靠前。
@Component
public class TestListener implements ApplicationListener, Ordered {
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("我是一个监听程序启动的方法");
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
@Component
public class NewListener implements ApplicationListener, Ordered {
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("我是一个新的监听方法");
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
运行结果:
自动装配
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的实现");
}
}
运行结果:
Primary
如果我们一个接口有多个实现类,但是98%
的业务环境下都需要注入我们的NewTestServiceImpl
实例,我们不愿意写那么多的Qualifier
,所以我们可以声明某个类为Primary
而被优先注入。极少数情况下需要别的实例的话再去Qualifier
声明。
@Primary
@Service("NewTestServiceImpl")
public class NewTestServiceImpl implements TestService {
@Override
public void show() {
System.out.println("我是NewTestServiceImpl, 也是TestService的实现");
}
}
运行结果:
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();
运行结果: