Spring容器接口
Spring是Java的春天 人气:01.容器接口有哪些
在Spring中,容器接口有BeanFactory 接口和ApplicationContext 接口
其继承关系如下(Ctrl + alt + u)
由这个继承关系图可以看出,ApplicationContext 接口是 BeanFactory 的子接口。它扩展了 BeanFactory 接口的功能
而BeanFactory 才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能
那么在哪里可以看见ApplicationContext 类呢?
就在SpringBoot的启动类中可以看见
@SpringBootApplication @MapperScan("com.lingnan.mapper") public class TestSpringbootApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(TestSpringbootApplication.class, args); } }
SpringApplication.run()方法的返回值,则是ApplicationContext 的子类ConfigurableApplicationContext,也就是Spring容器
使用debug模式,可以清晰看见ApplicationContext 里面有BeanFactory ,并且BeanFactory 有很多单例
2.BeanFactory能干嘛
使用快捷键Ctrl + n查找BeanFactory,然后使用Ctrl + F12即可查看BeanFactory的方法
可以看到,BeanFactory接口的方法看起来并不多,只有getBean
实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供
3.ApplicationContext有哪些扩展功能
通过前面的ApplicationContext 的继承关系图,不难看出,ApplicationContext 比BeanFactory多继承了MessageSource、ResourcePatternResolver、EnvironmentCapable、ApplicationEventPublisher这几个接口
这几个接口也就是ApplicationEventPublisher的扩展功能
MessageSource接口是用来提供处理国际化资源的能力,可以识别多国语言,相当于翻译
ResourcePatternResolver接口提供的是通配符匹配资源(磁盘或者类路径下的文件)的能力
ApplicationEventPublisher接口则是可以用来发布事件对象
EnvironmentCapable接口提供了读取Spring的一些环境信息的能力
3.1 MessageSource
MessageSource提供了getMessage方法,可以将语言翻译成不同国家的语言
System.out.println(context.getMessage("hi", null, Locale.CHINA)); System.out.println(context.getMessage("hi", null, Locale.ENGLISH)); System.out.println(context.getMessage("hi", null, Locale.JAPANESE));
这里就能将hi翻译成中文、英语、日语
因为这个项目下提供了三个不同的文件,就会根据里面的键值对转化为对应的语言
3.2 ResourcePatternResolver
ResourcePatternResolver提供了getResources方法,可以根据路径或者通配符获取多个资源
public interface ResourcePatternResolver extends ResourceLoader { String CLASSPATH_ALL_URL_PREFIX = "classpath*:"; Resource[] getResources(String locationPattern) throws IOException; }
当然根据ResourcePatternResolver的父接口ResourceLoader,可以发现也可以获取单个资源
public interface ResourceLoader { String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX; Resource getResource(String location); e org.springframework.util.ClassUtils#forName(String, ClassLoader) */ @Nullable ClassLoader getClassLoader(); }
下面举个栗子
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories"); for (Resource resource : resources) { System.out.println(resource); }
classpath是指当前类路径下(在jar包的话就需要像上面这样加*),而Resource是Spring中对资源的抽象
3.3 EnvironmentCapable
EnvironmentCapable提供了getEnvironment方法,获取当前Spring的配置信息(环境变量、application.properties等)
public interface EnvironmentCapable { /** * Return the {@link Environment} associated with this component. */ Environment getEnvironment(); }
可以借助Environment的父接口PropertyResolver提供的getProperty方法获取某个配置信息
public interface Environment extends PropertyResolver { String[] getActiveProfiles(); String[] getDefaultProfiles(); @Deprecated boolean acceptsProfiles(String... profiles); boolean acceptsProfiles(Profiles profiles); }
举个栗子
System.out.println(context.getEnvironment().getProperty("java_home")); System.out.println(context.getEnvironment().getProperty("server.port"));
这样就能获取到环境变量和server.port端口号了
3.4 ApplicationEventPublisher
ApplicationEventPublisher的作用是用来发布事件的
@FunctionalInterface public interface ApplicationEventPublisher { default void publishEvent(ApplicationEvent event) { publishEvent((Object) event); } void publishEvent(Object event); }
ApplicationEventPublisher提供了一个publishEvent方法用来发布事件
而事件则需要继承ApplicationEvent,source代表事件源,也就是谁发的事件
public class UserRegisteredEvent extends ApplicationEvent { public UserRegisteredEvent(Object source) { super(source); } }
然后就可以调用publishEvent来发送事件,参数为context,因为context是事件源,也就是context发的事件
context.publishEvent(new UserRegisteredEvent(context));
除了发事件,还应该有收事件的东西,也就是监听器
Spring中任何一个类都可以作为监听器
需要加上 @EventListener注解
然后参数为事件,也就是发的事件是什么类型,接收的事件也应该是什么类型
@Component public class Component2 { private static final Logger log = LoggerFactory.getLogger(Component2.class); @EventListener public void aaa(UserRegisteredEvent event) { log.debug("{}", event); log.debug("发送短信"); } }
这样就可以了,其实这种操作很像mq,可以用来异步处理某些业务
比如我这里有一个注册方法,然后异步需要发送短信,那么发布事件之后,aaa方法就会异步执行
@Component public class Component1 { private static final Logger log = LoggerFactory.getLogger(Component1.class); @Autowired private ApplicationEventPublisher context; public void register() { log.debug("用户注册"); context.publishEvent(new UserRegisteredEvent(this)); } }
加载全部内容