问题

@Lazy能干什么?

1
2
3
4
5
6
7
8
9
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lazy {
/**
* Whether lazy initialization should occur.
*/
boolean value() default true;
}

如何使用

可用在类上、方法返回值上、方法上、构造方法上、参数上、以及字段上

  • 类上、方法上、方法返回值上
    生成的bean懒加载,只有用到他的时候才会加载

    1
    2
    // 生成beanDefinition的时候会扫描注解,调用此方法,判断是否有Lazy注解,把beanDefinition的lazy属性变为true。
    AnnotationConfigUtils.processCommonDefinitionAnnotations(AnnotatedBeanDefinition, AnnotatedTypeMetadata)
  • 构造方法上、参数上、字段上
    注入的bean为一个代理过的对象,此方法可以解决循环依赖的问题,以及构造注入循环依赖的问题 源码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotationAutowireCandidateResolver {

    // 此方法在beanFactory进行ioc调用resolveDependency方法的时候,会调用此代码
    @Override
    @Nullable
    public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
    // 如果是lazy则生成一个代理对象
    return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
    }

    protected boolean isLazy(DependencyDescriptor descriptor) {
    // 如果字段上或者方法参数上
    for (Annotation ann : descriptor.getAnnotations()) {
    Lazy lazy = AnnotationUtils.getAnnotation(ann, Lazy.class);
    if (lazy != null && lazy.value()) {
    return true;
    }
    }
    MethodParameter methodParam = descriptor.getMethodParameter();
    if (methodParam != null) {
    Method method = methodParam.getMethod();
    // 如果方法为空代表为构造方法
    if (method == null || void.class == method.getReturnType()) {
    Lazy lazy = AnnotationUtils.getAnnotation(methodParam.getAnnotatedElement(), Lazy.class);
    if (lazy != null && lazy.value()) {
    return true;
    }
    }
    }
    return false;
    }

    protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
    BeanFactory beanFactory = getBeanFactory();
    Assert.state(beanFactory instanceof DefaultListableBeanFactory,
    "BeanFactory needs to be a DefaultListableBeanFactory");
    final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;

    // 不管三七二十一,直接生成代理对象,只有在调用bean内部方法的时候才会从beanFactory获取到真正的对象
    TargetSource ts = new TargetSource() {
    ...
    };

    ProxyFactory pf = new ProxyFactory();
    pf.setTargetSource(ts);
    Class<?> dependencyType = descriptor.getDependencyType();
    if (dependencyType.isInterface()) {
    pf.addInterface(dependencyType);
    }
    return pf.getProxy(dlbf.getBeanClassLoader());
    }

    }

主要作用

  1. 解决循环注入,构造注入也可以解决

    当spring容器不允许循环注入的时候,用@Lazy注入,可以解决。
    包括spring.main.allowCircularReferences=false的情况下