Spring Cloud Config in web application - java

I have legacy Java web application (with Spring MVC and web.xml) which are deployed in Tomcat. I want to swtich configuration to Spring Cloud Config.
Structure of this application (just simplify it for example) - jar file with Spring Controller and services, which I want to do Spring Cloud Config compatible. And another module with web.xml, which add jar as dependency.
I added bootstrap.yml with application name to module, which packaged to jar in "resources" folder and add "EnableAutoConfiguration" and "SpringBootApplication" annotations, but got exception:
java.lang.IllegalArgumentException: Could not resolve placeholder 'foo' in string value "${foo}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:219)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:193)
Config server is run. I wrote simple client, which I run via main method and it works, but when I deploy legacy app in Tomcat - it doesn't work.
Can someone help with it?

Related

Want to change the context path in Spring boot application in an external Tomact server version 9

I want to deploy a Spring boot application in an external Tomcat server version 9. I am able to deploy it and working the endpoints also. But properties I have set in application.properties file those are not working. Like server.servlet.context-path=/myapp is is not working instead the context path which I am getting is http://localhost:8080/myapp-0.0.1-SNAPSHOT/api/ping.
I am using 2.3.10.RELEASE and Java 1.8 and Tomcat version 9.0.46 Can anyone please help me out with this.
But everything is perfectly working on embedded tomcat. Thanks in advance and any suggestion, comment is highly appreciated.
Can anyone please help me with how I can do this - My war file name would be myapp-0.1.war but the context path of the application would be like this localhost:8080/myapp/api/ping
Use finalName property in your build file (pom.xml for maven)
<finalName>myapp</finalName>
When you run a Spring Boot application in an external servlet container, the server.* properties do not apply.
If you are willing to change the naming convention you can drop a WAR file named myapp##0.1.war in the $CATALINA_BASE/webapps directory and benefit from parallel deployment (cf. parallel deployment).
If you want to stick to your naming convention, you can create a folder for your WAR files (e.g. $CATALINA_BASE/webapps-available) and create a deployment descriptor $CATALINA_BASE/conf/<engine_name>/<host_name>/<context_path>.xml (in your case probably $CATALINA_BASE/conf/Catalina/localhost/myapp.xml) with the following content:
<Context docBase="${catalina.base}/webapps-available/myapp-0.1.war" />

Spring Boot not working with dependent application.properties

I'm working with the Spring Boot 2.2.9.RELEASE. I have the main app and some plain starter (which just uses spring-actuator functionality) with some properties in its some-starter/src/main/resources/application.properties file:
management.server.port=9000
management.server.ssl.enabled=false
management.endpoints.enabled-by-default=false
management.endpoint.health.enabled=true
management.endpoints.web.base-path=/
management.endpoints.web.path-mapping.health=health
I've imported the starter into my main app and I believe that the healthcheck endpoint should work with the port 9000 and with the path /health (smth like that localhost:9000/health).
But it doesn't. However, it works in case of the same properties in my main app main-app/src/main/resources/application.properties.
Is it problem with the property overriding in Spring Boot? Should i configure my resources via something like maven-resources-plugin?
When application.properties is loaded from the classpath, the first one on the classpath is loaded and any others on the classpath are ignored. In your case, the file in main-app/src/main/resources/application.properties will appear on the classpath before the application.properties in the jar of some-starter.
As its name suggests, application.properties is intended for configuring your application and it shouldn't be used in a starter. You should either configure all of the properties in your application, or you could update your starter to include an EnvironmentPostProcessor that is registered via spring.factories and adds some default properties to the Environment.

Create spring boot restful Webservices without #EnableAutoconfig

I have a Spring boot project which is packaged into jar and it functionalities are related to MQ and database. I want to now host a webservice on that project however I cannot use #EnableAutoConfiguration or #SpringBootApplication. The webservice to be created is a simple GET service that will return a integer value. I have tried following steps but still the webservice doesnt start.
Added Spring-webmvc, spring-web, spring-boot-web ,spring-tomcat jars to pom.xml
Changed the artifact type from jar to war in pom.xml
Added #EnableWebMvc in the config class
Added a class with #Controller and #RequestMapping
Created a bean for EmbeddedServletContext for Tomcat.
What have I missed?
Some blogs mentioned about creating a WebApplicationContextInitializer and some mentioned about creating a Dispatcher servlet.
My question is what all beans do I need to manually create to bring up my webservice (as I cannot use EnableAutoConfig)

Using Spring boot/cloud with Amazon AWS lambda does not inject values

I have an AWS lambda RequestHandler class which is invoked directly by AWS. Eventually I need to get it working with Spring Boot because I need it to be able to retrieve data from Spring Cloud configuration server.
The problem is that the code works if I run it locally from my own dev environment but fails to inject config values when deployed on AWS.
#Configuration
#EnableAutoConfiguration
#ComponentScan("my.package")
public class MyClass implements com.amazonaws.services.lambda.runtime.RequestHandler<I, O> {
public O handleRequest(I input, Context context) {
ApplicationContext applicationContext = new SpringApplicationBuilder()
.main(getClass())
.showBanner(false)
.web(false)
.sources(getClass())
.addCommandLineProperties(false)
.build()
.run();
log.info(applicationContext.getBean(SomeConfigClass.class).foo);
// prints cloud-injected value when running from local dev env
//
// prints "${path.to.value}" literal when running from AWS
// even though Spring Boot starts successfully without errors
}
}
#Configuration
public class SomeConfigClass {
#Value("${path.to.value}")
public String foo;
}
src/main/resources/bootstrap.yml:
spring:
application:
name: my_service
cloud:
config:
uri: http://my.server
failFast: true
profile: localdev
What have I tried:
using regular Spring MVC, but this doesn't have integration with #Value injection/Spring cloud.
using #PropertySource - but found out it doesn't support .yml files
verified to ensure the config server is serving requests to any IP address (there's no IP address filtering)
running curl to ensure the value is brought back
verified to ensure that .jar actually contains bootstrap.yml at jar root
verified to ensure that .jar actually contains Spring Boot classes. FWIW I'm using Maven shade plugin which packages the project into a fat .jar with all dependencies.
Note: AWS Lambda does not support environment variables and therefore I can not set anything like spring.application.name (neither as environment variable nor as -D parameter). Nor I can control the underlying classes which actually launch MyClass - this is completely transparent to the end user. I just package the jar and provide the entry point (class name), rest is taken care of.
Is there anything I could have missed? Any way I could debug this better?
After a bit of debugging I have determined that the issue is with using the Maven Shade plugin. Spring Boot looks in its autoconfigure jar for a META-INF/spring.factories jar see here for some information on this. In order to package a Spring Boot jar correctly you need to use the Spring Boot Maven Plugin and set it up to run during the maven repackage phase. The reason it works in your local IDE is because you are not running the Shade packaged jar. They do some special magic in their plugin to get things in the right spot that the Shade plugin is unaware of.
I was able to create some sample code that initially was not injecting values but works now that I used the correct plugin. See this GitHub repo to check out what I have done.
I did not connect it with Spring Cloud but now that the rest of the Spring Boot injection is working I think it should be straightforward.
As I mentioned in the comments you may want to consider just a simple REST call to get the cloud configuration and inject it yourself to save on the overhead of loading a Spring application with every request.
UPDATE: For Spring Boot 1.4.x you must provide this configuration in the Spring Boot plugin:
<configuration>
<layout>MODULE</layout>
</configuration>
If you do not then by default the new behavior of the plugin is to put all of your jars under BOOT-INF as the intent is for the jar to be executable and have the bootstrap process load it. I found this out while addressing adding a warning for the situation that was encountered here. See https://github.com/spring-projects/spring-boot/issues/5465 for reference.

Different spring XML files for development environment vs. deployment when using maven

Summary
We have a central LDAP server that our deployed Java web app should connect to. Our JUnit tests depend on specific data in the LDAP repository, so they need to connect to an embedded ApacheDS LDAP server, primed with a sample data set. How do we make sure that the ApacheDS server doesn't start up when we deploy our webapp?
Details
We are using Spring security, and have the following line in ldap-context.xml to start up the embedded LDAP server:
<security:ldap-server root="dc=test,dc=com" port="33389" ldif="classpath:EmbeddedServerRoot.ldif" />
Currently, our web.xml references both this test context file and our top-level application-context.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:ldap-context.xml
classpath:application-context.xml
</param-value>
</context-param>
We need to make sure that ldap-context.xml is included when we run our JUnit tests, and when we run the webapp directly from eclipse (via WTP), but excluded when we package the war and deploy it to a server.
We're using maven as the build tool. We can fairly easily take care of this situation for our JUnit tests by making sure they include both spring context files in the context configuration:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:ldap-context.xml", "classpath:application-context.xml" })
public class TestStuff {
}
Then, our web.xml would only include application-context.xml, except for one thing - this doesn't work when running from WTP - we need the embedded server to start up in that case as well. Any suggestions?
If you're using Maven, why not use the Assembly plugin to manage your environment deployments. It seems like your spring file is not that complex, so you can have a common spring file which doesn't have the ldap-context.xml reference, and then a test-specific version which does have the ldap reference. When assembly is configured and run, the environment specific file will overwrite the common version, and then you can deploy your packaged app.
An other possibility is to use some properties in the pom and a filtered spring bean file defining aliases for the beans to switch between environments. But you need to habe both beans in the config, but you will use the one or the other.

Categories