Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
spring-cloud-netflix
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
openSource
spring-cloud-netflix
Commits
7f9642ff
Commit
7f9642ff
authored
Dec 05, 2014
by
Spencer Gibb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
new @FeignClient annotation
parent
b7db6586
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
337 additions
and
0 deletions
+337
-0
FeignClient.java
.../org/springframework/cloud/netflix/feign/FeignClient.java
+14
-0
FeignClientScan.java
.../springframework/cloud/netflix/feign/FeignClientScan.java
+54
-0
FeignClientScanRegistrar.java
...amework/cloud/netflix/feign/FeignClientScanRegistrar.java
+155
-0
FeignClientTests.java
...springframework/cloud/netflix/feign/FeignClientTests.java
+114
-0
No files found.
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java
0 → 100644
View file @
7f9642ff
package
org
.
springframework
.
cloud
.
netflix
.
feign
;
import
java.lang.annotation.*
;
/**
* @author Spencer Gibb
*/
@Target
(
ElementType
.
TYPE
)
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Documented
public
@interface
FeignClient
{
String
value
();
boolean
loadbalance
()
default
true
;
}
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientScan.java
0 → 100644
View file @
7f9642ff
package
org
.
springframework
.
cloud
.
netflix
.
feign
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.Target
;
import
org.springframework.context.annotation.Import
;
/**
* Configures component scanning directives for use with @{@link org.springframework.context.annotation.Configuration} classes.
* Scan Spring Integration specific components.
*
* @author Artem Bilan
* @since 4.0
*/
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
(
ElementType
.
TYPE
)
@Documented
@Import
(
FeignClientScanRegistrar
.
class
)
public
@interface
FeignClientScan
{
/**
* Alias for the {@link #basePackages()} attribute.
* Allows for more concise annotation declarations e.g.:
* {@code @ComponentScan("org.my.pkg")} instead of
* {@code @ComponentScan(basePackages="org.my.pkg")}.
*
* @return the array of 'basePackages'.
*/
String
[]
value
()
default
{};
/**
* Base packages to scan for annotated components.
* <p>{@link #value()} is an alias for (and mutually exclusive with) this attribute.
* <p>Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names.
*
* @return the array of 'basePackages'.
*/
String
[]
basePackages
()
default
{};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages
* to scan for annotated components. The package of each class specified will be scanned.
* <p>Consider creating a special no-op marker class or interface in each package
* that serves no purpose other than being referenced by this attribute.
*
* @return the array of 'basePackageClasses'.
*/
Class
<?>[]
basePackageClasses
()
default
{};
}
\ No newline at end of file
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientScanRegistrar.java
0 → 100644
View file @
7f9642ff
package
org
.
springframework
.
cloud
.
netflix
.
feign
;
import
java.lang.annotation.Annotation
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
import
lombok.Data
;
import
org.springframework.beans.factory.BeanClassLoaderAware
;
import
org.springframework.beans.factory.FactoryBean
;
import
org.springframework.beans.factory.annotation.AnnotatedBeanDefinition
;
import
org.springframework.beans.factory.config.BeanDefinition
;
import
org.springframework.beans.factory.config.BeanDefinitionHolder
;
import
org.springframework.beans.factory.support.BeanDefinitionBuilder
;
import
org.springframework.beans.factory.support.BeanDefinitionReaderUtils
;
import
org.springframework.beans.factory.support.BeanDefinitionRegistry
;
import
org.springframework.context.ResourceLoaderAware
;
import
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider
;
import
org.springframework.context.annotation.ImportBeanDefinitionRegistrar
;
import
org.springframework.core.io.ResourceLoader
;
import
org.springframework.core.type.AnnotationMetadata
;
import
org.springframework.core.type.filter.AnnotationTypeFilter
;
import
org.springframework.util.Assert
;
import
org.springframework.util.ClassUtils
;
import
org.springframework.util.StringUtils
;
/**
* @author Spencer Gibb
* patterned after Spring Integration IntegrationComponentScanRegistrar
*/
public
class
FeignClientScanRegistrar
extends
FeignConfiguration
implements
ImportBeanDefinitionRegistrar
,
ResourceLoaderAware
,
BeanClassLoaderAware
{
private
ResourceLoader
resourceLoader
;
private
ClassLoader
classLoader
;
public
FeignClientScanRegistrar
()
{
}
@Override
public
void
setResourceLoader
(
ResourceLoader
resourceLoader
)
{
this
.
resourceLoader
=
resourceLoader
;
}
@Override
public
void
setBeanClassLoader
(
ClassLoader
classLoader
)
{
this
.
classLoader
=
classLoader
;
}
@Override
public
void
registerBeanDefinitions
(
AnnotationMetadata
importingClassMetadata
,
BeanDefinitionRegistry
registry
)
{
Map
<
String
,
Object
>
componentScan
=
importingClassMetadata
.
getAnnotationAttributes
(
FeignClientScan
.
class
.
getCanonicalName
());
Set
<
String
>
basePackages
=
new
HashSet
<
String
>();
for
(
String
pkg
:
(
String
[])
componentScan
.
get
(
"value"
))
{
if
(
StringUtils
.
hasText
(
pkg
))
{
basePackages
.
add
(
pkg
);
}
}
for
(
String
pkg
:
(
String
[])
componentScan
.
get
(
"basePackages"
))
{
if
(
StringUtils
.
hasText
(
pkg
))
{
basePackages
.
add
(
pkg
);
}
}
for
(
Class
<?>
clazz
:
(
Class
[])
componentScan
.
get
(
"basePackageClasses"
))
{
basePackages
.
add
(
ClassUtils
.
getPackageName
(
clazz
));
}
if
(
basePackages
.
isEmpty
())
{
basePackages
.
add
(
ClassUtils
.
getPackageName
(
importingClassMetadata
.
getClassName
()));
}
ClassPathScanningCandidateComponentProvider
scanner
=
new
ClassPathScanningCandidateComponentProvider
(
false
)
{
@Override
protected
boolean
isCandidateComponent
(
AnnotatedBeanDefinition
beanDefinition
)
{
if
(
beanDefinition
.
getMetadata
().
isIndependent
())
{
// TODO until SPR-11711 will be resolved
if
(
beanDefinition
.
getMetadata
().
isInterface
()
&&
beanDefinition
.
getMetadata
().
getInterfaceNames
().
length
==
1
&&
Annotation
.
class
.
getName
().
equals
(
beanDefinition
.
getMetadata
().
getInterfaceNames
()[
0
]))
{
try
{
Class
<?>
target
=
ClassUtils
.
forName
(
beanDefinition
.
getMetadata
().
getClassName
(),
classLoader
);
return
!
target
.
isAnnotation
();
}
catch
(
Exception
e
)
{
logger
.
error
(
"Could not load target class: "
+
beanDefinition
.
getMetadata
().
getClassName
(),
e
);
}
}
return
true
;
}
return
false
;
}
};
scanner
.
addIncludeFilter
(
new
AnnotationTypeFilter
(
FeignClient
.
class
));
scanner
.
setResourceLoader
(
resourceLoader
);
for
(
String
basePackage
:
basePackages
)
{
Set
<
BeanDefinition
>
candidateComponents
=
scanner
.
findCandidateComponents
(
basePackage
);
for
(
BeanDefinition
candidateComponent
:
candidateComponents
)
{
if
(
candidateComponent
instanceof
AnnotatedBeanDefinition
)
{
AnnotatedBeanDefinition
beanDefinition
=
(
AnnotatedBeanDefinition
)
candidateComponent
;
BeanDefinitionBuilder
definition
=
BeanDefinitionBuilder
.
genericBeanDefinition
(
FeignFactoryBean
.
class
);
AnnotationMetadata
annotationMetadata
=
beanDefinition
.
getMetadata
();
Assert
.
isTrue
(
annotationMetadata
.
isInterface
(),
"@FeignClient can only be specified on an interface"
);
Map
<
String
,
Object
>
attributes
=
annotationMetadata
.
getAnnotationAttributes
(
FeignClient
.
class
.
getCanonicalName
());
String
className
=
annotationMetadata
.
getClassName
();
definition
.
addPropertyValue
(
"loadbalance"
,
attributes
.
get
(
"loadbalance"
));
definition
.
addPropertyValue
(
"type"
,
className
);
definition
.
addPropertyValue
(
"schemeName"
,
attributes
.
get
(
"value"
));
String
beanName
=
StringUtils
.
uncapitalize
(
className
.
substring
(
className
.
lastIndexOf
(
"."
)+
1
));
BeanDefinitionHolder
holder
=
new
BeanDefinitionHolder
(
definition
.
getBeanDefinition
(),
beanName
);
BeanDefinitionReaderUtils
.
registerBeanDefinition
(
holder
,
registry
);
}
}
}
}
@Data
public
static
class
FeignFactoryBean
extends
FeignConfiguration
implements
FactoryBean
<
Object
>
{
boolean
loadbalance
;
Class
<?>
type
;
String
schemeName
;
@Override
public
Object
getObject
()
throws
Exception
{
if
(!
schemeName
.
startsWith
(
"http"
))
{
schemeName
=
"http://"
+
schemeName
;
}
if
(
loadbalance
)
{
return
loadBalance
(
type
,
schemeName
);
}
return
feign
().
target
(
type
,
schemeName
);
}
@Override
public
Class
<?>
getObjectType
()
{
return
type
;
}
@Override
public
boolean
isSingleton
()
{
return
true
;
}
}
}
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/FeignClientTests.java
0 → 100644
View file @
7f9642ff
package
org
.
springframework
.
cloud
.
netflix
.
feign
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
java.lang.reflect.InvocationHandler
;
import
java.lang.reflect.Proxy
;
import
java.util.ArrayList
;
import
java.util.List
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.boot.test.IntegrationTest
;
import
org.springframework.boot.test.SpringApplicationConfiguration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
;
import
org.springframework.test.context.web.WebAppConfiguration
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RestController
;
/**
* @author Spencer Gibb
*/
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
@SpringApplicationConfiguration
(
classes
=
FeignClientTests
.
Application
.
class
)
@WebAppConfiguration
@IntegrationTest
({
"server.port=0"
,
"spring.application.name=feignclienttest"
,
"spring.jmx.enabled=true"
})
public
class
FeignClientTests
extends
FeignConfiguration
{
@Value
(
"${local.server.port}"
)
private
int
port
=
0
;
@Autowired
TestClient
testClient
;
//@FeignClient(value = "http://localhost:9876", loadbalance = false)
@FeignClient
(
"feignclienttest"
)
protected
static
interface
TestClient
{
@RequestMapping
(
method
=
RequestMethod
.
GET
,
value
=
"/hello"
)
public
Hello
getHello
();
@RequestMapping
(
method
=
RequestMethod
.
GET
,
value
=
"/hellos"
)
public
List
<
Hello
>
getHellos
();
@RequestMapping
(
method
=
RequestMethod
.
GET
,
value
=
"/hellostrings"
)
public
List
<
String
>
getHelloStrings
();
}
@Configuration
@EnableAutoConfiguration
@RestController
@FeignClientScan
protected
static
class
Application
{
@RequestMapping
(
method
=
RequestMethod
.
GET
,
value
=
"/hello"
)
public
Hello
getHello
()
{
return
new
Hello
(
"hello world 1"
);
}
@RequestMapping
(
method
=
RequestMethod
.
GET
,
value
=
"/hellos"
)
public
List
<
Hello
>
getHellos
()
{
ArrayList
<
Hello
>
hellos
=
new
ArrayList
<>();
hellos
.
add
(
new
Hello
(
"hello world 1"
));
hellos
.
add
(
new
Hello
(
"oi terra 2"
));
return
hellos
;
}
@RequestMapping
(
method
=
RequestMethod
.
GET
,
value
=
"/hellostrings"
)
public
List
<
String
>
getHelloStrings
()
{
ArrayList
<
String
>
hellos
=
new
ArrayList
<>();
hellos
.
add
(
"hello world 1"
);
hellos
.
add
(
"oi terra 2"
);
return
hellos
;
}
public
static
void
main
(
String
[]
args
)
{
new
SpringApplicationBuilder
(
Application
.
class
).
properties
(
"spring.application.name=feignclienttest"
,
"management.contextPath=/admin"
)
.
run
(
args
);
}
}
@Test
public
void
testClient
()
{
assertNotNull
(
"testClient was null"
,
testClient
);
assertTrue
(
"testClient is not a java Proxy"
,
Proxy
.
isProxyClass
(
testClient
.
getClass
()));
InvocationHandler
invocationHandler
=
Proxy
.
getInvocationHandler
(
testClient
);
assertNotNull
(
"invocationHandler was null"
,
invocationHandler
);
}
//TODO: only works if port is hardcoded cant resolve ${local.server.port} in annotation
/*@Test
public void testSimpleType() {
Hello hello = testClient.getHello();
assertNotNull("hello was null", hello);
assertEquals("first hello didn't match", new Hello("hello world 1"), hello);
}*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public
static
class
Hello
{
private
String
message
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment