众所周知,Spring中的Bean默认都是单例的,如果想要每次返回的不一样,类上加@Scope注解,并指定scope属性为PROTOTYPE类型的时候,在每次注入的时候会自动创建一个新的bean实例。看一下这个例子:
/**
* @ClassName: LookupService
* @Description: 测试原型Bean的注入
* @Author: Kaisheng Du
* @Date: 2021/10/25 14:34
* @Version: 1.0
*/
@Component
@Scope("prototype")
public class LookupService {
}
@Component
public class GoodsService {
@Autowired
private LookupService lookupService;
public LookupService test(){
return lookupService;
}
}
测试代码:
@Test
public void testLookup() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ScanBean.class);
GoodsService goodsService = applicationContext.getBean(GoodsService.class);
for (int i = 0; i < 3; i++) {
System.out.println(goodsService.test());
}
}
打印结果:
cn.kieasar.service.LookupService@51dcb805
cn.kieasar.service.LookupService@51dcb805
cn.kieasar.service.LookupService@51dcb805
调用3次test()方法,返回的结果却是同样的,你不是说LookupService是多例吗?
是不是很奇怪,因为GoodsService 是单例的,它创建的时候赋值给LookupService属性的就是刚开始的那个Bean,后面执行test()方法的时候,调用的都是同一个LookupService的Bean对象,所以它的hashCode相同。
那如何每次拿到的都不一样呢?使用@Lookup注解:
@Component
public class GoodsService {
@Autowired
private LookupService lookupService;
@Lookup("lookupService")
public LookupService test(){
return null;
}
}
我们再看打印结果:
cn.kieasar.service.LookupService@306f16f3
cn.kieasar.service.LookupService@702b8b12
cn.kieasar.service.LookupService@22e357dc
这次就是我们要的效果了~
接下来我们看一下@Lookup注解的实现原理:
在Bean的实例化过程中,在推断构造方法determineCandidateConstructors()逻辑中除了去选择构造方法以及查找入参对象之外,会还判断是否在对应的类中是否存在使用@Lookup注解的方法。如果存在则把该方法封装为LookupOverride对象并添加到BeanDefinition中。
在实例化时,如果判断出来当前BeanDefinition中没有LookupOverride,就直接用构造方法反射得到一个实例对象。如果存在LookupOverride对象,也就是类中存在@Lookup注解了的方法,那就会生成一个代理对象。@Lookup注解就是方法注入。
所属类:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
// 完成有@Autowied注解的有参构造函数的实例化
@Override
@Nullable
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
throws BeanCreationException {
// Let's check for lookup methods here...
if (!this.lookupMethodsChecked.contains(beanName)) {
// 对@Lookup注解的支撑
if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
try {
Class<?> targetClass = beanClass;
do {
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Lookup lookup = method.getAnnotation(Lookup.class);
if (lookup != null) {
Assert.state(this.beanFactory != null, "No BeanFactory available");
// 将当前method封装成LookupOverride,并设置到BeanDefinition的methodOverrides属性中
LookupOverride override = new LookupOverride(method, lookup.value());
try {
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);
}
}
this.lookupMethodsChecked.add(beanName);
}
// Quick check on the concurrent map first, with minimal locking.
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
// Fully synchronized resolution now...
synchronized (this.candidateConstructorsCache) {
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
Constructor<?>[] rawCandidates;
try {
rawCandidates = beanClass.getDeclaredConstructors();
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
// candidates用来装构造函数
List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
// 用来记录required为true的构造方法,一个类中只能有一个为true的构造方法
Constructor<?> requiredConstructor = null;
// 用来记录默认的无参构造方法
Constructor<?> defaultConstructor = null;
// kotlin相关,不用管
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
int nonSyntheticConstructors = 0;
// 遍历每个构造方法
for (Constructor<?> candidate : rawCandidates) {
if (!candidate.isSynthetic()) {
// 记录一下普通的构造方法
nonSyntheticConstructors++;
}
else if (primaryConstructor != null) {
continue;
}
// 找@Autowired注解的过程,进入findAutowiredAnnotation()****
MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
if (ann == null) {
// 如果beanClass是代理类,获取到被代理类的类型
Class<?> userClass = ClassUtils.getUserClass(beanClass);
if (userClass != beanClass) {
try {
Constructor<?> superCtor =
userClass.getDeclaredConstructor(candidate.getParameterTypes());
ann = findAutowiredAnnotation(superCtor);
}
catch (NoSuchMethodException ex) {
// Simply proceed, no equivalent superclass constructor found...
}
}
}
// 不为空,表示当前构造方法上加了@Autowired注解
if (ann != null) {
// 一个类中只能有一个required为true的构造方法,不能还有其他@Autowired的构造方法,否则会报错
if (requiredConstructor != null) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructor: " + candidate +
". Found constructor with 'required' Autowired annotation already: " +
requiredConstructor);
}
// 拿到 @Autowired 注解的 required 属性值,如果是 true
boolean required = determineRequiredStatus(ann);
if (required) {
if (!candidates.isEmpty()) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructors: " + candidates +
". Found constructor with 'required' Autowired annotation: " +
candidate);
}
// 记录required属性为true的构造方法
requiredConstructor = candidate;
}
// 只要加了@Autowired注解,不管有无参数,requred属性为true和false,都加入到集合中
candidates.add(candidate);
}
// 表示无参构造方法
else if (candidate.getParameterCount() == 0) {
defaultConstructor = candidate;
}
}
if (!candidates.isEmpty()) {
// Add default constructor to list of optional constructors, as fallback.
if (requiredConstructor == null) {
if (defaultConstructor != null) {
candidates.add(defaultConstructor);
}
else if (candidates.size() == 1 && logger.isInfoEnabled()) {
logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
"': single autowire-marked constructor flagged as optional - " +
"this constructor is effectively required since there is no " +
"default constructor to fall back to: " + candidates.get(0));
}
}
// 如果只有一个required为true的构造方法,那就只有中一个是合格的
candidateConstructors = candidates.toArray(new Constructor<?>[0]);
}
// 没有添加Autowired注解的构造方法,且只有一个、且是有参的
else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
}
else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
}
else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
candidateConstructors = new Constructor<?>[] {primaryConstructor};
}
else {
// 如果有多个有参、且没有@Autowired注解的构造方法,则返回空
candidateConstructors = new Constructor<?>[0];
}
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
}
}
}
return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
这里会对@Lookup注解的支持,如果当前创建Bean的某个方法上有@Lookup注解,将当前method封装成LookupOverride,并设置到BeanDefinition的methodOverrides属性中,
然后在后面无参构造函数的实例化方法SimpleInstantiationStrategy.instantiate()会判断判断当前BeanDefinition对应的beanClass中是否存在@Lookup注解的方法,存在的话生成代理对象:
所属类:org.springframework.beans.factory.support.SimpleInstantiationStrategy
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
// 判断当前BeanDefinition对应的beanClass中是否存在@Lookup注解的方法
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
constructorToUse = clazz.getDeclaredConstructor();
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// constructorToUse就是缓存的无参构造方法
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
// 如果有@Lookup注解,则生成一个代理对象
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
调用到SimpleInstantiationStrategy子类CglibSubclassingInstantiationStrategy的instantiateWithMethodInjection()方法:
@Override
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
return instantiateWithMethodInjection(bd, beanName, owner, null);
}
@Override
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Constructor<?> ctor, Object... args) {
// Must generate CGLIB subclass...
return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
}
看实例化方法instantiate():
所属类:org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy
.CglibSubclassCreator
public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
if (ctor == null) {
instance = BeanUtils.instantiateClass(subclass);
}
else {
try {
Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
instance = enhancedSubclassConstructor.newInstance(args);
}
catch (Exception ex) {
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
}
}
// SPR-10785: set callbacks directly on the instance instead of in the
// enhanced class (via the Enhancer) in order to avoid memory leaks.
// 主要看LookupOverrideMethodInterceptor类,该类实现了MethodInterceptor接口,生成代理的逻辑在intercept()方法
// ReplaceOverrideMethodInterceptor类是对XML中replaced-method标签的支持,作用是替换方法,但是需要新建一个类实现MethodReplacer接口
Factory factory = (Factory) instance;
factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
return instance;
}
这里有个LookupOverrideMethodInterceptor类,它是CglibSubclassingInstantiationStrategy的内部类,专门处理@Lookup注解的实例化,该类实现了MethodInterceptor接口,生成代理的逻辑在intercept()方法:
所属类:org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy
.LookupOverrideMethodInterceptor
private static class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
private final BeanFactory owner;
public LookupOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
super(beanDefinition);
this.owner = owner;
}
@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())) {
// 根据@Lookup注解配置的beanName去BeanFactory中获取Bean对象,(没有执行有@Lookup注解的方法)
return (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
this.owner.getBean(lo.getBeanName()));
}
else {
return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
this.owner.getBean(method.getReturnType()));
}
}
}