Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring 具有自动连接功能的动态代理Bean_Spring_Dynamic Proxy - Fatal编程技术网

Spring 具有自动连接功能的动态代理Bean

Spring 具有自动连接功能的动态代理Bean,spring,dynamic-proxy,Spring,Dynamic Proxy,在我正在从事的一个基于spring的项目中,有一层用于调用web服务的功能。对于每个web服务操作,使用几乎相同的代码创建一个方法,但使用一些不同的、特定于操作的信息(例如服务名称、操作名称、名称空间等) 我用接口和带注释的方法替换这个层。例如,下面的代码是为web服务(“foo”)的操作“fetchBar”提供的 现在,我希望通过某种机制,spring允许我从一些指定的包创建动态代理bean,并且我可以使用以下代码调用web服务 package a.b.c.business; import

在我正在从事的一个基于spring的项目中,有一层用于调用web服务的功能。对于每个web服务操作,使用几乎相同的代码创建一个方法,但使用一些不同的、特定于操作的信息(例如服务名称、操作名称、名称空间等)

我用接口和带注释的方法替换这个层。例如,下面的代码是为web服务(“foo”)的操作“fetchBar”提供的

现在,我希望通过某种机制,spring允许我从一些指定的包创建动态代理bean,并且我可以使用以下代码调用web服务

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;
    }
}
为了实现这一点,我使用
java.lang.reflect.Proxy.newProxyInstance
创建了动态bean实例,方法是提供
InvocationHandler
的it实现。但是,在提供的
invocationHandler
实现及其进一步的依赖项中,自动连接不起作用

我尝试了以下方法来实现这一点

  • 使用
    ConfigurableListableBeanFactory.registerSingleton
    方法实现了
    BeanFactory后处理器。后处理BeanFactory
    并注册了Bean
  • 实现了
    importBeanDefinitionRegister.registerBeanDefinitions
    ,并尝试使用
    BeanDefinitionRegistry.registerBeanDefinition
    ,但我不知道如何提供支持自动连接的正确Bean定义

谁能告诉我少了什么?如果我的方向不对,请指导我。

你的调用处理器是豆子吗?您应该将其创建为一个bean,而不仅仅是一个简单的对象来让自动连线工作

以下是我如何实现所有功能的,这些功能创建了带有“WebService”注释的接口bean,并且还支持代理实现内部的自动连线。(以下代码中省略了包装声明和进口声明) 首先,我创建了
WebService
webservicecooperation
注释

WebService注释

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface WebService {
    String service();
    String namespace();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WebServiceOperation {
    String operation();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({
    WebServiceProxyConfig.class, 
    WebServiceProxyBeansRegistrar.class
})

public @interface EnableWebServices {

    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

}
WebService操作注释

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface WebService {
    String service();
    String namespace();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WebServiceOperation {
    String operation();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({
    WebServiceProxyConfig.class, 
    WebServiceProxyBeansRegistrar.class
})

public @interface EnableWebServices {

    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

}
下一步是扫描指定包中的所有
WebService
带注释的接口。Spring为包扫描提供了
ClassPathScanningCandidateComponentProvider
,但它不检测接口。有关更多详细信息,请参阅和。所以我扩展了
ClassPathScanningCandidateComponentProvider
并重写了
isCandidateComponent
方法

ClassPathScanner

public class ClassPathScanner extends ClassPathScanningCandidateComponentProvider {

    public ClassPathScanner(final boolean useDefaultFilters) {
        super(useDefaultFilters);
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isIndependent();
    }

}
@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();
        }

    }

}
此时,我创建了
EnableWebServices
annotation来启用web服务并提供包含
WebService
注释接口的web服务包

启用Web服务注释

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface WebService {
    String service();
    String namespace();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WebServiceOperation {
    String operation();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({
    WebServiceProxyConfig.class, 
    WebServiceProxyBeansRegistrar.class
})

public @interface EnableWebServices {

    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

}
此注释可应用于某些带有包的
配置
注释类,以扫描接口,如下所示

@EnableWebServices({
    "a.b.c.webservices",
    "x.y.z.webservices"
})
现在应该考虑动态代理创建,它将根据
WebService
webservicecooperation
注释中给出的信息调用实际的web服务。Java提供了一种创建动态代理的机制,需要提供
InvocationHandler
接口的实现,并在其
invoke
方法中提供逻辑。我将此实现命名为
WebServiceProxy

假设“TheWebServiceCaller”类型的bean包含调用web服务的所有讨厌的逻辑。我只需要注入它,并使用
TheWebServiceInfo
(从
WebService
webservicecooperation
注释中提取)和请求对象调用它的
call
方法

webserviceinfo(假设所有字段都有getter和setter)

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;
    }
}
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);
    }

}
InvocationHandler
的实现被传递到
Proxy.newProxyInstance
(以及一些其他信息)以创建代理对象。我需要为每个
WebService
annotated接口分离代理对象。现在我将创建一个工厂来代理实例创建,名称为“WebServiceProxyBeanFactory”。此工厂创建的实例将成为相应
WebService
注释接口的bean

稍后,我将把“WebServiceProxy”和
WebServiceProxyBeanFactory
公开为bean。在“WebServiceProxyBeanFactory”中,我将注入
WebServiceProxy
并使用它。请注意,
createWebServiceProxyBean
使用泛型。这很重要

WebServiceProxyBeanFactory

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;
    }
}
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);
    }

}
现在一切都准备好了。是时候编写一个钩子来开始扫描Web服务包并将动态代理注册为bean了。我将提供
importBeanDefinitionRegistrator
的实现

WebServiceProxyBeansRegistrar

public class ClassPathScanner extends ClassPathScanningCandidateComponentProvider {

    public ClassPathScanner(final boolean useDefaultFilters) {
        super(useDefaultFilters);
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isIndependent();
    }

}
@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();
        }

    }

}
@配置
公共类WebServiceProxByeansRegistrar实现ImportBeanDefinitionRegistrator、BeanClassLoaderware{
私有类路径扫描程序类路径扫描程序;
私有类加载器;
公共Web服务ProxyBeansRegistrar(){
classpathScanner=新的classpathScanner(false);
addIncludeFilter(新的AnnotationTypeFilter(WebService.class));
}
@凌驾
公共类加载器(类加载器类加载器){
this.classLoader=classLoader;
}
@凌驾
公共无效注册表BeanDefinitions(注释元数据导入类元数据,BeanDefinitionRegistry注册表){
字符串[]basePackages=getBasePackages(导入类元数据);
if(ArrayUtils.isNotEmpty(basePackages)){
for(字符串basePackage:basePackages){
CreateWebServiceProxies(基本包、注册表);
}
}
}
私有字符串[]getBasePackages(注释元数据导入类元数据){
字符串[]basePackages=null;
多值映射allAnnotationAttributes=
进口clas