I have created a microservice in springboot, there is folder under resource folder and then a file under this folder
i,e.
resource
mycustomfolder
myfile.txt
I am creating a bean, which filed populated by myfile
#Value("${file-path}")
private String filePath;
#Bean
public MyBean byBean() throws IOException {
//read file path
String path = ResourceUtils.getURL(filePath).getPath();
//populated by bean
MyBean myBean = myservice.populatedMyBean(path);
return myBean;
}
filePath value is set in application.property
dataload-config-file=src/main/resources/mycustomfolder/myfile.txt
when i am executing this springboot app it's working file.
But when i am creating a jar of it and deploying with spring cloud data flow it giving me error on creating myBean
showing exception cause
Caused by: java.io.FileNotFoundException: /tmp/spring-cloud-dataflow-4865534318197521357/test-1506882530191/test.process/src/main/resources/mycustomfolder/myfile.txt (No such file or directory)
why this is happning normally working fine, but throwing error with spring-cloud-dataflow?
Spring Cloud Data Flow can only orchestrate Spring Cloud Stream (SCSt) or Spring Cloud Task (SCT) based microservice applications. It is unclear whether your Spring Boot application complies to previously mentioned frameworks.
Please use the SCSt and SCT samples for reference. If your application does comply with the SCSt/SCT programming model, it'd be better you share the source code for review.
Related
I have a Spring project (not using Spring Boot, if that's relevant) that I'm trying to connect to a local database using the Postgres JDBC driver. (The local database is actually Yugabyte, but that should be fully compatible with the Postgres driver.)
When starting the application, I get this error message:
java.lang.IllegalArgumentException: An AbstractMessageProducingMessageHandler may only be referenced once (org.springframework.integration.config.SplitterFactoryBean#0) - use scope="prototype"
at org.springframework.util.Assert.isTrue(Assert.java:118)
at org.springframework.integration.config.AbstractStandardMessageHandlerFactoryBean.checkReuse(AbstractStandardMessageHandlerFactoryBean.java:168)
at org.springframework.integration.config.AbstractStandardMessageHandlerFactoryBean.createHandler(AbstractStandardMessageHandlerFactoryBean.java:137)
at org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean.createHandlerInternal(AbstractSimpleMessageHandlerFactoryBean.java:186)
at org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean.getObject(AbstractSimpleMessageHandlerFactoryBean.java:174)
at org.springframework.integration.config.AbstractSimpleMessageHandlerFactoryBean.getObject(AbstractSimpleMessageHandlerFactoryBean.java:59)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:171)
... 52 more
I can't place this error at all. There is one similar question on Stack Overflow, but there the asker seems to actually know what they're doing and how this is related to spring integration. I, however, am not aware at all that I'm trying to 'reuse' anything. The referenced question also doesn't seem to be related to database configuration.
My setup/configuration is a bit involved, so I'll try to quote the parts that seem relevant.
I have a dao layer project that has the following gradle dependencies (among others):
implementation("org.springframework:spring-context:5.2.2.RELEASE")
implementation("org.springframework:spring-jdbc:5.2.2.RELEASE")
implementation("org.jooq:jooq-kotlin:3.14.11")
runtimeOnly("org.postgresql:postgresql:42.2.19.jre7")
In the same project, I have some configuration (in Kotlin):
#Configuration
open class Config {
#Bean
open fun jdbcTemplate(dataSource: DataSource): JdbcTemplate = JdbcTemplate(dataSource)
#Bean
open fun dslContext(): DSLContext = DefaultDSLContext(SQLDialect.POSTGRES)
#Configuration
#Profile("!unittest")
open inner class NonTestConfig {
#Bean
open fun dataSource(): DataSource {
return DriverManagerDataSource().apply {
// Hardcoded properties to be replaced by values from property file
setDriverClassName("org.postgresql.Driver")
url = "jdbc:postgresql://localhost:5433/demo"
username = "yugabyte"
password = "yugabyte"
}
}
}
}
(Notes: the DSLContext bean is used for JOOQL, included for completeness' sake. The inner class config is there because there is also a separate unit testing config for an embedded database - that one works fine!)
Now, the above project is used in my top-level project that contains the actual application. It's a maven runtime dependency there. I import the config class in this project's XML configuration, using this method:
<context:annotation-config />
<bean class="my.package.Config" />
Then trying to start the application produces the error message.
I figured out what the problem was, but I still don't know how it relates to a <splitter>.
The problem was that the Config class, apart from the database stuff, also included a bean to encrypt data. It turned out that this bean was also defined in another library used by the top-level project. Fixing this duplicate bean problem made the error go away.
I discovered this in a roundabout way: I included the dao project and its configuration in a different top-level project that uses Spring Boot. This led to a clear error message about the encryptor bean having two definitions.
If anyone can explain why the error message is so cryptic in the non-Boot case, that would be a nice complementary answer.
How to view autoconfigure log output during spring boot server start
I have created a spring boot application. It uses a shared library (Spring boot jar via maven dependency). Shared library class is loaded via
META-INF/spring.factories
I have mentioned the classes from the library in spring.factories. The job of shared library is to read Vault role id and Vault
secret id value from application.properties and call a REST API and fetch secrets from Vault. After fetching the secret it sets the value again in system property.
for (Map.Entry<String, String> entry : allSecrets.entrySet())
{
System.setProperty(entry.getKey(), entry.getValue());
}
Everything is working as expected. But I am not able to see logs from shared library in my logs.
shared library's package structure is com.myorg.abc. My spring boot package structure is com.myorg.xyz
I tried the following in application properties.
logging.level.root= DEBUG
logging.level.com.myorg.xyz: DEBUG
logging.level.com.myorg.abc: DEBUG
logging.level.org.springframework.boot.autoconfigure.logging=DEBUG
I am able to get logs only from my application but not from shared library. But when I change the shared library Logger.error to System.out, then I am getting the message in my application. How to view shared library's log in my application.
Spring boot initializes logging at least 3 times. The first happens when SpringApplication is loaded. It creates an SLF4J Logger before anything in Spring is accessed. This causes whatever logging implementation you have chosen to initialize. By default, it will use the logging configuration in the Spring jar. With Log4j 2 you can override this by setting log4j.configurationFile to the location of your desired configuration either as a system property or in a log4j.component.properties file.
Everything Spring does will be logged using this configuration until it initializes the logging configuration again, which is controlled by bootstrap.yml. Finally, your application's logging configuration is initialized which is configured either from application.yml or again from bootstrap.yml.
I replaced org.springframework.boot.env.EnvironmentPostProcessor with org.springframework.context.ApplicationListener in Spring.factories and it fixed the issue. I was able to get logs from shared library in invoking application.
Spring.factories
org.springframework.context.ApplicationListener=com.mypackage.MyClassName
MyClassName.java
public class MyClassName implements ApplicationListener<ApplicationPreparedEvent>
{
private static final Logger LOGGER = LoggerFactory.getLogger(MyClassName.class);
#Override
public void onApplicationEvent(ApplicationPreparedEvent applicationPreparedEvent)
{
ConfigurableEnvironment configurableEnvironment = applicationPreparedEvent.getApplicationContext()
.getEnvironment();
String roleId = configurableEnvironment.getProperty(Constants.VAULT_ROLE_ID_LITERAL);
String secretId = configurableEnvironment.getProperty(Constants.VAULT_SECRET_ID_LITERAL);
...
Optional<String> errorMessage = ServiceUtil.validateSystemProperty(roleId, secretId);
if (!errorMessage.isPresent())
{
Map<String, String> secret = ServiceUtil.getSecret(roleId, secretId);
for (Map.Entry<String, String> entry : secret.entrySet())
{
System.setProperty(entry.getKey(), entry.getValue());
}
LOGGER.info("Successfully populated secrets from Vault in system property");
}
else
{
LOGGER.error("Failed to populate secrets from Vault in system property. Error:{}", errorMessage.get());
}
}
}
application.properties
logging.level.com.myorg.abc: DEBUG
I am building a new spring boot application deployable to bluemix (cloud foundry) which needs to do the following:
use spring-cloud-cloudfoundry-connector to discover user-provided "properties service": read the service URL and credentials from VCAP_APPLICATION env variable.
This step is completed.
connect to properties service via HTTP call, receive JSON response, parse individual property values and expose them as application properties (in Environment object?)
What would be the correct solution for this in spring-boot app?
In older non-boot Spring app, the property service call would be initiated early in Spring lifecycle by a class that extended PropertySourcesPlaceholderConfigurer and the property collection from the service would be handled inside postProcessBeanFactory() method call of the same class.
public class CustomPopertiesFactory
extends PropertySourcesPlaceholderConfigurer
implements EnvironmentAware {
private Properties properties;
getServiceCredentials() {
// parse VCAP_APPLICATION json
final String localVcapServices = System.getProperty("VCAP_SERVICES");
// extract url, username, pwd to connect to the service
}
connectToService () {
// via HTTP request using RestTemplate
// parse JSON response and add properties to this.properties
... this.properties.put("prop1", valueFromJson);
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
getServiceCredentials();
connectToService();
// load values from properties service into app properties
setProperties(properties);
// continue with lifecycle and load properties from other sources
super.postProcessBeanFactory(beanFactory);
}
}
That was painful to maintain and switch between cloud and local spring profiles IMO and I am wondering if spring boot has a better way of handling external properties.
I ended up replacing "properties service" with spring-cloud-config-server
and using spring-cloud-config-client
in my spring boot application to consume properties from spring-cloud-config-server.
I am new with Spring Boot Development and currently can't move-on on the issue of how to load my spring application configuration outside the jar file.
My existing code looks like this
private ApplicationContext context;
public static void main(String[] args){
SpringApplication.run(SMPPEngine.c1ass);
new SMPPEngine();
}
public SMPPEngine(){
loadConfiguration();
process();
}
private void loadConfiguration(){
context = new ClassPatthlApplicationContext(”application-context.xm1”);
}
What I want to achieve is to have the jar file next to application-context.xml in one directory so that when there are configuration changes,I don't need to recompile my code just to reflect the changes on application-context.xml.
Based on what I've read on the internet, this is possible by using 'file://directory/application.xml' instead of classpath. But my problem on using the later is that when you place your jar and file to other location, I am required to do code change to reflect the new directory which does not solve the problem of getting away from code recompilation.
I hope I made my issue clear, and get an immediately response with you guys :)
Thanks in advance :)
There are many approaches to do this, standard, you can use spring file: prefix for accessing filesystem paths.
but with spring boot, you can specifiy it in application.properties with
spring.config.location propertiy, or you can add it in command line when run the spring boot jar file like
java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
But for your codes, actually you do not need to re-create the spring context from the configuration files, but you want get the context instance, you just need to inject it
#Autowired
private ApplicationContext context;
Another approach, if you have the infrastructure. Would be to use Spring Cloud Config. After your Boot application is configured to read from it, they can be modified at anytime without recompilation or restarting.
I have a persistence layer (JPA entity objects) created and managed by Roo. It is in its own project, builds to a jar, and I have used it with a separate Spring MVC 3 web application.
I'd like to use this same Roo persistence project in another web application powered by Apache Wicket. I have seen a couple of the Roo add-ons made for Wicket, but none of them even compile (I'm not the only one to have the issue).
The problem I am encountering is that whenever I try to call one of my Roo entities from within a Wicket Page or component, I get the following exception:
Caused by: java.lang.IllegalStateException: Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)
at com.x.domain.UserAccount_Roo_Entity.ajc$interMethod$com_x_domain_UserAccount_Roo_Entity$com_x_domain_UserAccount$entityManager(UserAccount_Roo_Entity.aj:91)
at com.x.domain.UserAccount.entityManager(UserAccount.java:1)
I have configured my application following the Spring+Wicket wiki here: https://cwiki.apache.org/WICKET/spring.html
Does anyone know the 1,2,3 steps to set up a Wicket application to utilize Spring Roo entities? Any help is appreciated. Thanks!
I found this in google code, sounds like its doing exactly what you want http://code.google.com/p/spring-roo-wicket-addon/
I found the solution to my problem. When I ran my wicket webapp using the Maven jetty:run goal, it worked. However, I was trying to start Jetty via Java code:
public class Start {
public static void main(String[] args) throws Exception {
Server server = new Server();
SocketConnector connector = new SocketConnector();
server.start();
}
}
I was not loading the Spring ApplicationContext in this "Start" class. Once I modified this class to load the Spring application context, it worked