Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
爱吃血肠
spring-framework
提交
8580d2d1
S
spring-framework
项目概览
爱吃血肠
/
spring-framework
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
spring-framework
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
8580d2d1
编写于
12月 08, 2013
作者:
J
Juergen Hoeller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Fixed detection of generic types and qualifier annotations on scoped-proxy factory methods
Issue: SPR-11116
上级
1f9b833c
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
216 addition
and
36 deletion
+216
-36
spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyUtils.java
.../java/org/springframework/aop/scope/ScopedProxyUtils.java
+2
-2
spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
...otation/QualifierAnnotationAutowireCandidateResolver.java
+20
-10
spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java
...ry/support/GenericTypeAwareAutowireCandidateResolver.java
+44
-16
spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java
...text/annotation/ConfigurationClassPostProcessorTests.java
+99
-4
spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java
...nnotation/configuration/BeanMethodQualificationTests.java
+51
-4
未找到文件。
spring-aop/src/main/java/org/springframework/aop/scope/ScopedProxyUtils.java
浏览文件 @
8580d2d1
...
...
@@ -50,17 +50,17 @@ public abstract class ScopedProxyUtils {
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.
RootBeanDefinition
proxyDefinition
=
new
RootBeanDefinition
(
ScopedProxyFactoryBean
.
class
);
proxyDefinition
.
setDecoratedDefinition
(
new
BeanDefinitionHolder
(
targetDefinition
,
targetBeanName
));
proxyDefinition
.
setOriginatingBeanDefinition
(
targetDefinition
);
proxyDefinition
.
setSource
(
definition
.
getSource
());
proxyDefinition
.
setRole
(
BeanDefinition
.
ROLE_INFRASTRUCTURE
);
String
targetBeanName
=
getTargetBeanName
(
originalBeanName
);
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.
...
...
spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
浏览文件 @
8580d2d1
...
...
@@ -216,18 +216,22 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
Class
<?
extends
Annotation
>
type
=
annotation
.
annotationType
();
RootBeanDefinition
bd
=
(
RootBeanDefinition
)
bdHolder
.
getBeanDefinition
();
AutowireCandidateQualifier
qualifier
=
bd
.
getQualifier
(
type
.
getName
());
if
(
qualifier
==
null
)
{
qualifier
=
bd
.
getQualifier
(
ClassUtils
.
getShortName
(
type
));
}
if
(
qualifier
==
null
)
{
Annotation
targetAnnotation
=
null
;
Method
resolvedFactoryMethod
=
bd
.
getResolvedFactoryMethod
();
if
(
resolvedFactoryMethod
!=
null
)
{
targetAnnotation
=
AnnotationUtils
.
getAnnotation
(
resolvedFactoryMethod
,
type
);
// First, check annotation on factory method, if applicable
Annotation
targetAnnotation
=
getFactoryMethodAnnotation
(
bd
,
type
);
if
(
targetAnnotation
==
null
)
{
RootBeanDefinition
dbd
=
getResolvedDecoratedDefinition
(
bd
);
if
(
dbd
!=
null
)
{
targetAnnotation
=
getFactoryMethodAnnotation
(
dbd
,
type
);
}
}
if
(
targetAnnotation
==
null
)
{
//
l
ook for matching annotation on the target class
//
L
ook for matching annotation on the target class
if
(
getBeanFactory
()
!=
null
)
{
Class
<?>
beanType
=
getBeanFactory
().
getType
(
bdHolder
.
getBeanName
());
if
(
beanType
!=
null
)
{
...
...
@@ -242,30 +246,31 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
return
true
;
}
}
Map
<
String
,
Object
>
attributes
=
AnnotationUtils
.
getAnnotationAttributes
(
annotation
);
if
(
attributes
.
isEmpty
()
&&
qualifier
==
null
)
{
//
i
f no attributes, the qualifier must be present
//
I
f no attributes, the qualifier must be present
return
false
;
}
for
(
Map
.
Entry
<
String
,
Object
>
entry
:
attributes
.
entrySet
())
{
String
attributeName
=
entry
.
getKey
();
Object
expectedValue
=
entry
.
getValue
();
Object
actualValue
=
null
;
//
c
heck qualifier first
//
C
heck qualifier first
if
(
qualifier
!=
null
)
{
actualValue
=
qualifier
.
getAttribute
(
attributeName
);
}
if
(
actualValue
==
null
)
{
//
f
all back on bean definition attribute
//
F
all back on bean definition attribute
actualValue
=
bd
.
getAttribute
(
attributeName
);
}
if
(
actualValue
==
null
&&
attributeName
.
equals
(
AutowireCandidateQualifier
.
VALUE_KEY
)
&&
expectedValue
instanceof
String
&&
bdHolder
.
matchesName
((
String
)
expectedValue
))
{
//
f
all back on bean name (or alias) match
//
F
all back on bean name (or alias) match
continue
;
}
if
(
actualValue
==
null
&&
qualifier
!=
null
)
{
//
f
all back on default, but only if the qualifier is present
//
F
all back on default, but only if the qualifier is present
actualValue
=
AnnotationUtils
.
getDefaultValue
(
annotation
,
attributeName
);
}
if
(
actualValue
!=
null
)
{
...
...
@@ -278,6 +283,11 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
return
true
;
}
protected
Annotation
getFactoryMethodAnnotation
(
RootBeanDefinition
bd
,
Class
<?
extends
Annotation
>
type
)
{
Method
resolvedFactoryMethod
=
bd
.
getResolvedFactoryMethod
();
return
(
resolvedFactoryMethod
!=
null
?
AnnotationUtils
.
getAnnotation
(
resolvedFactoryMethod
,
type
)
:
null
);
}
/**
* Determine whether the given dependency carries a value annotation.
...
...
spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java
浏览文件 @
8580d2d1
...
...
@@ -21,7 +21,9 @@ import java.lang.reflect.Method;
import
org.springframework.beans.factory.BeanFactory
;
import
org.springframework.beans.factory.BeanFactoryAware
;
import
org.springframework.beans.factory.FactoryBean
;
import
org.springframework.beans.factory.config.BeanDefinition
;
import
org.springframework.beans.factory.config.BeanDefinitionHolder
;
import
org.springframework.beans.factory.config.ConfigurableListableBeanFactory
;
import
org.springframework.beans.factory.config.DependencyDescriptor
;
import
org.springframework.core.ResolvableType
;
import
org.springframework.util.ClassUtils
;
...
...
@@ -77,22 +79,13 @@ public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandid
if
(
bdHolder
.
getBeanDefinition
()
instanceof
RootBeanDefinition
)
{
rbd
=
(
RootBeanDefinition
)
bdHolder
.
getBeanDefinition
();
}
if
(
rbd
!=
null
&&
rbd
.
getFactoryMethodName
()
!=
null
)
{
// Should typically be set for any kind of factory method, since the BeanFactory
// pre-resolves them before reaching out to the AutowireCandidateResolver...
Class
<?>
preResolved
=
rbd
.
resolvedFactoryMethodReturnType
;
if
(
preResolved
!=
null
)
{
targetType
=
ResolvableType
.
forClass
(
preResolved
);
}
else
{
Method
resolvedFactoryMethod
=
rbd
.
getResolvedFactoryMethod
();
if
(
resolvedFactoryMethod
!=
null
)
{
if
(
descriptor
.
getDependencyType
().
isAssignableFrom
(
resolvedFactoryMethod
.
getReturnType
()))
{
// Only use factory method metadata if the return type is actually expressive enough
// for our dependency. Otherwise, the returned instance type may have matched instead
// in case of a singleton instance having been registered with the container already.
targetType
=
ResolvableType
.
forMethodReturnType
(
resolvedFactoryMethod
);
}
if
(
rbd
!=
null
)
{
// First, check factory method return type, if applicable
targetType
=
getReturnTypeForFactoryMethod
(
rbd
,
descriptor
);
if
(
targetType
==
null
)
{
RootBeanDefinition
dbd
=
getResolvedDecoratedDefinition
(
rbd
);
if
(
dbd
!=
null
)
{
targetType
=
getReturnTypeForFactoryMethod
(
dbd
,
descriptor
);
}
}
}
...
...
@@ -122,6 +115,41 @@ public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandid
return
dependencyType
.
isAssignableFrom
(
targetType
);
}
protected
RootBeanDefinition
getResolvedDecoratedDefinition
(
RootBeanDefinition
rbd
)
{
BeanDefinitionHolder
decDef
=
rbd
.
getDecoratedDefinition
();
if
(
decDef
!=
null
&&
this
.
beanFactory
instanceof
ConfigurableListableBeanFactory
)
{
ConfigurableListableBeanFactory
clbf
=
(
ConfigurableListableBeanFactory
)
this
.
beanFactory
;
if
(
clbf
.
containsBeanDefinition
(
decDef
.
getBeanName
()))
{
BeanDefinition
dbd
=
clbf
.
getMergedBeanDefinition
(
decDef
.
getBeanName
());
if
(
dbd
instanceof
RootBeanDefinition
)
{
return
(
RootBeanDefinition
)
dbd
;
}
}
}
return
null
;
}
protected
ResolvableType
getReturnTypeForFactoryMethod
(
RootBeanDefinition
rbd
,
DependencyDescriptor
descriptor
)
{
// Should typically be set for any kind of factory method, since the BeanFactory
// pre-resolves them before reaching out to the AutowireCandidateResolver...
Class
<?>
preResolved
=
rbd
.
resolvedFactoryMethodReturnType
;
if
(
preResolved
!=
null
)
{
return
ResolvableType
.
forClass
(
preResolved
);
}
else
{
Method
resolvedFactoryMethod
=
rbd
.
getResolvedFactoryMethod
();
if
(
resolvedFactoryMethod
!=
null
)
{
if
(
descriptor
.
getDependencyType
().
isAssignableFrom
(
resolvedFactoryMethod
.
getReturnType
()))
{
// Only use factory method metadata if the return type is actually expressive enough
// for our dependency. Otherwise, the returned instance type may have matched instead
// in case of a singleton instance having been registered with the container already.
return
ResolvableType
.
forMethodReturnType
(
resolvedFactoryMethod
);
}
}
return
null
;
}
}
/**
* This implementation always returns {@code null}, leaving suggested value support up
...
...
spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java
浏览文件 @
8580d2d1
...
...
@@ -158,8 +158,43 @@ public class ConfigurationClassPostProcessorTests {
pp
.
postProcessBeanFactory
(
beanFactory
);
RepositoryInjectionBean
bean
=
(
RepositoryInjectionBean
)
beanFactory
.
getBean
(
"annotatedBean"
);
assertSame
(
beanFactory
.
getBean
(
"stringRepo"
),
bean
.
stringRepository
);
assertSame
(
beanFactory
.
getBean
(
"integerRepo"
),
bean
.
integerRepository
);
assertEquals
(
"Repository<String>"
,
bean
.
stringRepository
.
toString
());
assertEquals
(
"Repository<Integer>"
,
bean
.
integerRepository
.
toString
());
}
@Test
public
void
testGenericsBasedInjectionWithScoped
()
{
AutowiredAnnotationBeanPostProcessor
bpp
=
new
AutowiredAnnotationBeanPostProcessor
();
bpp
.
setBeanFactory
(
beanFactory
);
beanFactory
.
addBeanPostProcessor
(
bpp
);
RootBeanDefinition
bd
=
new
RootBeanDefinition
(
RepositoryInjectionBean
.
class
);
bd
.
setScope
(
RootBeanDefinition
.
SCOPE_PROTOTYPE
);
beanFactory
.
registerBeanDefinition
(
"annotatedBean"
,
bd
);
beanFactory
.
registerBeanDefinition
(
"configClass"
,
new
RootBeanDefinition
(
ScopedRepositoryConfiguration
.
class
));
ConfigurationClassPostProcessor
pp
=
new
ConfigurationClassPostProcessor
();
pp
.
postProcessBeanFactory
(
beanFactory
);
RepositoryInjectionBean
bean
=
(
RepositoryInjectionBean
)
beanFactory
.
getBean
(
"annotatedBean"
);
assertEquals
(
"Repository<String>"
,
bean
.
stringRepository
.
toString
());
assertEquals
(
"Repository<Integer>"
,
bean
.
integerRepository
.
toString
());
}
@Test
public
void
testGenericsBasedInjectionWithScopedProxy
()
{
AutowiredAnnotationBeanPostProcessor
bpp
=
new
AutowiredAnnotationBeanPostProcessor
();
bpp
.
setBeanFactory
(
beanFactory
);
beanFactory
.
addBeanPostProcessor
(
bpp
);
RootBeanDefinition
bd
=
new
RootBeanDefinition
(
RepositoryInjectionBean
.
class
);
bd
.
setScope
(
RootBeanDefinition
.
SCOPE_PROTOTYPE
);
beanFactory
.
registerBeanDefinition
(
"annotatedBean"
,
bd
);
beanFactory
.
registerBeanDefinition
(
"configClass"
,
new
RootBeanDefinition
(
ScopedProxyRepositoryConfiguration
.
class
));
ConfigurationClassPostProcessor
pp
=
new
ConfigurationClassPostProcessor
();
pp
.
postProcessBeanFactory
(
beanFactory
);
beanFactory
.
freezeConfiguration
();
RepositoryInjectionBean
bean
=
(
RepositoryInjectionBean
)
beanFactory
.
getBean
(
"annotatedBean"
);
assertEquals
(
"Repository<String>"
,
bean
.
stringRepository
.
toString
());
assertEquals
(
"Repository<Integer>"
,
bean
.
integerRepository
.
toString
());
}
@Test
...
...
@@ -295,12 +330,72 @@ public class ConfigurationClassPostProcessorTests {
@Bean
public
Repository
<
String
>
stringRepo
()
{
return
new
Repository
<
String
>();
return
new
Repository
<
String
>()
{
@Override
public
String
toString
()
{
return
"Repository<String>"
;
}
};
}
@Bean
public
Repository
<
Integer
>
integerRepo
()
{
return
new
Repository
<
Integer
>();
return
new
Repository
<
Integer
>()
{
@Override
public
String
toString
()
{
return
"Repository<Integer>"
;
}
};
}
}
@Configuration
public
static
class
ScopedRepositoryConfiguration
{
@Bean
@Scope
(
"prototype"
)
public
Repository
<
String
>
stringRepo
()
{
return
new
Repository
<
String
>()
{
@Override
public
String
toString
()
{
return
"Repository<String>"
;
}
};
}
@Bean
@Scope
(
"prototype"
)
public
Repository
<
Integer
>
integerRepo
()
{
return
new
Repository
<
Integer
>()
{
@Override
public
String
toString
()
{
return
"Repository<Integer>"
;
}
};
}
}
@Configuration
public
static
class
ScopedProxyRepositoryConfiguration
{
@Bean
@Scope
(
value
=
"prototype"
,
proxyMode
=
ScopedProxyMode
.
TARGET_CLASS
)
public
Repository
<
String
>
stringRepo
()
{
return
new
Repository
<
String
>()
{
@Override
public
String
toString
()
{
return
"Repository<String>"
;
}
};
}
@Bean
@Scope
(
value
=
"prototype"
,
proxyMode
=
ScopedProxyMode
.
TARGET_CLASS
)
public
Repository
<
Integer
>
integerRepo
()
{
return
new
Repository
<
Integer
>()
{
@Override
public
String
toString
()
{
return
"Repository<Integer>"
;
}
};
}
}
...
...
spring-context/src/test/java/org/springframework/context/annotation/configuration/BeanMethodQualificationTests.java
浏览文件 @
8580d2d1
...
...
@@ -21,16 +21,17 @@ import java.lang.annotation.RetentionPolicy;
import
org.junit.Test
;
import
org.springframework.tests.sample.beans.NestedTestBean
;
import
org.springframework.tests.sample.beans.TestBean
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Qualifier
;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Lazy
;
import
org.springframework.context.annotation.Scope
;
import
org.springframework.context.annotation.ScopedProxyMode
;
import
org.springframework.stereotype.Component
;
import
org.springframework.tests.sample.beans.NestedTestBean
;
import
org.springframework.tests.sample.beans.TestBean
;
import
static
org
.
hamcrest
.
CoreMatchers
.*;
import
static
org
.
junit
.
Assert
.*;
...
...
@@ -53,6 +54,24 @@ public class BeanMethodQualificationTests {
assertThat
(
pojo
.
testBean
.
getName
(),
equalTo
(
"interesting"
));
}
@Test
public
void
testScoped
()
{
AnnotationConfigApplicationContext
ctx
=
new
AnnotationConfigApplicationContext
(
ScopedConfig
.
class
,
StandardPojo
.
class
);
assertFalse
(
ctx
.
getBeanFactory
().
containsSingleton
(
"testBean1"
));
StandardPojo
pojo
=
ctx
.
getBean
(
StandardPojo
.
class
);
assertThat
(
pojo
.
testBean
.
getName
(),
equalTo
(
"interesting"
));
}
@Test
public
void
testScopedProxy
()
{
AnnotationConfigApplicationContext
ctx
=
new
AnnotationConfigApplicationContext
(
ScopedProxyConfig
.
class
,
StandardPojo
.
class
);
assertTrue
(
ctx
.
getBeanFactory
().
containsSingleton
(
"testBean1"
));
// a shared scoped proxy
StandardPojo
pojo
=
ctx
.
getBean
(
StandardPojo
.
class
);
assertThat
(
pojo
.
testBean
.
getName
(),
equalTo
(
"interesting"
));
}
@Test
public
void
testCustom
()
{
AnnotationConfigApplicationContext
ctx
=
...
...
@@ -75,7 +94,7 @@ public class BeanMethodQualificationTests {
@Configuration
static
class
StandardConfig
{
@Bean
@
Lazy
@Qualifier
(
"interesting"
)
@Bean
@
Qualifier
(
"interesting"
)
@Lazy
public
TestBean
testBean1
()
{
return
new
TestBean
(
"interesting"
);
}
...
...
@@ -86,6 +105,34 @@ public class BeanMethodQualificationTests {
}
}
@Configuration
static
class
ScopedConfig
{
@Bean
@Qualifier
(
"interesting"
)
@Scope
(
"prototype"
)
public
TestBean
testBean1
()
{
return
new
TestBean
(
"interesting"
);
}
@Bean
@Qualifier
(
"boring"
)
@Scope
(
"prototype"
)
public
TestBean
testBean2
()
{
return
new
TestBean
(
"boring"
);
}
}
@Configuration
static
class
ScopedProxyConfig
{
@Bean
@Qualifier
(
"interesting"
)
@Scope
(
value
=
"prototype"
,
proxyMode
=
ScopedProxyMode
.
TARGET_CLASS
)
public
TestBean
testBean1
()
{
return
new
TestBean
(
"interesting"
);
}
@Bean
@Qualifier
(
"boring"
)
@Scope
(
value
=
"prototype"
,
proxyMode
=
ScopedProxyMode
.
TARGET_CLASS
)
public
TestBean
testBean2
()
{
return
new
TestBean
(
"boring"
);
}
}
@Component
@Lazy
static
class
StandardPojo
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录