spring常见注解

fxz大约 10 分钟

spring常见注解

@Lookup

使用场景:A 依赖多例bean B,可以使用Lookup 注解在A中定义一个方法,该方法每次都会从容器中获取一个bean,因为B 是多例的,所以每次都是返回新的对象。

  • 这个注解标注在方法上。
  • 如果一个bean对象中的方法标注了 Lookup注解,那么会生成代理对象放入 bean容器中(在是实例化阶段通过后置处理器解析注解属性信息,通过cglib生成代理对象)。
  • 执行代理对象的方法,如果方法是标注了 Lookup 注解的方法时,会直接返回 Lookup 需要查找的bean,并不会执行方法体。
  1. 如果 BeanDefinition 设置了 instanceSupplier 属性,直接调用该接口返回实例对象,会导致 @Lookup 失效。
  2. 如果 BeanFactoryName 不为空,即是通过 @Bean 注册的情况,同样会导致 @Lookup 失效。
  3. 实例化 Bean 时,涉及到了代理的逻辑。标注了 @Lookup 注解的 Bean 在实例化时返回 CGLIB 生成的代理对象,执行方法时会被代理对象拦截,具体的拦截动作由 LookupOverrideMethodInterceptor 实现。

推断构造阶段,获取类方法上@Lookup注解信息到beanDefintion中。后面用。
记录到 BeanDefinition 中
会在bean实例化的时候,判断是否有 {@link AbstractBeanDefinition#methodOverrides} 属性,属性不为空,
就会创建代理对象。
{@link AbstractAutowireCapableBeanFactory#instantiateBean(String, RootBeanDefinition)}
{@link SimpleInstantiationStrategy#instantiate(RootBeanDefinition, String, BeanFactory)}
{@link CglibSubclassingInstantiationStrategy#instantiateWithMethodInjection(RootBeanDefinition, String, BeanFactory)}
{@link CglibSubclassingInstantiationStrategy#instantiateWithMethodInjection(RootBeanDefinition, String, BeanFactory, Constructor, Object...)}
return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
{@link CglibSubclassingInstantiationStrategy.CglibSubclassCreator#instantiate(Constructor, Object...)}
{@link CglibSubclassingInstantiationStrategy.CglibSubclassCreator#createEnhancedSubclass(RootBeanDefinition)}

instance = BeanUtils.instantiateClass(subclass);
instance = enhancedSubclassConstructor.newInstance(args);"
AutowiredAnnotationBeanPostProcessor: 

@Override
@Nullable
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
        throws BeanCreationException {

    // 没有校验过是否有Lookup方法
    if (!this.lookupMethodsChecked.contains(beanName)) {
        /**
         * 是候选类,可以简单理解。不是java包下的类,不是Ordered类 就是候选类
         * */
        if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
            try {
                Class<?> targetClass = beanClass;
                do {
                    // 遍历类的所有方法
                    ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                        Lookup lookup = method.getAnnotation(Lookup.class);
                        // 方法上有 @Lookup 注解
                        if (lookup != null) {
                            Assert.state(this.beanFactory != null, "No BeanFactory available");
                            // 装饰成 LookupOverride 对象
                            LookupOverride override = new LookupOverride(method, lookup.value());
                            try {
                                // 拿到这个beanName 的 BeanDefinition
                                RootBeanDefinition mbd = (RootBeanDefinition)
                                        this.beanFactory.getMergedBeanDefinition(beanName);
                              
          							
                                mbd.getMethodOverrides().addOverride(override);
                            } catch (NoSuchBeanDefinitionException ex) {
                                throw new BeanCreationException(beanName,
                                        "Cannot apply @Lookup to beans without corresponding bean definition");
                            }
                        }
                    });
                    // 递归解析父类的方法
                    targetClass = targetClass.getSuperclass();
                }
                while (targetClass != null && targetClass != Object.class);

            } catch (IllegalStateException ex) {
                throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
            }
        }
        // 记录这个beanName 已经处理过了
        this.lookupMethodsChecked.add(beanName);
    }

  ............
}
LookupOverrideMethodInterceptor:

@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
    // Cast is safe, as CallbackFilter filters are used selectively.
    LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
    Assert.state(lo != null, "LookupOverride not found");
    Object[] argsToUse = (args.length > 0 ? args : null);  // if no-arg, don't insist on args at all
    if (StringUtils.hasText(lo.getBeanName())) {
        Object bean = (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
                this.owner.getBean(lo.getBeanName()));
        // Detect package-protected NullBean instance through equals(null) check
        return (bean.equals(null) ? null : bean);
    } else {
        // Find target bean matching the (potentially generic) method return type
        ResolvableType genericReturnType = ResolvableType.forMethodReturnType(method);
        return (argsToUse != null ? this.owner.getBeanProvider(genericReturnType).getObject(argsToUse) :
                this.owner.getBeanProvider(genericReturnType).getObject());
    }
}

@DependsOn

@DependsOn 表示依赖关系,在获取当前bean的时候会先获取@DependsOn的值。比如:在getBean(A) 的时候,会获取@DependsOn 的值,遍历注解的值 getBean(b)。

AbstractBeanFactory:

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {

  ............
    
            // 依赖bean 的名称
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                /**
                 * A 依赖了 B,B 依赖了 A 即循环依赖的情况,抛出 BeanCreationException异常
                 * 比如:
                 * @Component
                 * @DependsOn({"b1"})
                 * class A1 {}
                 *
                 * @Component
                 * @DependsOn({"a1"})
                 * class b1 {
                 *
                 * }
                 */
                for (String dep : dependsOn) {
                    // beanName是当前正在创建的bean,dep是正在创建的bean 依赖的bean的名称
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    /**
                     * 保存的是 bean 和 依赖beanName之间的映射关系
                     * 被依赖bean:依赖beanList
                     *
                     * 依赖bean:被依赖beanList
                     * */
                    registerDependentBean(dep, beanName);
                    try {
                        // 取 dependOn的bean,从这里体现出 依赖bean 会先创建
                        getBean(dep);
                    } catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

 	...............
       
}

@Lazy

@Lazy 注解用于指示Spring容器在需要的时候才会初始化被注解的Bean。

默认情况下,Spring容器在启动时就会实例化所有的单例Bean,但通过使用 @Lazy 注解,可以将Bean的初始化推迟到首次被请求的时候。

  1. 懒加载: Bean被标记为 @Lazy 后,只有在第一次被请求时才会被实例化。这对于某些资源消耗较大的Bean,或者在启动时不需要立即初始化的Bean很有用。

    @Component
    @Lazy
    public class MyLazyBean {
        // Bean 的定义
    }
    
  2. 单例模式下的懒加载: 默认情况下,Spring容器在启动时会实例化所有的单例Bean。但如果某个单例Bean标记了 @Lazy 注解,那么它将在首次被请求时进行初始化。

    @Component
    @Lazy
    public class MyLazySingletonBean {
        // 单例 Bean 的定义
    }
    

需要注意的是,@Lazy 注解主要用于单例Bean。对于原型(prototype)作用域的Bean,因为每次请求都会创建新的实例,懒加载的概念并不适用。

过程:

  1. 创建Bean:

    • AbstractAutowireCapableBeanFactory#createBeandoCreateBean方法是在Bean的创建阶段执行的核心方法。这两个方法负责实例化和初始化Bean,执行构造函数和各种初始化方法。
  2. 填充Bean:

    • AbstractAutowireCapableBeanFactory#populateBean方法用于填充Bean的属性。在Bean实例创建后,该方法将通过依赖注入等方式将属性值注入到Bean中,确保Bean的各个属性都得到正确的初始化。
  3. 后置处理器解析属性值:

    • AutowiredAnnotationBeanPostProcessor#postProcessProperties方法是后置处理器的一部分。它负责解析带有@Autowired注解的属性,处理属性值的注入。其中,InjectionMetadata#inject方法用于实际注入属性值。

    • 对于@Lazy注解,Spring使用ContextAnnotationAutowireCandidateResolver来处理。它的getLazyResolutionProxyIfNecessary方法检查是否需要创建@Lazy代理对象。如果需要,就会使用CGLIB或JDK动态代理生成代理对象。这个代理对象的逻辑由CglibAopProxy.DynamicAdvisedInterceptorJdkDynamicAopProxy定义。

    • AbstractAutowireCapableBeanFactory#applyPropertyValues方法将解析后的属性值设置到Bean中。这是Bean填充阶段的最后一步,确保Bean实例的所有属性都正确设置。