i would like to understand what is the programmatic equivalent of a #Bean annotated bean registration
Lets say i have a class like this:
#Configuration
public class SimpleConfiguration {
#Bean
public BigDecimal aDecimal( String example ) {
return new BigDecimal( example );
}
}
here is what i think happens here:
somehow spring register this method as a factory for a bean named
"aDecimal" of type BigDecimal, with a dependency on a bean of type
String
at some point this method will be called with the right bean as
parameter and the result will be the instance associated to the
"aDecimal" bean.
If i wanted to do the same with something like this:
#Configuration
public class DynamicConfiguration {
public void registerDefinition() {
/* i know it can't be like this but i hope it's clear what i mean */
register( "aDecimal", (example) -> aDecimal( example ) );
}
public BigDecimal aDecimal( String example ) {
/* this could be any kind of complex bean creation method */
return new BigDecimal( example );
}
}
what would be the right way to achieve this result?
i already researched a bit about this, and i found for example
How do I create beans programmatically in Spring Boot?
but this kind of registration doesn't seem as powerful as the annotation, and let's spring instatiate the bean, i want the bean to be instatied by a provided method
How to programmatically create bean definition with injected properties?
and this is missing the ability to call a method with injected bean parameters.
the reason i want to do this, is that i have some configuration classes that hold a lot of the same kind of beans with different qualifiers, based on a configuration file.
now every time the configuration file expands, i need to add new beans and configurations ( many of these are spring SessionFactories and SpringIntegration flows so i need these things to be spring beans )
You need to consider to use IntegrationFlowContext:
#Autowired
private IntegrationFlowContext integrationFlowContext;
...
IntegrationFlow myFlow = f -> ...;
BeanFactoryHandler additionalBean = new BeanFactoryHandler();
IntegrationFlowRegistration flowRegistration =
this.integrationFlowContext.registration(myFlow)
.addBean(additionalBean)
.register();
It provides for you hooks to register additional beans at runtime, not only IntegrationFlow structure.
I found the way to solve my problem, it all happens in the BeanDefinition "phase" this way everything is managed by spring and works exactly the same as as a #Bean annotated method with injected parameters, it also cleanly bridge between annotated and programmatically registered beans.
here is what i did
#Configuration
#RunWith( SpringJUnit4ClassRunner.class )
#ContextConfiguration( classes = { TestSpringDynamicConfiguration.class } )
public class TestSpringDynamicConfiguration implements BeanDefinitionRegistryPostProcessor {
#Autowired
#Qualifier( "qualified" )
private String dynamicString;
#Bean
public Integer zero() {
return 0;
}
public String zeroString( Integer aInteger ) {
return aInteger.toString();
}
#Override
public void postProcessBeanDefinitionRegistry( final BeanDefinitionRegistry registry ) throws BeansException {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setAutowireMode( GenericBeanDefinition.AUTOWIRE_CONSTRUCTOR );
beanDefinition.setScope( BeanDefinition.SCOPE_SINGLETON );
beanDefinition.setFactoryBeanName( "testSpringDynamicConfiguration" );
beanDefinition.setFactoryMethodName( "zeroString" );
registry.registerBeanDefinition( "qualified", beanDefinition );
}
#Override public void postProcessBeanFactory( final ConfigurableListableBeanFactory beanFactory ) throws BeansException { }
#Test
public void testDynamicConfiguration() throws Exception {
assertThat( dynamicString, is( "0" ) );
}
}
Related
I am using Spring AOP to fire metrics in our application. I have created an annotation #CaptureMetrics which has an #around advice associated with it. The advice is invoked fine from all the methods tagged with #CaptureMetrics except for a case when a method is invoked on a prototype bean.
The annotation has #Target({ElementType.TYPE, ElementType.METHOD})
PointCut expression:
#Around(value = "execution(* *.*(..)) && #annotation(captureMetrics)",
argNames = "joinPoint,captureMetrics")
Prototype bean creation
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public DummyService getDummyServicePrototypeBean(int a, String b) {
return new DummyService(a, b);
}
DummyService has a method called dummyMethod(String dummyString)
#CaptureMetrics(type = MetricType.SOME_TYPE, name = "XYZ")
public Response dummyMethod(id) throws Exception {
// Do some work here
}
When dummyService.dummyMethod("123") is invoked from some other service, the #Around advice is not called.
Config class
#Configuration
public class DummyServiceConfig {
#Bean
public DummyServiceRegistry dummyServiceRegistry(
#Value("${timeout}") Integer timeout,
#Value("${dummy.secrets.path}") Resource dummySecretsPath) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Map<String, String> transactionSourceToTokens = mapper.readValue(
dummySecretsPath.getFile(), new TypeReference<Map<String, String>>() {
});
DummyServiceRegistry registry = new DummyServiceRegistry();
transactionSourceToTokens.forEach((transactionSource, token) ->
registry.register(transactionSource,
getDummyServicePrototypeBean(timeout, token)));
return registry;
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public DummyService getDummyServicePrototypeBean(int a, String b) {
return new DummyService(a, b);
}
}
Singleton Registry class
public class DummyServiceRegistry {
private final Map<String, DummyService> transactionSourceToService = new HashMap<>();
public void register(String transactionSource, DummyService dummyService) {
this.transactionSourceToService.put(transactionSource, dummyService);
}
public Optional<DummyService> lookup(String transactionSource) {
return Optional.ofNullable(transactionSourceToService.get(transactionSource));
}
}
Any advice on this please?
Note:
The prototype Dummy service is used to call a third party client. It is a prototype bean as it has a state that varies based on whose behalf it is going to call the third party.
A singleton registry bean during initialization builds a map of {source_of_request, dummyService_prototype}. To get the dummyService prototype it calls getDummyServicePrototypeBean()
The configuration, registry and prototype dummy bean were correct.
I was testing the flow using an existing integration test and there instead of supplying a prototype Bean, new objects of DummyService were instantiated using the new keyword. It wasn't a spring managed bean.
Spring AOP works only with Spring managed beans.
In a spring based project I am working on, there's a layer of functionality for calling web service. For each web service operation, a method is created with almost same code but with some different, operation specific, information(e.g. service name, operation name, namespaces, etc).
I am replacing this layer with interfaces and annotated methods. For example, below code is provided for operation "fetchBar" of web service("foo").
package a.b.c.webservices;
#WebService(service="foo", namespace="...")
public interface FooWebService {
#WebServiceOperation(operation="fetchBar")
BarRespons fetchBar(BarRequest request) throws WebServiceException;
}
Now I want, with some mechanism, spring allow me to create dynamic proxy beans from some specified package(s) and I can use following code to call web service.
package a.b.c.business;
import a.b.c.webservices.FooWebService;
public class FooBusiness {
#Autowired
FooWebService fooWebService;
public Bar getBar() {
Bar bar = null;
BarRequest request;
//create request
BarResponse response = fooWebService.fetchBar(request);
//extrac bar from response
return bar;
}
}
To achieve this I have created dynamic beans instances using java.lang.reflect.Proxy.newProxyInstance by providing it implementation of InvocationHandler. But Autowiring doesn't work in provided implementation of invocationHandler and in its further dependencies.
I tried following ways to achieve this.
Implemented BeanFactoryPostProcessor.postProcessBeanFactory and registered beans using ConfigurableListableBeanFactory.registerSingleton method.
Implemented ImportBeanDefinitionRegistrar.registerBeanDefinitions and tried to use BeanDefinitionRegistry.registerBeanDefinition but I am confused how to provide correct Bean definition that supports Autowiring.
Can any one tell me what is missing? Please guide me if I am not going in right direction.
Here's how I implemented all the functionality that creates beans of 'WebService' annotated interfaces and also supports Autowiring inside proxy implementation. (package declaration and import statements are omitted in below code)
First of all I created WebService and WebServiceOperation annotation.
WebService Annotation
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface WebService {
String service();
String namespace();
}
WebService Operation Annotation
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface WebServiceOperation {
String operation();
}
Next step is to scan all WebService annotated interfaces from specified packages. Spring provides ClassPathScanningCandidateComponentProvider for package scanning but it does not detect interfaces. Please see this question and it's answer for more details. So I extended ClassPathScanningCandidateComponentProvider and overrode isCandidateComponent method.
ClassPathScanner
public class ClassPathScanner extends ClassPathScanningCandidateComponentProvider {
public ClassPathScanner(final boolean useDefaultFilters) {
super(useDefaultFilters);
}
#Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isIndependent();
}
}
At this point I created EnableWebServices annotation to enable web services and to provide web service packages that contain WebService annotated interfaces.
EnableWebServices Annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#Import({
WebServiceProxyConfig.class,
WebServiceProxyBeansRegistrar.class
})
public #interface EnableWebServices {
#AliasFor("basePackages")
String[] value() default {};
#AliasFor("value")
String[] basePackages() default {};
}
This annotation can be applied to some Configuration annotated class with packages to scan interfaces, as below.
#EnableWebServices({
"a.b.c.webservices",
"x.y.z.webservices"
})
It's time to think about dynamic proxy creation that will invoke actual web service from information given in WebService and WebServiceOperation annotations. Java provides a mechanism to create dynamic proxy which requires to provide implementation of InvocationHandler interface and provide logic in its invoke method. I named this implementaiton as WebServiceProxy
Suppose a bean of type 'TheWebServiceCaller' contains all nasty logic to call a web service. I just have inject it and to invoke it's call method with a TheWebServiceInfo (extracted from WebService and WebServiceOperation annotations) and request object.
TheWebServiceInfo(Suppose all fields have getters and setters)
public class TheWebServiceInfo {
private String service;
private String namespace;
private String operation;
}
WebServiceProxy
public class WebServiceProxy implements InvocationHandler {
#Autowired
private TheWebServiceCaller caller;
#Override
public Object invoke(Object target, Method method, Object[] args) throws Exception {
Object request = (null != args && args.length > 0) ? args[0] : null;
WebService webService = method.getDeclaringClass().getAnnotation(WebService.class);
WebServiceOperation webServiceOperation = method.getAnnotation(WebServiceOperation.class);
TheWebServiceInfo theInfo = createTheWebServiceInfo(webService, webServiceOperation);
return caller.call(theInfo, request);
}
private TheWebServiceInfo createTheWebServiceInfo(WebService webService, WebServiceOperation webServiceOperation) {
TheWebServiceInfo theInfo = new TheWebServiceInfo();
theInfo.setService(webService.service());
theInfo.setNamespace(webService.namespace());
theInfo.setOperation(webServiceOperation.operation());
return theInfo;
}
}
Implementaion of InvocationHandler is passed to Proxy.newProxyInstance (along with some other information) to create proxy objects. I need separat proxy objectes for each WebService annotated interface. I will now create a factory to proxy instances creation and name is as 'WebServiceProxyBeanFactory'. Instances created by this factory will become beans for corresponding WebService annotated interfaces.
A bit later, I will expose 'WebServiceProxy' and WebServiceProxyBeanFactory as beans. In 'WebServiceProxyBeanFactory', I will inject WebServiceProxy and used it. Please note that createWebServiceProxyBean uses generics. This is important.
WebServiceProxyBeanFactory
public class WebServiceProxyBeanFactory {
#Autowired
WebServiceProxy webServiceProxy;
#SuppressWarnings("unchecked")
public <WS> WS createWebServiceProxyBean(ClassLoader classLoader, Class<WS> clazz) {
return (WS) Proxy.newProxyInstance(classLoader, new Class[] {clazz}, webServiceProxy);
}
}
If you remember, earlier I have imported WebServiceProxyConfig in EnableWebServices annotations. WebServiceProxyConfig is used to expose WebServiceProxy and WebServiceProxyBeanFactory as beans.
WebServiceProxyConfig
#Configuration
public class WebServiceProxyConfig {
#Bean
public WebServiceProxy webServiceProxy() {
return new WebServiceProxy();
}
#Bean(name = "webServiceProxyBeanFactory")
public WebServiceProxyBeanFactory webServiceProxyBeanFactory() {
return new WebServiceProxyBeanFactory();
}
}
Now everything is in place. it's time to write a hook to start scanning Web service packages and register dynamic proxies as beans. I will provide implementation of ImportBeanDefinitionRegistrar.
WebServiceProxyBeansRegistrar
#Configuration
public class WebServiceProxyBeansRegistrar implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware {
private ClassPathScanner classpathScanner;
private ClassLoader classLoader;
public WebServiceProxyBeansRegistrar() {
classpathScanner = new ClassPathScanner(false);
classpathScanner.addIncludeFilter(new AnnotationTypeFilter(WebService.class));
}
#Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
#Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
String[] basePackages = getBasePackages(importingClassMetadata);
if (ArrayUtils.isNotEmpty(basePackages)) {
for (String basePackage : basePackages) {
createWebServicProxies(basePackage, registry);
}
}
}
private String[] getBasePackages(AnnotationMetadata importingClassMetadata) {
String[] basePackages = null;
MultiValueMap<String, Object> allAnnotationAttributes =
importingClassMetadata.getAllAnnotationAttributes(EnableWebServices.class.getName());
if (MapUtils.isNotEmpty(allAnnotationAttributes)) {
basePackages = (String[]) allAnnotationAttributes.getFirst("basePackages");
}
return basePackages;
}
private void createWebServicProxies(String basePackage, BeanDefinitionRegistry registry) {
try {
for (BeanDefinition beanDefinition : classpathScanner.findCandidateComponents(basePackage)) {
Class<?> clazz = Class.forName(beanDefinition.getBeanClassName());
WebService webService = clazz.getAnnotation(WebService.class);
String beanName = StringUtils.isNotEmpty(webService.bean())
? webService.bean() : ClassUtils.getShortNameAsProperty(clazz);
GenericBeanDefinition proxyBeanDefinition = new GenericBeanDefinition();
proxyBeanDefinition.setBeanClass(clazz);
ConstructorArgumentValues args = new ConstructorArgumentValues();
args.addGenericArgumentValue(classLoader);
args.addGenericArgumentValue(clazz);
proxyBeanDefinition.setConstructorArgumentValues(args);
proxyBeanDefinition.setFactoryBeanName("webServiceProxyBeanFactory");
proxyBeanDefinition.setFactoryMethodName("createWebServiceProxyBean");
registry.registerBeanDefinition(beanName, proxyBeanDefinition);
}
} catch (Exception e) {
System.out.println("Exception while createing proxy");
e.printStackTrace();
}
}
}
In this class, I extracted all packages provided in EnableWebServices annotation. for each extracted package, I used ClassPathScanner to scan. (Here logic can be refined to filter only WebService annotated interfaces). For each detected interface, I have registered a bean definitions. Please note I have used webServiceProxyBeanFactory and called its createWebServiceProxyBean with classLoader and type of interface. This factory method, when invoked by spring later, will return bean of same type as that of interface, so bean with correct type is registered. This bean can be injected anywhere with interface type. Moreover, WebServiceProxy can inject and use any other bean. So autowiring will also work as expected.
Is your InvocationHandler a bean? You should create it as a bean, not just a simple object to get Autowired working
I was thinking about the same problem but in a slightly more lightweight context. I don't need to load dynamicaly all the webservice clients. So instead I used a FactoryBean and within this factory bean I constructed the dynamic proxy. Here is one example where Autowiring of the service works:
public class CurrencyServiceWithDynamicProxy extends AbstractFactoryBean<CurrencyService> {
ServiceClientConfiguration clientConfiguration;
Object proxy;
#Autowired
public CurrencySyncFactoryDynamicProxy(ServiceClientConfigurationProvider serviceClientConfigurationProvider) {
this.clientConfiguration = serviceClientConfigurationProvider.createClientConfig("currency");
proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[] { getObjectType() }, new MyInvocationHandler());
}
#Override
public Class<CurrencySync> getObjectType() {
// TODO Auto-generated method stub
return CurrencyService.class;
}
#Override
public CurrencySync createInstance() throws Exception {
// do some creational logic
return (CurrencySync)proxy;
}
public CurrencySync createService() {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(getObjectType());
factory.getFeatures().add(som features);
return getObjectType().cast(factory.create());
}
}
With respect of the accepted answer this factory example can easily be extended into a more dynamic version.
I'm a Spring rookie and trying to benefit from the advantages of the easy 'profile' handling of Spring. I already worked through this tutorial: https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile and now I'd like to adapt that concept to an easy example.
I've got two profiles: dev and prod. I imagine a #Configuration class for each profile where I can instantiate different beans (implementing a common interface respectively) depending on the set profile.
My currently used classes look like this:
StatusController.java
#RestController
#RequestMapping("/status")
public class StatusController {
private final EnvironmentAwareBean environmentBean;
#Autowired
public StatusController(EnvironmentAwareBean environmentBean) {
this.environmentBean = environmentBean;
}
#RequestMapping(method = RequestMethod.GET)
Status getStatus() {
Status status = new Status();
status.setExtra("environmentBean=" + environmentBean.getString());
return status;
}
}
EnvironmentAwareBean.java
public interface EnvironmentAwareBean {
String getString();
}
EnvironmentAwareBean.java
#Service
public class DevBean implements EnvironmentAwareBean {
#Override
public String getString() {
return "development";
}
}
EnvironmentAwareBean.java
#Service
public class ProdBean implements EnvironmentAwareBean {
#Override
public String getString() {
return "production";
}
}
DevConfig.java
#Configuration
#Profile("dev")
public class DevConfig {
#Bean
public EnvironmentAwareBean getDevBean() {
return new DevBean();
}
}
ProdConfig.java
#Configuration
#Profile("prod")
public class ProdConfig {
#Bean
public EnvironmentAwareBean getProdBean() {
return new ProdBean();
}
}
Running the example throws this exception during startup (SPRING_PROFILES_DEFAULT is set to dev):
(...) UnsatisfiedDependencyException: (...) nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [EnvironmentAwareBean] is defined: expected single matching bean but found 3: prodBean,devBean,getDevBean
Is my approach far from a recommended configuration? In my opinion it would make more sense to annotate each Configuration with the #Profile annotation instead of doing it for each and every bean and possibly forgetting some variants when new classes are added later on.
Your implementations of EnvironmentAwareBean are all annotated with #Service.
This means they will all be picked up by component scanning and hence you get more than one matching bean. Do they need to be annotated with #Service?
Annotating each #Configuration with the #Profile annotation is fine. Another way as an educational exercise would be to not use #Profile and instead annotate the #Bean or Config classes with your own implementation of #Conditional.
I am trying to implement factory pattern to get producer from a list of available ones. While doing it i am getting the below exception. Not able to figure out the issue with the code. Can you please let me know what i am missing.
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.test.interfaces.Producer] is defined: expected single matching bean but found 2: A,B
Please find the code below
public interface Producer<T> {
public void start();
public List<T> produce() throws CEHServiceException;
public void stop();
}
#Component("A")
public class ProducerA extends Producer {
//Autowire Services & Properties
}
#Component("B")
public class ProducerB extends Producer {
//Autowire Services & Properties
}
#Configuration
public class AgentConfiguration {
#Bean
public ServiceLocatorFactoryBean createProducerFactoryBean(){
ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
bean.setServiceLocatorInterface(ProducerFactory.class);
return bean;
}
}
public interface ProducerFactory {
Producer getProducer(String producerName);
}
#Component
public class AdvancedAgentProcessor {
#Autowired
private ObjectFactory<AdvancedRunnerImpl> runnerFactory;
public void init(){
AdvancedRunnerImpl runner = runnerFactory.getObject();
runner.setProducerName("A");
runner.start();
}
}
#Component
#Scope("prototype")
public class AdvancedRunnerImpl implements Runner {
#Autowired private ProducerFactory producerFactory;
private Producer producer;
private String producerName;
public void start() {
producer = producerFactory.getProducer(this.producerName);
}
}
Full stack tracke
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.test.etl.interfaces.Producer] is defined: expected single matching bean but found 2: A,B
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:365)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
at org.springframework.beans.factory.config.ServiceLocatorFactoryBean$ServiceLocatorInvocationHandler.invokeServiceLocatorMethod(ServiceLocatorFactoryBean.java:377)
at org.springframework.beans.factory.config.ServiceLocatorFactoryBean$ServiceLocatorInvocationHandler.invoke(ServiceLocatorFactoryBean.java:363)
at com.sun.proxy.$Proxy34.getProducer(Unknown Source)
at com.test.runner.AdvancedRunnerImpl.start(AdvancedRunnerImpl.java:54)
at com.test.app.AdvancedAgentProcessor.init(AdvancedAgentProcessor.java:48)
at com.test.app.DataAgentApplication.main(DataAgentApplication.java:25)
Spring does not know which component to autowire. It seems that the problem is in the ProducerFactoryImplementation but we cannot see it.
There are three possible solutions:
Use Qualifiers so you can tell Spring which specific implementation you want.There is an example in StackOverflow
here
Use the Primary annotation (See more here3). That means that in case of ambiguity Spring will give priority to the #Primary annotated component
Autowire a list of beans. Something like:
#Autowired private List<Producer> myAvalilableProducers;
public Producer getByName(name){
for( Producer producer: myAvalilableProducers){
if(producer.getName().equals(name)){ return producer; }
}
throw new RuntimeException("No producer with name " + name " found");
}
This third option more useful when you do not know the specific instance at compile time or if you really want to inject a list of components.
You have two beans that extend Producer. Somewhere you are trying to autowire a Producer. Spring does not know which Producer to use.
This happens when the dynamic proxy is not able to pick the correct Bean. Please check whether this.producerName is null or empty.
I want to create a custom spring annotation which will work under some conditions or parameters. But as a business constraint I need to share the library which has Genre annotation to all my applications. Is it possible to configure my annotation for limiting to some of my applications like #Profile annotation?
#Target({ElementType.FIELD, ElementType.PARAMETER}) #Retention(RetentionPolicy.RUNTIME)
#Qualifier
public #interface Genre {
String value();
}
and its usage
public class MovieRecommender {
#Autowired
#Genre("Action")
private MovieCatalog actionCatalog;
private MovieCatalog comedyCatalog;
#Autowired
public void setComedyCatalog(#Genre("Comedy") MovieCatalog comedyCatalog) {
this.comedyCatalog = comedyCatalog;
}
// ...
}
I don't think it is possible to alter the behaviour of #Autowired annotation.
However you can easily implement your own BeanPostProcessor and use all the convenience Spring classes, such as AnnotationUtils, ReflectionUtils, etc.
On one project we needed custom JAX-WS port injection. So we created #InjectedPort annotation and implemented our own InjectedPortAnnotationBeanPostProcessor (this just illustrates the simplicity of custom injection logic, the purpose of the code itself is unrelated to the question):
#Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) {
// Walk through class fields and check InjectedPort annotation presence
ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
#Override
public void doWith(final Field field) {
// Find InjectedPort annotation
final InjectedPort injectedPort = field.getAnnotation(InjectedPort.class);
if (injectedPort == null) {
return; // Annotation is not present
}
// Get web service class from the annotation parameter
Class<?> serviceClass = injectedPort.value();
// Find web service annotation on the specified class
WebServiceClient serviceAnnotation = AnnotationUtils.findAnnotation(serviceClass, WebServiceClient.class);
if (serviceAnnotation == null) {
throw new IllegalStateException("Missing WebService " + "annotation on '" + serviceClass + "'.");
}
// Get web service instance from the bean factory
Service service = (Service) beanFactory.getBean(serviceClass);
// Determine the name of the JAX-WS port
QName portName = new QName(service.getServiceName().getNamespaceURI(), findPortLocalName(serviceClass, field.getType()));
// Obtain the JAX-WS port
Object port = service.getPort(portName, field.getType());
// Inject the port into the target bean
ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field, bean, port);
}
});
return bean;
}