笔记:spring 不知道的知识点

171 阅读3分钟

spring 不知道的知识点

<aop:scoped-proxy/>

  • 例子:

    <!-- 例子1: -->
    <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
    <bean id="userManager" class="com.foo.UserManager">
        <property name="userPreferences" ref="userPreferences"/>
    </bean>
    <!-- 例子2: -->
    <bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
        <aop:scoped-proxy/>
    </bean>
    
    <bean id="userManager" class="com.foo.UserManager">
        <property name="userPreferences" ref="userPreferences"/>
    </bean>
    
  • 说明:第二个例子中,userManager注入的是userPreferences的代理对象,当调用这个代理对象的方法时,会自动从httpsession中获取对应的userPreferences对象并调用其方法,从而实现在长生命周期对象里注入短生命周期的对象。创建代理用的,修改BeanDefinition,变成代理对象,其他bean引用时获取的也就是代理对象了

    • class ScopedProxyBeanDefinitionDecorator implements BeanDefinitionDecorator {
      private static final String PROXY_TARGET_CLASS = "proxy-target-class";
      
      public BeanDefinitionHolder decorate(Node node,
              BeanDefinitionHolder definition, ParserContext parserContext) {
          boolean proxyTargetClass = true;
          if (node instanceof Element) {
              Element ele = (Element) node;
              if (ele.hasAttribute("proxy-target-class")) {
                  proxyTargetClass = Boolean.valueOf(
                          ele.getAttribute("proxy-target-class")).booleanValue();
              }
      
          }
      
          BeanDefinitionHolder holder = ScopedProxyUtils.createScopedProxy(
                  definition, parserContext.getRegistry(), proxyTargetClass);
          String targetBeanName = ScopedProxyUtils.getTargetBeanName(definition
                  .getBeanName());
          parserContext.getReaderContext().fireComponentRegistered(
                  new BeanComponentDefinition(definition.getBeanDefinition(),
                          targetBeanName));
          return holder;
      }
      }
      

    spring 中 Aware接口 系列作用

    接口名接口作用
    ApplicationContextAware获取到ApplicationContext接口实例,然后通过这个上下文类就可以做一些其他的事,比如获取 bean(,spring文档中并不推荐用这个类获取bean,理由是这样会增加耦合性原文One use would be the programmatic retrieval of other beans. Sometimes this capability is useful. However, in general, you should avoid it, because it couples the code to Spring and does not follow the Inversion of Control style, where collaborators are provided to beans as properties.)、访问文件资源、发布应用事件(这个功能是因为ApplicationContext接口继承了ApplicationEventPublisherAware)、访问MessageSource等。
    ApplicationEventPublisherAware通过此接口获取到ApplicationEventPublisher接口实例,然后就可以发布事件了,这个功能需要配合ApplicationEvent接口使用,可以用来实现异步发送短信、邮件之类的功能,这样也有助于解耦。
    BeanClassLoaderAware获取当前 bean 的类加载器
    BeanFactoryAware获取BeanFactory类实例,BeanFactory是访问 spring bean 容器根接口
    BeanNameAware获取 bean 名字的接口
    LoadTimeWeaverAware获取LoadTimeWeaver接口实例。LoadTimeWeaver用于在类加载时实现织入(比如AspectJ类加载时织入,AspectJ还可以编译器织入)
    MessageSourceAware获取MessageSource接口实例,MessageSourceAware`用于实现国际化
    NotificationPublisherAware获取NotificationPublisher接口实例,spring 对 jmx的支持
    ResourceLoaderAware获取ResourceLoader接口实例,这个类在 spring 中用来加载资源
    ServletConfigAware获取ServletConfig接口实例
    ServletContextAware获取ServletContext接口实例

    BeanPostProcessor

    • 先创建BeanPostProcessor 对象,然后再创建 bean 对象,然后再调用BeanPostProcessor 中的前后处理方法
    • BeanPostProcessor被实例化顺序
      • 1、首先是 spring 默认的四个BeanPostProcessor
        • org.springframework.context.support.ApplicationContextAwareProcessor,这个类默认修饰符,外部不可见
        • org.springframework.context.support.ApplicationListenerDetector,这个类默认修饰符,外部不可见
        • org.springframework.web.context.support.ServletContextAwareProcessor
        • org.springframework.context.annotation.ConfigurationClassPostProcessor
      • 2、然后是实现了PriorityOrdered接口的BeanPostProcessor
      • 3、然后是实现了Ordered接口的BeanPostProcessor
      • 4、最后是没有实现上述两个接口的BeanPostProcessor
    • 可能遇到的问题: Bean someBean is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying)
      • 原因:BeanPostProcessor 实例化顺序靠前的BeanPostProcessor 依赖了实例化顺序中比较靠后的BeanPostProcessor 处理的bean,导致bean 被未经过处理就提前注入了(也就是说 bean 被提前加载了),从而使 bean 未达到预期效果,这时 spring 的org.springframework.context.support.PostProcessorRegistrationDelegate.BeanPostProcessorChecker类会打印Bean someBean is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying)这样的提示信息
      • 参考: