1.现象说明
当一个单例bean注入一个原型bean,原型bean的特性会消失
写一个例子演示现象
创建实体类Car Person
package com.test.bd.component;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope(scopeName = "prototype")
public class Car {
}
package com.test.bd.component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Person {
@Autowired
private Car car;
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}
创建配置类
package com.test.bd.config;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan("com.test.bd")
public class AppConfig {
}
创建启动类
package com.test.bd;
import com.test.bd.component.Car;
import com.test.bd.component.Person;
import com.test.bd.config.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Person p1 = context.getBean(Person.class);
Car car1 = p1.getCar();
Person p2 = context.getBean(Person.class);
Car car2 = p2.getCar();
boolean equation = (car1 == car2);
System.out.println(equation);
}
}
运行main方法,查看运行结果
两个car是同一个对象,没有体现原型的特性
2.使用@Lookup注解解决上述问题
修改实体类Person
package com.test.bd.component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Component;
@Component
public class Person {
//@Autowired
private Car car;
@Lookup
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}
再次运行main方法,查看运行结果
两个car不是同一个对象,体现了原型的特性
3.源码分析
第一阶段 BeanDefinition对象相关属性赋值
当我们实例化Person对象的时候,会执行一个推断构造方法的方法(determineConstructorsFromBeanPostProcessors),这个方法会循环执行bpp的determineCandidateConstructors方法,其中一个子类实现AutowiredAnnotationBeanPostProcessor会处理@Lookup注解(给BeanDefinition的methodOverrides属性设置值)
相关方法
- AbstractAutowireCapableBeanFactory#createBeanInstance
- AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors
- AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors
第二阶段 动态代理
在后面的某个阶段会判断BeanDefinition的methodOverrides属性是否为空,当methodOverrides属性不为空则进行cglib动态代理,动态代理的时候会注册LookupOverrideMethodInterceptor拦截器
相关方法
- AbstractAutowireCapableBeanFactory#instantiateBean
- SimpleInstantiationStrategy#instantiate
- CglibSubclassingInstantiationStrategy#instantiateWithMethodInjection
第三阶段 分析LookupOverrideMethodInterceptor执行流程
当我们执行getCar方法的时候,拦截器不会返回bean注入的car,而是去beanFactory中重新获取,因为Car是一个原型bean,所以两次取出来的值不一样
相关方法
- LookupOverrideMethodInterceptor#intercept
- DefaultListableBeanFactory#getBeanProvider
- DefaultListableBeanFactory#resolveBean
- DefaultListableBeanFactory#resolveNamedBean
总结
如果类中存在@Lookup标注的方法,Spring在实例化bean的时候会进行动态代理,注册一个LookupOverrideMethodInterceptor拦截器。后期如果我们调用@Lookup标注的方法,就会进入拦截器的intercept方法,该ntercept方法通过beanFactory.getBean重新获取bean