AnnotationConfigWebApplicationContext
AnnotationConfigWebApplicationContext-->WebApplicationContext-->ApplicationContext
核心方法:loadBeanDefinitions
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
//加载Bean
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
//扫描注解
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
//装配Bean
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
//注册Bean
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
if (!this.annotatedClasses.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Registering annotated classes: [" +
StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
}
//注册Bean
reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
if (!this.basePackages.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
//扫描指定基包
scanner.scan(StringUtils.toStringArray(this.basePackages));
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
if (logger.isTraceEnabled()) {
logger.trace("Registering [" + configLocation + "]");
}
reader.register(clazz);
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not load class for config location [" + configLocation +
"] - trying package scan. " + ex);
}
int count = scanner.scan(configLocation);
if (count == 0 && logger.isDebugEnabled()) {
logger.debug("No annotated classes found for specified class/package [" + configLocation + "]");
}
}
}
}
}
BeanPostProcessor(后置处理器)
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
在上面的context中随处可见对BeanPostProcessor的方法调用,用于检查标记接口或用代理封装,在Bean对象在实例化和依赖注入完毕后调用,第三方扩展功能均会实现此接口,在Bean的初始化时,通过InitializingBean来调用afterPropertiesSet方法。
ApplicationContextAware
在某些特殊的情况下,Bean需要实现某个功能,但该功能必须借助于Spring容器才能实现,此时就必须让该Bean先获取Spring容器,然后借助于Spring容器实现该功能。为了让Bean获取它所在的Spring容器,可以让该Bean实现ApplicationContextAware接口。ApplicationContextAware 通过它Spring容器会自动把上下文环境对象调用ApplicationContextAware接口中的setApplicationContext方法。在ApplicationContextAware的实现类中,就可以通过这个上下文环境对象得到Spring容器中的Bean。看到—Aware就知道是干什么的了,就是属性注入的,但是这个ApplicationContextAware的不同地方在于,实现了这个接口的bean,当spring容器初始化的时候,会自动的将ApplicationContext注入进来。
public interface ApplicationContextAware extends Aware {
/*
设置此对象在其中运行的ApplicationContext。通常,此调用将用于初始化对象。
*/
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
//setContext
applicationContext = context;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//获取Bean
public static <T> T getBean(Class<T> requiredType){
return getApplicationContext().getBean(requiredType);
}
public static <T> T getBean(String name){
return (T) getApplicationContext().getBean(name);
}
}
ResourceLoaderAware
ResourceLoaderAware是特殊的标记接口,它希望拥有一个ResourceLoader 引用的对象。
public interface ResourceLoaderAware {
void setResourceLoader(ResourceLoader resourceLoader);
}
当实现了 ResourceLoaderAware接口的类部署到application context(比如受Spring管理的bean)中时,它会被application context识别为 ResourceLoaderAware。 接着application context会调用setResourceLoader(ResourceLoader)方法,并把自身作为参数传入该方法(记住,所有Spring里的application context都实现了ResourceLoader接口)。
既然 ApplicationContext 就是ResourceLoader,那么该bean就可以实现 ApplicationContextAware接口并直接使用所提供的application context来载入资源,但是通常更适合使用特定的满足所有需要的 ResourceLoader实现。 这样一来,代码只需要依赖于可以看作辅助接口的资源载入接口,而不用依赖于整个Spring ApplicationContext 接口。
从Spring 2.5开始, 你可以使用ResourceLoader 的自动装配来代替实现 ResourceLoaderAware 接口。“传统的” constructor及 byType的自动装配模式 (第 3.3.5 节 “自动装配(autowire)协作者”已有论述)现在可以分别为构造方法参数及setter方法参数提供 ResourceLoader 类型的依赖。请使用新式的基于注解的自动装配特性以提供更大的灵活性(包括装配属性及多个方法参数的能力)。在这种情况下,只要属性、构造方法或者方法被 @Autowired注解修饰,ResourceLoader 就会被装配到需要ResourceLoader类型的属性、构造方法参数或者方法参数中
Servlet与HttpServlet
类图标明很是明显,在这个图中展示了servlet,tomcat,Springboot的关系,完美解释了那句Springboot是内嵌了tomcat的嵌入式引擎,嵌入式容器的说法~
而HttpServlet即是大部分请求的处理对象,嵌入式引擎---->嵌入式容器---->webfilter---->weblistener
javax.servlet.ServletContext#addServlet(java.lang.String, java.lang.Class<? extends javax.servlet.Servlet>)返回一个ServletRegistration对象,可用于进一步
配置已注册的servlet
javax.servlet.ServletRegistration
public interface ServletRegistration extends Registration {
/**
* TODO
* @param urlPatterns The URL patterns that this Servlet should be mapped to
* @return TODO
* @throws IllegalArgumentException if urlPattern is null or empty
* @throws IllegalStateException if the associated ServletContext has
* already been initialised
*/URL必须映射
public Set<String> addMapping(String... urlPatterns);
public Collection<String> getMappings();
public String getRunAsRole();
public static interface Dynamic
extends ServletRegistration, Registration.Dynamic {
public void setLoadOnStartup(int loadOnStartup);
public Set<String> setServletSecurity(ServletSecurityElement constraint);
public void setMultipartConfig(MultipartConfigElement multipartConfig);
public void setRunAsRole(String roleName);
}
}
思考:为什么Applacationcontext会有那么多重载方法?
@Override
public ServletRegistration.Dynamic addServlet(String servletName, String className) {
return addServlet(servletName, className, null, null);
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
return addServlet(servletName, null, servlet, null);
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName,
Class<? extends Servlet> servletClass) {
return addServlet(servletName, servletClass.getName(), null, null);
}
--用在不同场景下解决同一类问题
而在HttpServlet中的关键方法service可看到平时请求接口的所有方法