我们看一段代码,先定义一个多例的Bean:
@Component
@Scope(value = DefaultListableBeanFactory.SCOPE_PROTOTYPE)
public class ScopedProxyBean {
public void code() {
System.out.println(this.hashCode());
}
}
再定义一个单例Bean,通过@Autowired注解把上面的多例Bean注入进去,打印hashCode:
@Component
public class SingleBean {
@Autowired
private ScopedProxyBean scopedProxyBean;
public void test() {
scopedProxyBean.code();
}
}
单元测试:
@Test
public void testScopedProxy() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ScanBean.class);
SingleBean bean = applicationContext.getBean(SingleBean.class);
for (int i = 0; i < 10; i++) {
bean.test();
}
}
不是多例的吗,为什么hashCode 却是一样的?
因为SingleBean是单例,在属性赋值的时候,@Autowired注解的是引用类,会触发ScopedProxyBean的getBean()操作,拿到实例对象,然后进行反射调用,但只会拿到一个(在启动的时候),即使ScopedProxyBean是多例,但也只会创建一次,因为在Spring的启动,SingleBean的实例化过程中就定了,所以,即使调用多次,但实例确实同一个,所以打印结果一致也就不奇怪了。
对上面的代码做一点改动,在注解上加代理模式的配置:
proxyMode = ScopedProxyMode.TARGET_CLASS
@Component
@Scope(value = DefaultListableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ScopedProxyBean {
public void code() {
System.out.println(this.hashCode());
}
}
再看打印结果:
此时却时不一样的,这又是为什么?
看一下ScopedProxyMode.TARGET_CLASS:
public enum ScopedProxyMode {
/**
* Default typically equals {@link #NO}, unless a different default
* has been configured at the component-scan instruction level.
*/
DEFAULT,
/**
* Do not create a scoped proxy.
* This proxy-mode is not typically useful when used with a
* non-singleton scoped instance, which should favor the use of the
* {@link #INTERFACES} or {@link #TARGET_CLASS} proxy-modes instead if it
* is to be used as a dependency.
*/
NO,
/**
* Create a JDK dynamic proxy implementing all interfaces exposed by
* the class of the target object.
*/
INTERFACES,
/**
* Create a class-based proxy (uses CGLIB).采用的是CGLIB的代理
*/
TARGET_CLASS
}
采用的是CGLIB代理,之前我们实例化的是原始对象,之后加了这个,依赖注入的是代理对象,如果代理对象去调用目标方法,就会走切面,切面中拿到目标实例再进行方法调用,在拿BeanDefinition的时,发现它是多例的,每次getBean()拿到的实例都是新创建的,所以hashCode不一样。
但是,为什么这里依赖注入的是代理对象?
通过前面系列的源码,我们看扫描注解及Scope的填充过程,就是这个解析配置信息的类ConfigurationClassPostProcessor:
ConfigurationClassPostProcessor.processConfigBeanDefinitions()——>
解析过程ConfigurationClassParser#parse()——>
ConfigurationClassParser#processConfigurationClass——>
ConfigurationClassParser#doProcessConfigurationClass——>
ComponentScanAnnotationParser#parse——>
ClassPathBeanDefinitionScanner#doScan():
protected Set doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 根据扫描路径,得到BeanDefinition
Set candidates = findCandidateComponents(basePackage);
// 解析class
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析@lazy、@Primary、@DependsOn、@Role、@Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查Spring容器是否已经存在beanName
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
Scope是this.scopeMetadataResolver.resolveScopeMetadata(candidate);
所属类:org.springframework.context.annotation.AnnotationScopeMetadataResolver
@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
// this.scopeAnnotationType就是@Scope注解
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
metadata.setScopeName(attributes.getString("value"));
// 根据注解中proxyMode的拿到代理模式
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
}
根据注解中proxyMode的拿到代理模式,ScopedProxyMode.DEFAULT为默认的代理模式,表示没有。
获取代理模式就是这里,参数中的BeanDefinition是通过填充传进来的:
definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
所属类:org.springframework.context.annotation.AnnotationConfigUtils
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
// 如果代理模式是TARGET_CLASS,就创建代理
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
所属类:org.springframework.context.annotation.ScopedProxyCreator
public static BeanDefinitionHolder createScopedProxy(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {
return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
}
创建代理就是创建一个新的BeanDefinition:
所属类:org.springframework.aop.scope.ScopedProxyUtils
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
BeanDefinitionRegistry registry, boolean proxyTargetClass) {
String originalBeanName = definition.getBeanName();
BeanDefinition targetDefinition = definition.getBeanDefinition();
String targetBeanName = getTargetBeanName(originalBeanName);
// Create a scoped proxy definition for the original bean name,
// "hiding" the target bean in an internal target definition.
// 创建一个新的BeanDefinition
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(targetDefinition.getRole());
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
}
else {
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
}
// Copy autowire settings from original bean definition.
// 代理实例的配置从原始的BeanDefnition复制autowire配置(没有配置默认为true)
proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
// 相同类型,以它为准
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
// The target bean should be ignored in favor of the scoped proxy.
// 目标对象autowire属性设置为false,表示容器在查找自动装配对象时,不考虑该Bean
targetDefinition.setAutowireCandidate(false);
// 将之前的BeanDefinition覆盖
targetDefinition.setPrimary(false);
// Register the target bean as separate bean in the factory.
// 将新的targetDefinition注册进去
registry.registerBeanDefinition(targetBeanName, targetDefinition);
// Return the scoped proxy definition as primary bean definition
// (potentially an inner bean).
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
我们看一下这个ScopedProxyFactoryBean:
public class ScopedProxyFactoryBean extends ProxyConfig
implements FactoryBean
将CGLIB产生的代理对象返回,CGLIB的代理逻辑会进入到DynamicAdvisedInterceptor类,它是CglibAopProxy的内部类,执行intercept()方法:
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class> targetClass = (target != null ? target.getClass() : null);
List
target = targetSource.getTarget()就会调到SimpleBeanTargetSource.getTarget(),把代理对象(实例代码中的ScopedProxyBean)返回:
public class SimpleBeanTargetSource extends AbstractBeanFactoryBasedTargetSource {
@Override
public Object getTarget() throws Exception {
return getBeanFactory().getBean(getTargetBeanName());
}
}
依赖注入的才是代理对象,代理对象走切面才会调用TargetSource.getTarget()方法,getTarget()中才会执行getBean(),每次会生成新的实例。
ScopedProxyFactoryBean实现了FactoryBean接口,在这里会生成代理,getObjectType()方法就是在依赖注入时执行,走切面的逻辑this.scopedTargetSource.getTargetClass()返回的就是代理实例,getObjectType()返回的是依赖注入对象,上面示例代码中ScopedProxyBean的依赖注入最终会执行ScopedProxyFactoryBean.getObject()方法:
@Override
public Object getObject() {
if (this.proxy == null) {
throw new FactoryBeanNotInitializedException();
}
return this.proxy;
}