Migrating existing legacy application to java 11 and spring 5 and seems to be ServiceActivator method not invoking. I see publisher method invoking and printing log statement but no logs printing from ServiceActivator class
spring 5.3.14
spring-integration-* 5.5.7
XML Configuration:
<int:channel id="employeeServicesChannel">
<int:dispatcher task-executor="employeeServicesExecutor" />
</int:channel>
<bean id="employeeServicesExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="40" />
<property name="queueCapacity" value="10" />
<property name="keepAliveSeconds" value="0"></property>
</bean>
public class EmployeeServicesPublisher {
#Publisher(channel = "employeeServicesChannel")
public EmployeeServicesDto publishEmployeeServicesRequest(EmployeeServicesDto requestDto) {
logger.info(" employee service request :" + requestDto);
return requestDto;
}
#MessageEndpoint
public class EmployeeServicesServerGateway {
#ServiceActivator(inputChannel = "employeeServicesChannel", outputChannel =
"esDynamicOutputChannel")
public EmployeeServicesDto processRequest(EmployeeServicesDto employeeServicesDto) {
logger.info("===================================");
logger.info(" request Id:" + employeeServicesDto.getRequestId());
return employeeServicesDto;
}
Related
Log4j2 JDBC appender can be setup using a pooled connection factory that is defined using calls and method (see log4j2 Appenders):
<ConnectionFactory class="net.example.db.ConnectionFactory" method="getDatabaseConnection" />
Using Spring I have already a defined datasource that is providing a pooled connection :
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${db_driver_class}" />
<property name="url" value="${db_jdbc_url}" />
<property name="username" value="${db_username}" />
<property name="password" value="${db_password}" />
<property name="initialSize" value="10" />
<property name="maxActive" value="100" />
<property name="maxIdle" value="50" />
<property name="minIdle" value="10" />
<property name="validationQuery" value="select 1" />
<property name="testOnBorrow" value="true" />
I would like to use the the Spring connection pool for the JDBC appender. Any idea how can this be done ?
thanks
Raz
I mange to create a 3-steps solution :
Define a bean in spring context that provide access to a data
source
Build an implementation of the bean that provide the
desired connection.
Build a static wrapper that can be accessed by the log4j JDBC appender.
1st step - bean declaration :
<bean id="springConnection" class="com.dal.entities.SpringConnection" scope="singleton">
<property name="dataSource" ref="myDataSource" />
the 2nd step - bean implementation - is also simple :
class SpringConnection {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
Connection getConnection() throws Exception {
return dataSource.getConnection();
}
}
the 3rd part - wrapper with static method - is a bit more complex:
public class SpringAccessFactory {
private final SpringConnection springCon;
private static ApplicationContext context;
private interface Singleton {
final SpringAccessFactory INSTANCE = new SpringAccessFactory();
}
private SpringAccessFactory() {
this.springCon = context.getBean(SpringConnection.class);
}
public static Connection getConnection() throws Exception {
return Singleton.INSTANCE.springCon.getConnection();
}
public static void setContext( ApplicationContext context) {
SpringAccessFactory.context = context;
}
}
There are - however - 2 issues I found so far:
You need to initialize the spring context and send it into the wrapper (SpringAccessFactory.setConetxt) before you start using the logger
initializing spring context early in program may trigger #PostConstruct methods (if any exists), before you plan to do so.....
I am trying to convert the spring batch configuration from xml based to annotation based.
Below is my xml based configuration.
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" />
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<!-- Step will need a transaction manager -->
<bean id="transactionManager"
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
<bean id="dbMapper" class="org.test.DBValueMapper">
</bean>
<bean id="dbMapperFlatfile" class="org.test.FlatFileRowMapper">
</bean>
<bean id="paramSetter" class="org.test.DBParamSetter">
</bean>
<bean id="dbReader" class="org.test.DBValueReader"
scope="step">
<property name="paramSetter" ref="paramSetter"/>
<property name="verifyCursorPosition" value="false" />
<property name="dataSource" ref="dataSource" />
<property name="sql" value="#{jobParameters['SQL_QUERY']}" />
<property name="rowMapper" ref="dbMapper" />
<property name="fetchSize" value="5000" />
</bean>
<bean id="dbWriterIO" class="org.test.TemplateWritterIO"
scope="step">
<property name="velocityEngine" ref="velocityEngine" />
<!-- <property name="rptConfig" value="#{jobParameters['RPT_CONFIGVAL']}" /> -->
<property name="headerCallback" ref="dbWriterIO" />
<property name="footerCallback" ref="dbWriterIO" />
</bean>
<batch:job id="fileGenJobNio">
<batch:step id="fileGenJobStempNio">
<batch:tasklet>
<batch:chunk reader="dbReader" writer="dbWriterNIO"
commit-interval="5000">
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
Below is the equivalent Java based configuration:
#EnableBatchProcessing
#Import({ServiceConfiguration.class})
public class SRBatchGenerator extends DefaultBatchConfigurer{
#Autowired
private JobBuilderFactory jobBuilders;
#Autowired
private StepBuilderFactory stepBuilders;
#Autowired
private VelocityEngine velocityEngine;
#Autowired
private DBValueMapper mapper;
#Autowired
private DbHelper dbhelper;
#Autowired
private DataSource datasource;
#Bean
public Step step(){
return stepBuilders.get("step")
.chunk(5000)
.reader(reader())
//.processor(processor())
.writer(writer())
//.listener(logProcessListener())
.faultTolerant()
//.skipLimit(10)
//.skip(UnknownGenderException.class)
//.listener(logSkipListener())
.build();
}
#Bean
public Job fileGeneratorJob(){
return jobBuilders.get("fileGeneratorJob")
//.listener(protocolListener())
.start(step())
.build();
}
#Bean
public DBValueMapper mapper(){
return new DBValueMapper();
}
#Bean
#StepScope
public DBValueReader3 reader(){
String query="Select Test1,Test2,test3,test4 from RPt_TEST";
DBValueReader3 dbread = new DBValueReader3();
dbread.setSql(query);
dbread.setRowMapper(mapper);
dbread.setDataSource(datasource);
return dbread;
}
#Bean
#StepScope
public TemplateWritterIO writer(){
TemplateWritterIO writer=new TemplateWritterIO();
writer.setVelocityEngine(velocityEngine);
return writer;
}
#Override
protected JobRepository createJobRepository() throws Exception {
MapJobRepositoryFactoryBean factory =
new MapJobRepositoryFactoryBean();
factory.afterPropertiesSet();
return (JobRepository) factory.getObject();
}
}
When I execute my Job using xml based it took 27sec to write 1 Million record into Flat file.
But to write same 1 million record, Java based job took about 2 hours to write.
I am not sure what I am missing here. Can anyone help me or guide me why it is slow in Java based configuration.
I have such method
#JmsListener(containerFactory = "jmsListenerContainerFactory", destination = "myQName")
public void rceive(MySerializableObject message) {
log.info("received: {}", message);
}
and such config on xml
<jms:annotation-driven />
<bean id="jmsListenerContainerFactory" class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
<property name="connectionFactory" ref="pooledConnectionFactory" />
<property name="concurrency" value="3-10" />
</bean>
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${brokerURL}" />
</bean>
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="maxConnections" value="5" />
<property name="maximumActiveSessionPerConnection" value="500" />
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
<bean id="jmsContainerFactory" class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
<property name="connectionFactory" ref="pooledConnectionFactory" />
<property name="concurrency" value="3-10" />
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate" p:connectionFactory-ref="pooledConnectionFactory" />
Seems consumer was not created. I can send messages but cannot receive them.
Any idea whats wrong here?
Just tested your config and it works well. Only difference that I make a class with #JmsListener as a <bean> in that context:
<bean class="org.springframework.integration.jms.JmsListenerAnnotationTests$TestService"/>
#ContextConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#DirtiesContext
public class JmsListenerAnnotationTests {
#Autowired
private JmsTemplate jmsTemplate;
#Autowired
private TestService testService;
#Test
public void test() throws InterruptedException {
this.jmsTemplate.convertAndSend("myQName", "foo");
assertTrue(this.testService.receiveLatch.await(10, TimeUnit.SECONDS));
assertNotNull(this.testService.received);
assertEquals("foo", this.testService.received);
}
public static class TestService {
private CountDownLatch receiveLatch = new CountDownLatch(1);
private Object received;
#JmsListener(containerFactory = "jmsListenerContainerFactory", destination = "myQName")
public void receive(String message) {
this.received = message;
this.receiveLatch.countDown();
}
}
}
<jms:annotation-driven /> makes the #JmsListener infrastructure available, but to force Spring to see those methods your classes should be beans anyway.
For example <component-scan> for the package with #Service classes.
Cheers!
My config:
<bean parent="cache-template">
<property name="name" value="yagoLabel" />
<property name="cacheMode" value="PARTITIONED" />
<property name="atomicityMode" value="TRANSACTIONAL" />
<property name="distributionMode" value="PARTITIONED_ONLY" />
<property name="backups" value="1" />
<property name="store">
<bean class="id.ac.itb.ee.lskk.lumen.yago.YagoLabelCacheStore" autowire="byType" init-method="init" />
</property>
<property name="writeBehindEnabled" value="true" />
<property name="writeBehindFlushSize" value="102380" />
<property name="writeBehindFlushFrequency" value="30000" />
<property name="writeBehindBatchSize" value="10240" />
<property name="swapEnabled" value="false" />
<property name="evictionPolicy">
<bean class="org.gridgain.grid.cache.eviction.lru.GridCacheLruEvictionPolicy">
<property name="maxSize" value="102400" />
</bean>
</property>
</bean>
And I start GridGain as follows:
My GridCacheStore implementation:
public class YagoLabelCacheStore extends GridCacheStoreAdapter<String, YagoLabel> {
private static final Logger log = LoggerFactory
.getLogger(YagoLabelCacheStore.class);
private DBCollection labelColl;
#GridSpringResource(resourceName="mongoDb")
private DB db;
#Inject
private GridGainSpring grid;
#PostConstruct
public void init() {
log.info("Grid is {}", grid);
labelColl = db.getCollection("label");
}
I start GridGain as follows:
String entityId = "Muhammad";
try (AnnotationConfigApplicationContext appCtx
= new AnnotationConfigApplicationContext(LumenConfig.class)) {
Grid grid = appCtx.getBean(Grid.class);
GridCache<String, YagoLabel> labelCache = YagoLabel.cache(grid);
log.info("Label for {}: {}", entityId, labelCache.get(entityId));
}
LumenConfig Spring configuration contains a DB bean named mongoDb.
However this throws NullPointerException because db is not injected properly. I tried #Inject GridGainSpring just for testing, and even GridGainSpring itself is not injected.
I also tried setting <property name="db" ref="mongoDb"/> in the GridGain Config XML but Spring complains cannot find the bean.
My workaround is to put it inside a public static field but that's soo hacky: https://github.com/ceefour/lumen-kb/blob/b8445fbebd227fb7ac337c758a60badb7ecd3095/cli/src/main/java/id/ac/itb/ee/lskk/lumen/yago/YagoLabelCacheStore.java
The way is to load the GridConfiguration using Spring, then pass it to GridGainSpring.start() :
// "classpath:" is required, otherwise it won't be found in a WAR
#ImportResource("classpath:id/ac/itb/ee/lskk/lumen/core/lumen.gridgain.xml")
#Configuration
public static class GridGainConfig {
#Inject
private ApplicationContext appCtx;
#Inject
private GridConfiguration gridCfg;
#Bean(destroyMethod="close")
public Grid grid() throws GridException {
return GridGainSpring.start(gridCfg, appCtx);
}
}
:-)
We have an application where we have used spring for IOC. We have the dataSource bean configured in applicationContext.xml and that is referenced in other bean definations.
The dataSource bean defination looks like:
<bean id="dbDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url"
value="jdbc:oracle:oci:#TESTDB" />
<property name="username" value="TESTUSER" />
<property name="password" value="TESTPWD" />
<property name="initialSize" value="50" />
<property name="maxActive" value="40" />
<property name="maxIdle" value="10" />
<property name="minIdle" value="10" />
<property name="maxWait" value="-1" />
</bean>
<bean id="serviceDAO" class="com.test.impl.ServiceDAOImpl">
<property name="dataSource" ref="dbDataSource" />
</bean>
ServiceDAOImpl looks as follows:
public class ServiceDAOImpl implements ServiceDAO {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
#SuppressWarnings({ "rawtypes", "unchecked" })
public ValueObj readValue(String key) {
String query = "SELECT * FROM SERVICE_LOOKUP WHERE KEY=?";
/**
* Implement the RowMapper callback interface
*/
return (ValueObj) jdbcTemplate.queryForObject(query,
new Object[] { key }, new RowMapper() {
public Object mapRow(ResultSet resultSet, int rowNum)
throws SQLException {
return new ValueObj(resultSet.getString("KEY"),
resultSet.getString("VALUE"));
}
});
}
public ServiceDAOImpl() {
}
}
Now, at the server start up injection is happening fine and when we use the dataSource in serviceDAOImpl the connection is happening fine. But the very first time the database call is made it takes around 3 mins to get the response back. I think this is because the pool creation is done during the first call and we have set the parameter "initialSize" = 50 in applicationConext.xml.
So, to avoid this we need a way in which the pool can be created during the application startup itself and can be used directly.
Please suggest. Let me know if any clarification required.
Regards
Saroj
There's a work-around for this .You could force jdbcTemplate to use the
DB connection at startup. See the link here for detailed explanation .
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg index="0" ref="dataSource"/>
<constructor-arg index="1" value="false"/>
</bean>
The second constructor-arg is the lazy Init flag.
Aravind A's solution is the preffered one, but just in case you don't want to define an extra bean you can point spring to your DAO's init method:
<bean id="serviceDAO" class="com.test.impl.ServiceDAOImpl" init-method="init">
<property name="dataSource" ref="dbDataSource" />
</bean>
and then define ServiceDAOImpl.init() which calls some sql like SELECT 1 FROM SERVICE_LOOKUP LIMIT 1 or even better some noop like SELECT 1:
public class ServiceDAOImpl implements ServiceDAO {
public void init() {
String query = "SELECT 1 FROM SERVICE_LOOKUP LIMIT 1";
int i = jdbcTemplate.queryForInt(query);
}
}