Loading

Spring番外篇

Spring 番外篇

😉 本文共4405字,阅读时间约8min

Spring refresh方法

  • refresh()是 Spring 最核心的方法,没有之一。refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 ApplicationContext 容器,容器必须调用 refresh 才能正常工作。

  • 它的内部主要会调用 12 个方法,我们把它们称为 refresh 的 12 个步骤:

    • 注意下面的EnvironmentBeanFactory都是ApplicationContext的成员变量。

image-20230205190318003

  1. Environment
  2. BeanFactory初始化成员变量(bean definiton、解析SpEL器、特殊bean解析器、注册bean后处理器),调用BeanFactory后处理器来补充bean definiton。
  3. ApplicationContext初始化成员变量(国际化、事件广播器、事件监听器,生命周期管理器),初始化单例Bean,并执行Bean后处理器扩展。

01_Environment

  • Environment 对象的作用之一是为后续 @Value,值注入时提供键值
  • Environment 分成三个主要部分
    • systemProperties - 保存 java 环境键值
    • systemEnvironment - 保存系统环境键值
    • 自定义 PropertySource - 保存自定义键值,例如来自于 *.properties 文件的键值

image-20210902181639048

02_获取BeanFactory

  • 这一步获取(或创建) BeanFactory,它也是作为 ApplicationContext 的一个成员变量
  • BeanFactory 的作用是负责 bean 的创建、依赖注入和初始化,bean 的各项特征由 BeanDefinition 定义
    • BeanDefinition 作为 bean 的设计蓝图,规定了 bean 的特征,如单例多例、依赖关系、初始销毁方法等
    • BeanDefinition 的来源有多种多样,可以是通过 xml 获得、配置类获得、组件扫描获得,也可以是编程添加。所有的 BeanDefinition 会存入 BeanFactory 中的 beanDefinitionMap 集合。

image-20210902182004819

03_准备BeanFactory

这一步会进一步完善 BeanFactory,为它的各项成员变量赋值

  • 解析SpEL器,比如#{}

  • 特殊bean注册器:注册 beanFactory 以及 ApplicationContext(不在bean definition里)

  • beanPostProcessors 是 bean 后处理器集合,会工作在 bean 的生命周期各个阶段,此处会添加两个:

    • ApplicationContextAwareProcessor 用来解析 Aware 接口
    • ApplicationListenerDetector 用来识别容器中 ApplicationListener 类型的 bean

image-20210902182541925

04_05_扩展BeanFactory

  • 第四步是空实现,留给子类扩展。一般 Web 环境的 ApplicationContext 都要利用它注册新的 Scope,完善 Web 下的 BeanFactory。

    • 这里体现的是模板方法设计模式
  • 第五步会调用 beanFactory 后处理器

    • beanFactory 后处理器,充当 beanFactory 的扩展点,可以用来补充或修改 BeanDefinition
    • 常见的 beanFactory 后处理器有
      • ConfigurationClassPostProcessor – 解析 @Configuration、@Bean、@Import、@PropertySource 等
      • PropertySourcesPlaceHolderConfigurer – 替换 BeanDefinition 中的 $

image-20210902183232114

06_注册Bean后处理器

  • 这一步是继续从 beanFactory 中找出 bean 后处理器,添加至 beanPostProcessors 集合中
  • bean 后处理器,充当 bean 的扩展点,可以工作在 bean 的实例化、依赖注入、初始化阶段,常见的有:
    • AutowiredAnnotationBeanPostProcessor 功能有:解析 @Autowired,@Value 注解
    • CommonAnnotationBeanPostProcessor 功能有:解析 @Resource,@PostConstruct,@PreDestroy
    • AnnotationAwareAspectJAutoProxyCreator 功能有:为符合切点的目标 bean 自动创建代理

image-20210902183520307

07_10 国际化 & 广播器 & 监听器

  • 为 ApplicationContext 添加 messageSource 成员,实现国际化功能

  • 为 ApplicationContext 添加事件广播器成员,即 applicationContextEventMulticaster,它的作用是发布事件给监听器,之后就可以调用 ApplicationContext.publishEvent(事件对象) 来发布事件。

  • 这一步会从多种途径找到事件监听器,并添加至 applicationEventMulticaster

    • 事件监听器顾名思义,用来接收事件广播器发布的事件,有如下来源
      • 事先编程添加的、来自容器中的 bean、来自于 @EventListener 的解析
      • 要实现事件监听器,只需要实现 ApplicationListener 接口,重写其中 onApplicationEvent(E e) 方法即可

image-20210902184343872

11_初始化所有非延迟单例bean

  • 这一步会将 beanFactory 的成员补充完毕,并初始化所有非延迟单例 bean
    • 利用类型转换器、内嵌值解析器
  • conversionService 也是一套转换机制,作为对 PropertyEditor 的补充
  • embeddedValueResolvers 即内嵌值解析器,用来解析 @Value 中的 ${ },借用的是 Environment 的功能
  • singletonObjects 即单例池,缓存所有单例对象
    • 对象的创建都分三个阶段,每一阶段都有不同的 bean 后处理器参与进来,扩展功能

image-20210902184641623

12_完成初始化-添加 lifecycleProcessor 成员

  • 这一步会为 ApplicationContext 添加 lifecycleProcessor 成员,用来控制容器内需要生命周期管理的 bean
    • 调用 context 的 start,即可触发所有实现 LifeCycle 接口 bean 的 start
    • 调用 context 的 stop,即可触发所有实现 LifeCycle 接口 bean 的 stop
  • 发布 ContextRefreshed 事件,整个 refresh 执行完成

image-20210902185052433

Spring Bean

Bean 代指的就是那些被 IoC 容器所管理的对象。

我们需要告诉 IoC 容器帮助我们管理哪些对象,这个是通过配置元数据来定义的。配置元数据可以是 XML 文件、注解或者 Java 配置类。

将一个类声明为 Bean 的注解有哪些?

  • @Component :通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。
  • @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
  • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
  • @Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。

@Component 和 @Bean 的区别是什么?

  • @Component 注解作用于类,而@Bean注解作用于方法
  • @Component通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了 Spring 这是某个类的实例,当我需要用它的时候还给我
  • @Bean 注解比 @Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册 bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。
// bean注解使用示例
@Configuration
public class AppConfig {
    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }
}
// 上面的代码相当于下面的 xml 配置
<beans>
    <bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
// 下面这个例子是通过 @Component 无法实现的
@Bean
public OneService getService(status) {
    case (status)  {
        when 1:
                return new serviceImpl1();
        when 2:
                return new serviceImpl2();
        when 3:
                return new serviceImpl3();
    }
}        

注入bean的注解有哪些?

Spring 内置的 @Autowired 以及 JDK 内置的 @Resource@Inject 都可以用于注入 Bean。

@Autowired 和 @Resource 的区别是什么?

Autowired 属于 Spring 内置的注解,默认的注入方式为byType(根据类型进行匹配),也就是说会优先根据接口类型去匹配并注入 Bean (接口的实现类)。

这会有什么问题呢? 当一个接口存在多个实现类的话,byType这种方式就无法正确注入对象了,因为这个时候 Spring 会同时找到多个满足条件的选择,默认情况下它自己不知道选择哪一个。

这种情况下,注入方式会变为 byName(根据名称进行匹配),这个名称通常就是类名(首字母小写)。就比如说下面代码中的 smsService 就是我这里所说的名称,这样应该比较好理解了吧。我们还是建议通过 @Qualifier 注解来组合使用显式指定名称而不是依赖变量的名称。

@Resource属于 JDK 提供的注解,默认注入方式为 byName。如果无法通过名称匹配到对应的 Bean 的话,注入方式会变为byType

@Resource 有两个比较重要且日常开发常用的属性:name(名称)、type(类型)。

简单总结一下:

@Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。

Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。

当一个接口存在多个实现类的情况下,@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。

Tomcat中的 Filter和Servlet 与 SpringMVC Interceptor

img

Filter

Filter可以拦截请求与响应

  • 实现URL级别的权限访问控制、压缩响应信息等。
  • 针对传入的request提前设置一些参数,或response过滤掉一些信息。

多个Filter对同一个资源进行了拦截,会先按顺序走每一个Filter。

Servlet

Tomcat 是Web应用服务器,是一个Servlet容器。jetty jboss weblogic都是servlet容器。这些servlet把网络相关的问题已经全部处理好,我们写servlet只需要关注业务逻辑即可。

Tomcat 作为 Servlet 容器,负责处理客户请求,把请求传送给 Servlet,并将 Servlet 的响应传送回给客户,而 Servlet 是一种运行在支持 Java 语言的服务器上的组件。

Interceptor

拦截器是spring容器的,是spring支持的。

面向切面编程AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截,然后在之前或之后加入某些操作。

比如动态代理就是拦截器的简单实现,而动态代理基于java的反射机制的。

posted @ 2023-02-06 12:34  iterationjia  阅读(52)  评论(0编辑  收藏  举报