似乎 BeanPostProcessor 接口实现对@ServiceActivator 产生了影响。将 BeanPostProcessor 与 @ServiceActivator 一起使用的方式应该是什么。谢谢。
完整的日志可在此处获取日志
以下是用于 SFTP 的 Java 配置 -
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:在 org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:685) 在 org.springframework.beans.factory.support.AbstractBeanFactory 中没有名为“toSftpChannel”的 bean .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 的 org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:88)。resolveDestination(BeanFactoryChannelResolver.java:45) at org.springframework.integration.gateway.MessagingGatewaySupport.getRequestChannel(MessagingGatewaySupport.java:327) at org.springframework.integration.gateway.MessagingGatewaySupport.send(MessagingGatewaySupport.java:368) at org.springframework .integration.gateway.GatewayProxyFactoryBean.invokeGatewayMethod(GatewayProxyFactoryBean.java:477) at org.springframework.integration.gateway.GatewayProxyFactoryBean.doInvoke(GatewayProxyFactoryBean.java:429) at org.springframework.integration.gateway.GatewayProxyFactoryBean.invoke(GatewayProxyFactoryBean.java :420) 在 org.springframework.aop.framework 的 org.springframework.integration.gateway.GatewayCompletableFutureProxyFactoryBean.invoke(GatewayCompletableFutureProxyFactoryBean.java:65)。ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy57.sendToSftp(Unknown Source)