spring常见注解
spring常见注解
@Lookup
使用场景:A 依赖多例bean B,可以使用Lookup 注解在A中定义一个方法,该方法每次都会从容器中获取一个bean,因为B 是多例的,所以每次都是返回新的对象。
- 这个注解标注在方法上。
- 如果一个bean对象中的方法标注了 Lookup注解,那么会生成代理对象放入 bean容器中(在是实例化阶段通过后置处理器解析注解属性信息,通过cglib生成代理对象)。
- 执行代理对象的方法,如果方法是标注了 Lookup 注解的方法时,会直接返回 Lookup 需要查找的bean,并不会执行方法体。
- 如果 BeanDefinition 设置了
instanceSupplier
属性,直接调用该接口返回实例对象,会导致@Lookup
失效。 - 如果 BeanFactoryName 不为空,即是通过
@Bean
注册的情况,同样会导致@Lookup
失效。 - 实例化 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的初始化推迟到首次被请求的时候。
懒加载: Bean被标记为
@Lazy
后,只有在第一次被请求时才会被实例化。这对于某些资源消耗较大的Bean,或者在启动时不需要立即初始化的Bean很有用。@Component @Lazy public class MyLazyBean { // Bean 的定义 }
单例模式下的懒加载: 默认情况下,Spring容器在启动时会实例化所有的单例Bean。但如果某个单例Bean标记了
@Lazy
注解,那么它将在首次被请求时进行初始化。@Component @Lazy public class MyLazySingletonBean { // 单例 Bean 的定义 }
需要注意的是,@Lazy
注解主要用于单例Bean。对于原型(prototype)作用域的Bean,因为每次请求都会创建新的实例,懒加载的概念并不适用。
过程:
创建Bean:
AbstractAutowireCapableBeanFactory#createBean
和doCreateBean
方法是在Bean的创建阶段执行的核心方法。这两个方法负责实例化和初始化Bean,执行构造函数和各种初始化方法。
填充Bean:
AbstractAutowireCapableBeanFactory#populateBean
方法用于填充Bean的属性。在Bean实例创建后,该方法将通过依赖注入等方式将属性值注入到Bean中,确保Bean的各个属性都得到正确的初始化。
后置处理器解析属性值:
AutowiredAnnotationBeanPostProcessor#postProcessProperties
方法是后置处理器的一部分。它负责解析带有@Autowired
注解的属性,处理属性值的注入。其中,InjectionMetadata#inject
方法用于实际注入属性值。对于
@Lazy
注解,Spring使用ContextAnnotationAutowireCandidateResolver
来处理。它的getLazyResolutionProxyIfNecessary
方法检查是否需要创建@Lazy
代理对象。如果需要,就会使用CGLIB或JDK动态代理生成代理对象。这个代理对象的逻辑由CglibAopProxy.DynamicAdvisedInterceptor
或JdkDynamicAopProxy
定义。AbstractAutowireCapableBeanFactory#applyPropertyValues
方法将解析后的属性值设置到Bean中。这是Bean填充阶段的最后一步,确保Bean实例的所有属性都正确设置。