SFTP:BeanPostProcessor干扰@ServiceActivator和@MessagingGateway

时间:2017-10-09 11:57:07

标签: spring spring-integration spring-integration-sftp

似乎BeanPostProcessor接口实现对@ServiceActivator产生了影响。将BeanPostProcessor与@ServiceActivator一起使用的方法应该是什么。感谢。

此处提供完整日志logs

以下是用于SFTP的Java Config -

package com.ftp.example;

import java.io.File;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.file.remote.session.CachingSessionFactory;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.sftp.outbound.SftpMessageHandler;
import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

import com.jcraft.jsch.ChannelSftp.LsEntry;

@Configuration
@EnableScheduling
@EnableAspectJAutoProxy
@EnableAsync
@IntegrationComponentScan
@EnableIntegration
@EnableBatchProcessing
@PropertySource("file:C:\\DEV\\workspace_oxygen\\ftp-example\\ftp-example.properties")
public class DependencySpringConfiguration {

    private Logger LOG = LoggerFactory.getLogger(DependencySpringConfiguration.class);

    @Value("${project.name}")
    private String applicationName;


    @Value("${${project.name}.ftp.server}")
    private String server;

    @Value("${${project.name}.ftp.port}")
    int port;

    @Value("${${project.name}.ftp.username}")
    private String username;

    @Value("${${project.name}.ftp.password}")
    private String password;

    @Value("${${project.name}.ftp.remote.directory}")
    private String remoteDirectory;

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    public ProcessStarter processStarter() {
        return new ProcessStarter();
    }

/*  @Bean
    public LogInjector logInjector() {
        return new LogInjector();
    }*/


    @Bean
    public FTPOutService fTPOutService() {
        return new FTPOutService();
    }


    @Bean
    public SessionFactory<LsEntry> sftpSessionFactory() {
        DefaultSftpSessionFactory sf = new DefaultSftpSessionFactory();
        sf.setHost(server);
        sf.setPort(port);
        sf.setUser(username);
        sf.setPassword(password);
        sf.setAllowUnknownKeys(true);
        return new CachingSessionFactory<LsEntry>(sf);
    }

    @Bean
    @ServiceActivator(inputChannel = "toSftpChannel")
    public MessageHandler handler() {
        SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
        handler.setRemoteDirectoryExpression(new LiteralExpression(remoteDirectory));
        handler.setFileNameGenerator(new FileNameGenerator() {

            @Override
            public String generateFileName(Message<?> message) {
                return "fileNameToBeFtp.txt";
            }

        });
        return handler;
    }

    @MessagingGateway
    public interface MyGateway {
        @Gateway(requestChannel = "toSftpChannel")
        void sendToSftp(File file);
    }


}

我们在做SFTP时正在调用这样的网关对象

主要课程

public class FtpExample {

    public static String[] ARGS;
    private static final Logger LOG = LoggerFactory.getLogger(FtpExample.class);

    public static void main(String[] args) throws Exception {
        ARGS = args;
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(DependencySpringConfiguration.class);

        ProcessStarter processStarter = ctx.getBean(ProcessStarter.class);
        processStarter.startService();
    }
}

其他课程 -

public class ProcessStarter {
    @Inject
    private FTPOutService ftpOutService;

    public void startService() {
        ftpOutService.ftpToBbg();
    }
}



public class FTPOutService {
    private static Logger log = LoggerFactory.getLogger(FTPOutService.class);

    @Inject
    private ApplicationContext appContext;

    public void ftpToBbg() {

        log.info("Starting FTP out process...");
        File file = null;
        try {
            file = new File("C:\\Temp\\log\\debug\\ftp\\priceindex\\for-upload\\ftp-example.txt.REQ");
            MyGateway gateway = appContext.getBean(MyGateway.class);
            gateway.sendToSftp(file);
            log.info("File {} written successfully on remote server", file);
        } catch (Exception e) {
            log.error("Error while uploading file {}", file, e);
        }
    }

}

上面的代码工作正常,除非我没有在上面定义的Java Config中添加以下bean声明 -

public LogInjector logInjector() {
            return new LogInjector();
}

上面的bean定义有以下实现 -

public class LogInjector implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
            @Override
            public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                // make the field accessible if defined private
                ReflectionUtils.makeAccessible(field);
                if (field.getAnnotation(Log.class) != null) {
                    if (org.slf4j.Logger.class == field.getType()) {
                        org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(bean.getClass());
                        field.set(bean, log);
                    }  else if (java.util.logging.Logger.class == field.getType()) {
                        java.util.logging.Logger log = java.util.logging.Logger.getLogger(bean.getClass().toString());
                        field.set(bean, log);
                    }
                }
            }
        });
        return bean;
    }
}


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface Log {
}

在Java Config中添加任何BeanPostProcessor实现后,它会产生问题并且应用程序无法看到toSftpChannel -

  

org.springframework.beans.factory.NoSuchBeanDefinitionException:没有   bean命名为toSftpChannel&#39;可在   org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:685)     在   org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1199)     在   org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)     在   org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)     在   org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:88)     在   org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:45)     在   org.springframework.integration.gateway.MessagingGatewaySupport.getRequestChannel(MessagingGatewaySupport.java:327)     在   org.springframework.integration.gateway.MessagingGatewaySupport.send(MessagingGatewaySupport.java:368)     在   org.springframework.integration.gateway.GatewayProxyFactoryBean.invokeGatewayMethod(GatewayProxyFactoryBean.java:477)     在   org.springframework.integration.gateway.GatewayProxyFactoryBean.doInvoke(GatewayProxyFactoryBean.java:429)     在   org.springframework.integration.gateway.GatewayProxyFactoryBean.invoke(GatewayProxyFactoryBean.java:420)     在   org.springframework.integration.gateway.GatewayCompletableFutureProxyFactoryBean.invoke(GatewayCompletableFutureProxyFactoryBean.java:65)     在   org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)     在   org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)     在com.sun.proxy。$ Proxy57.sendToSftp(未知来源)

1 个答案:

答案 0 :(得分:2)

看看你有什么:

@Bean
public LogInjector logInjector() {
    return new LogInjector();
}

如果您将BeanPostProcessor声明为@Bean,则必须使用static修饰符指定它们:https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/core.html#beans-factorybeans-annotations

  

您可以将@Bean方法声明为静态,允许在不创建包含配置类作为实例的情况下调用它们。这在定义后处理器bean时特别有意义,例如,类型BeanFactoryPostProcessorBeanPostProcessor,因为这些bean将在容器生命周期的早期初始化,并且应避免在此时触发配置的其他部分。