Is there any way to refresh spring beans/properties w/o actuator and config server?
In my case, there is only one app/instance which reads the properties from the local file system
myapp.sample.prop1=1
myapp.sample.prop2=2
#ConfigurationProperties("myapp.sample")
public class Prop{
private int prop1;
private int prop2;
}
I autowire and i use it,
#Autowired
private Prop prop;
Occasionally the value might change in the file system. In that case,I just want to call my custom endpoint /reload which should refresh the values by reading the file.
Related
I am creating a spring boot app which has multiple data sources (7 in total) and whilst properties like dbUrl, username and password are data source specific, a great many are common. I obviously don't want to duplicate the properties for each data source and am trying to work out how I can create a HikariConfig instance for each datasource using a blended set of common properties.
The properties have the following format
spring.oracle.datasource.driverClassName
spring.oracle.datasource.autoCommit
spring.oracle.datasource.instance[0].dbUrl
spring.oracle.datasource.instance[0].username
spring.oracle.datasource.instance[0].password
spring.oracle.datasource.instance[1].dbUrl
spring.oracle.datasource.instance[1].username
spring.oracle.datasource.instance[1].password
spring.oracle.datasource.instance[2].dbUrl
spring.oracle.datasource.instance[2].username
spring.oracle.datasource.instance[2].password
spring.oracle.datasource.instance[n].dbUrl
spring.oracle.datasource.instance[n].username
spring.oracle.datasource.instance[n].password
I did try using configuration properties with a class that had the format below (lombok annotations ommitted)
public class DataSourceProperties extends HikariConfig {
public List<Instance> instance;
public static class Instance {
public String dbUrl;
public String username;
public String password;
}
}
But although the object is populated correctly I cannot figure out how I then create the n HikariConfig instances using the properties in the pojo. Clone or BeanUtils does not work, as it copies across all of the null fields which are rejected by the HikarConfig setters.
Anyone know a possible solution without duplicating the common properties and resorting to manual creation of the HikariConfig instances?
In the end, I used Spring's BeanUtils and wrote a function which found the null fields so they could be excluded.
Spring BeanUtils API Doc
I have method which is taking multipart image file,if i want to update same image then obviously i have to take image url as a input but i cant able to take the input as url since it is taking file format
my method:
MediaType.APPLICATION_OCTET_STREAM_VALUE}, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ApiResponse> updatePersonalDataForUser(
#RequestHeader("accessToken") #NotEmpty(message = "accessToken is mandatory") String bearer,
#RequestHeader("mappingId") #NotEmpty(message = "mappingId is mandatory") String mappingId,
#RequestPart("personalInfoObj") String personalInfoObj,
#RequestPart(value = "profileImage") MultipartFile profileImage)
throws IOException {
jobPostController.userRoleAuthorization(mappingId);
userController.oAuthByRedisAccessToken(bearer, mappingId);
ObjectMapper objectMapper = new ObjectMapper();
PersonalInfoResponse personalInfoConv = objectMapper.readValue(personalInfoObj, PersonalInfoResponse.class);
return userController.updatePersonalData(mappingId, personalInfoConv, profileImage, Contants.UserRoleName);
}```
You should take a look at the Spring community project called Spring Content.
This project makes it easy to build contentful applications and services. It has the same programming model as Spring Data. Meaning it can supply implementations for the file storage and REST controllers on top of that file storage, therefore you don't need to concern yourself with creating these yourself. It is to content (or unstructured data) what Spring Data is to structured data.
This might look something like the following:-
pom.xml (for Spring Web MVC. Spring Boot also supported)
<!-- Spring Web MVC dependencies -->
...
<!-- Java API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-fs</artifactId>
<version>1.0.0.M5</version>
</dependency>
<!-- REST API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-rest</artifactId>
<version>1.0.0.M5</version>
</dependency>
StoreConfig.java
#Configuration
#EnableFilesystemStores
#Import(RestConfiguration.class)
public class EnableFilesystemStoresConfig {
#Bean
File filesystemRoot() {
try {
return new File("/path/to/your/uploaded/files");
} catch (IOException ioe) {}
return null;
}
#Bean
FileSystemResourceLoader fileSystemResourceLoader() {
return new FileSystemResourceLoader(filesystemRoot().getAbsolutePath());
}
}
ImageStore.java
#StoreRestResource(path="images")
public interface ImageStore extends Store<String> {
}
This is all you need to do to get REST Endpoints that will allow you to store and retrieve files. As mentioned how this actually works is very much like Spring Data. When your application starts Spring Content will see the spring-content-fs dependency, know that you want to store content on your filesystem and inject a filesystem implementation of the ImageStore interface into the application context. It will also see the spring-content-rest and inject a controller (i.e. REST endpoints) that talk to the ImageStore interface. Therefore, you don't have to do any of this yourself.
So, for example:
curl -X POST /images/myimage.jpg -F "file=#/path/to/myimage.jpg"
will store the image on the filesystem at /path/to/your/uploaded/files/myimage.jpg
And:
curl /images/myimage.jpg
will fetch it again and so on...these endpoints support full CRUD and the GET & PUT endpoints also support video streaming (or byte range-requests).
You could also decide to store the contents elsewhere like in the database with your entities, or in S3 by swapping the spring-content-fs dependency for the appropriate Spring Content Storage module. Examples for every type of storage are here.
In addition, in case it is helpful, often content is associated with Spring Data Entities. So, it is also possible to have the ImageStore interface implement ContentStore, like this:
> FileStore.java
#StoreRestResource(path="images")
public interface ImageStore extends ContentStore<PersonalInfo, String> {
}
And to add Spring Content-annotated fields to your Spring Data entities, like this:
> PersonalInfo.java
#Entity
public class PersonalInfo {
#Id
#GeneratedValue
private long id;
...other existing fields...
#ContentId
private String contentId;
#ContentLength
private long contentLength = 0L;
#MimeType
private String mimeType = "text/plain";
...
}
This approach changes the REST endpoints as the content is now addressable via the Spring Data URL. So:
POST /personalInfos/{personalInfoId} -F "image=#/some/path/to/myimage.jpg"
will upload myimage.jpg to /path/to/your/uploaded/files/myimage.jpg. As it did before but it will also update the fields on the PersonalInfo entity with id personalInfoId.
GET /personalInfos/{personalInfoId}
will get it again.
HTH
I am writing 2 applications using cloud config, one the server and another is the client. The server is running on 8888 and holding the configuration stored in GIT repository. It has the property:
spring.cloud.config.server.git.uri=${HOME}/Desktop/config-repo
The client is using the above configuration where it has one property as: message. Client is a restful webservice which has a controller as:
#RestController
class Controller{
#Value ("${message}")
private String message;
#Value ("${course}")
private String course;
#RequestMapping("/showMessage")
private String showMessage(){
return message;
}
#RequestMapping("/showCourse")
private String showCourse(){
return course;
}
}
When accessing http://localhost:8080/showCourse it is perfectly working and showing the message in the web page which is configured in the message.properties.
Issue when using #RefreshScope
Now when I am using #RefreshScope with the controller, I am not at all getting any output where the webpage is blank. When debugging, the issue is with
#Value ("${message}")
private String message;
#RequestMapping("/showMessage")
private String showMessage(){
return message;
}
in the controller where the message is null.
This happens when using the annotation - RefreshScope.
I have added the code/project at GIT: https://github.com/santoshkar/SpringBootCentralConfigUsingGit.git
Kindly help.
Thanks,
Santosh
Using Spring Boot 1.0, I was able to customize the actuator endpoints as follows...
endpoints.beans.id=foo/springbeans
This would expose the spring beans endpoint at /foo/springbeans. However, in the latest Spring Boot this is not possible due to the following code in the AbstractEndpoint...
#NotNull
#Pattern(regexp = "\\w+", message = "ID must only contains letters, numbers and '_'")
private String id;
I tried using the underscore, but that just exposes the endpoint at /foo_springbeans. This lead me to try to add a view controller so I could at least redirect or forward to the default endpoint, but I couldn't find an easy way to do that either. How can I configure the endpoint or a redirect?
After opening an issue with Spring Boot and being told to simply move the entire management context as suggested by Rafal, I was able to achieve what I was looking for, albeit with more code than I'd like. I created a custom MvcEndpoint as follows...
#Named
public class MyCustomHealthCheck extends EndpointMvcAdapter {
private HealthEndpoint delegate;
#Inject
public MyCustomHealthCheck(HealthEndpoint delegate) {
super(delegate);
this.delegate = delegate;
}
#ResponseBody
#RequestMapping(value = "/springbeans", method = GET)
public Health foo() {
return delegate.invoke();
}
}
The code above creates the /springbeans path underwhatever path the HealthEndpoint is mapped to, which is fine enough for my usecase. If I wanted it mapped to an entirely separate path, I would have needed to create a dummy endpoint and stick this MvcEndpoint under that.
For Spring 1.x Following property should help you:
endpoints.beans.path: /foo/springbeans
You can use it with any standard endpoint and if you want to use it with custom endpoint that extends AbstractEndpoint then you need additional annotation:
#ConfigurationProperties(prefix = "endpoints.customEndpoint")
and then use property:
endpoints.customEndpoint.path: /custom/endpoint
I have requirement for spring mvc 3 caching. Requirement is : while starting the server, we need to call database for one dropdown and put those values in the cache. So that whenever we required those values, we need to retrieve from cache.
Please help me with an example.
Thanks in advance.
May be you can use init-method (Spring 2.5) or #PostConstruct annotation (in Spring 3.0).
This method will be called during server start up
The following is code snippet
#Component
public class CacheDBData {
private String values[];
//add setter & getter
//This will be called during server start up after properties are initialised
#PostConstruct
public void getDataFromDB() {
values = //Logic to get data from DB and store that in values property
}
}
Suppose for example you can use in class as follows
#controller
public class HomeController {
#Autowired
private CacheDBData cacheDBData ;
//getter and setters
private void methodxyz() {
String values[] = cacheDBData.getValues();
}
}
I've had success with Ehcahe for Spring. There's a couple of config files to setup but after that you simply annotate the methods you want to cache the output from and it just works.
This has the advantage that you can change the values coming back from the service/database and NOT have to restart your app, unlike the accepted answer.