目录
@Lazy作用
作用
加在Bean上,指示是否要延迟初始化bean。
如加在@Autowired注入的属性上,可以用来解决Spring无法解决的循环依赖
解决问题举例
例如两个Bean循环依赖,并且使用了@Async等注解,在系统启动 bean生成过程中抛出循环依赖异常,可在其中一个bean注入时加上@Lazy
@Lazy使用
@Service
public class AServiceImpl implements AService {
@Autowired
private BService bService;
@Async
public void aMethod1(){
...
}
@Async
public void aMethod2(){
bService.bMethod();
}
}
@Service
public class BServiceImpl implements BService {
@Autowired
@Lazy
private AService aService;
public void bMethod(){
aService.aMethod1();
}
}
@Lazy原理
位置
org.springframework.context.annotation.Lazy
@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;
}
被Spring源码使用处ContextAnnotationAutowireCandidateResolver
如下,其中ContextAnnotationAutowireCandidateResolver类
该类实现了两个接口,AutowireCandidateResolver是自动装配的策略接口,Aware->BeaFactoryAware接口说明此类参与了Spring启动流程并产生了影响
参与循环依赖解决getLazyResolutionProxyIfNecessary
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
在resolveDependency时,doResolveDependency之前,Spring会使用getLazyResolutionProxyIfNecessary尝试获取LazyResolutionProxy
@Override
@Nullable
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
}
这段代码会在Spring生成bean的时候用到,打断点看一下调用栈,研究过SpringBoot启动流程、Spring Bean生成流程的同学比较容易理解,看到很多熟悉的方法,大致流程是项目启动-刷新应用上下文-获取bean-创建bean,然后在解决依赖的时候调用到getLazyResolutionProxyIfNecessary
这段代码也很好理解,先判断当前bean是否使用了@lazy
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;
}
buildLazyResolutionProxy创建 “虚假的”代理
是的话执行buildLazyResolutionProxy,创建AService的lazy注解专用代理,此代理非最终注入BService的代理,当实际使用到AService时,会走getTarget()获取正确的代理对象
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory,
"BeanFactory needs to be a DefaultListableBeanFactory");
final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory();
//创建了接口TargetSource的匿名内部类和对象
TargetSource ts = new TargetSource() {
@Override
public Class<?> getTargetClass() {
return descriptor.getDependencyType();
}
@Override
public boolean isStatic() {
return false;
}
//此方法为关键方法,在实际使用到此bean的时候才去获取完整的Spring代理对象
@Override
public Object getTarget() {
Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);
if (target == null) {
Class<?> type = getTargetClass();
if (Map.class == type) {
return Collections.emptyMap();
}
else if (List.class == type) {
return Collections.emptyList();
}
else if (Set.class == type || Collection.class == type) {
return Collections.emptySet();
}
throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
"Optional dependency not present for lazy injection point");
}
//运行中AService真正使用到BService时使用的完整代理
return target;
}
@Override
public void releaseTarget(Object target) {
}
};
//创建lazy代理对象
ProxyFactory pf = new ProxyFactory();
//将ts设置到代理中
pf.setTargetSource(ts);
Class<?> dependencyType = descriptor.getDependencyType();
if (dependencyType.isInterface()) {
pf.addInterface(dependencyType);
}
//将AService的lazy代理返回给BService暂用
return pf.getProxy(beanFactory.getBeanClassLoader());
}
从getLazyResolutionProxyIfNecessary上一级方法中看出,返回Lazy代理时不会走doResolveDependency,也就是说,如果不加@Lazy,会进入解决循环依赖的
doResolveDependency方法中,如果Spring无法解决,就会抛出异常
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
总结
通过源码分析可以看出,@Lazy通过生成“假”代理对象的方式,阻止参与循环依赖的bean解决依赖。直接阻止了项目启动时有可能发生的循环依赖错误,而随后真正使用@Autowired注入的bean时,获取Spring容器中完整的代理bean
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/93728.html