团建活动目的JavaSpring@Lazy延迟注⼊源码案例详解
前⾔
有时候我们会在属性注⼊的时候添加@Lazy注解实现延迟注⼊,今天咱们通过阅读源码来分析下原因
⼀、⼀个简单的⼩例⼦
代码如下:
@Service
public class NormalService1 {
@Autowired
@Lazy
private MyService myService;
public void doSomething() {
}
}
作⽤是为了进⾏延迟加载,在NormalService1进⾏属性注⼊的时候,如果MyService还没有⽣成bean也不⽤担⼼,会注⼊⼀个代理,但是在实际运⾏的时候,会获取Spring容器中实际的MyService,在某些情况下,因为spring⽣命周期的原因,这个注解有⼤⽤。
⼆、源码解读
1. 注⼊
代码如下(DefaultListableBeanFactory#resolveDependency):
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == DependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
el if (ObjectFactory.class == DependencyType() ||
ObjectProvider.class == DependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
el if (javaxInjectProviderClass == DependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
红酒配什么}
el {
//如果注⼊属性添加了@Lazy,懒加载,此时spring会根据具体类型搞个cglib代理类
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
血站管理办法
很明显要执⾏getLazyResolutionProxyIfNecessary⽅法,如果加了@Lazy注解,最终会执⾏buildLazyResolutionProxy⽅法
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
Asrt.state(getBeanFactory() instanceof DefaultListableBeanFactory,
"BeanFactory needs to be a DefaultListableBeanFactory");
final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory();
TargetSource ts = new TargetSource() {
@Override
public Class<?> getTargetClass() {
DependencyType();
}小星星吉他
@Override
public boolean isStatic() {
return fal;
}
@Override
public Object getTarget() {
Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);
/**
something valid
**/
return target;
}
@Override
public void releaTarget(Object target) {
}
};
ProxyFactory pf = new ProxyFactory();
pf.tTargetSource(ts);
Class<?> dependencyType = DependencyType();
if (dependencyType.isInterface()) {ps如何反选
世界足球队pf.addInterface(dependencyType);
}
BeanClassLoader());
}
可以看到上⾯这段代码,其实就是⽣成了⼀个TargetSource,然后再⽣成了⼀个代理(CGLIB或者JDK),然后作为MyService对象注⼊给了NormalService1。那么所谓的执⾏的过程中才进⾏获取真正的MyService对象是什么意思呢?
2. 使⽤逻辑
本⽂⽰例代码使⽤的是CGLIB代理,其实是类似的,因为注⼊的MyService是个CGLIB代理对象,那么在执⾏⽅法的时候,就会调⽤
CglibAopProxy#DynamicAdvidInterceptor#intercept⽅法
那么此处其实调⽤的就是上⾯的
Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);
这个⽅法就不⽤认真看了,主要功能就是从Spring容器中找到MyService。
在之前讲@Autowired原理和@Resource注⼊原理的时候解释过了,不清楚的可以看专栏⾥其他⽂章。
武则天怎么死的拿出来之后会发现,咱们拿到的target对象还是⼀个CGLIB代理的对象动量公式
那么当执⾏⽅法逻辑时
由于target是CGLIB对象,会再次进⼊到CglibAopProxy#DynamicAdvidInterceptor#intercept⽅法。
此时拿到的target对象类型就不同了
是我们代理之前的target对象,此时再次进⾏invoke的时候,就会进⾏动态代理的⼀般逻辑,先查找该⽅法匹配的所有advice,然后依次调⽤,最终调⽤target 本⾝对于⽅法的执⾏。
总结
所以可以发现其实@Lazy只不过是给spring的代理对象proxy再进⾏了⼀次proxy,只不过没有在注⼊的时候,就获取到对象,⽽是借⽤了⽅法invoke时通过proxy的intercept⽅法getTarget,然后进⾏⽅法调⽤,延迟了对象的注⼊。之后每次调⽤的时候都需要从Spring容器中获取到原⽣的proxy对象。
到此这篇关于Java Spring @Lazy延迟注⼊源码案例详解的⽂章就介绍到这了,更多相关Java Spring @Lazy延迟注⼊源码内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!