I want to set the maxSwallowSize property for boot supplied tomcat.
My application.properties has this line:
server.context-parameters.maxSwallowSize=20971520
Doesn't work for some reason. Other properties like server.port work well.
Debugging the creation in TomcatEmbeddedServletContainerFactory I see that there is a ServletContexInitializer (InitParameterConfiguringServletContextInitializer) with this property but it doesn't seem to be used in any way. (Even though it's in a variable name initializersToUse, ironic ;p)
I don't like the kill of a connection when the upload exceeds the max size set by
multipart.max-request-size=10MB
multipart.max-file-size=2MB
Is this the correct way of setting this property? During debuggin I can see that the IdentityInputFilter has the default value of 2MB.
newest version of org.springframework.boot:spring-boot-starter-web
server.context-parameters (as defined in the documentation can be used to specify the init parameters of the servlet context). maxSwallowSize is a property of the connector. That's a different thing I guess.
We don't have an explicit property for that but you can always configure it via your own TomcatEmbeddedServletContainerFactory.
#Bean
public TomcatEmbeddedServletContainerFactory containerFactory() {
return new TomcatEmbeddedServletContainerFactory() {
protected void customizeConnector(Connector connector) {
super.customizeConnector(connector);
if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol) {
(AbstractHttp11Protocol <?>) connector.getProtocolHandler()).setMaxSwallowSize(value);
}
}
};
}
The configuration like above didn’t help me(I’m using Spring Boot 1.5.10)
I found that the solution was to set
application.properties:
spring.http.multipart.max-file-size=10MB
spring.http.multipart.max-request-size=10MB
and all uploads works OK without configurating Tomcat.
Configuration spring.http.multipart.max-request-size is not the same as maxSwallowSize. The former configures the application and the latter configures the Tomcat server.
So in addition to spring.http.multipart configuration you also should provide configuration for maxSwallowSize, which can simply be done for Spring Boot 2 by setting application property:
server.tomcat.max-swallow-size=100MB
Related
I have a Spring Boot 2.7 Web/MVC server application with profiles for different environments (DEV/QA/PROD). I have a common application.properties with shared configuration and environment specific configuration, for example, JDBC URLs in separate application-<environment>.properties on the classpath.
If the application is started without a profile being selected, it fails with a cryptic error message complaining about a jdbcUrl property missing and not being able to initialize the context - all this within a huge stack trace. This is self-explanatory for the developer, but not trivial for an operations person.
What would be the Spring way of checking if exactly one profile is selected and displaying a non-stacktrace, human (operator) friendly error message?
I am looking for something similar to what is shown if the server port is already in use.
I would like to avoid hacks and find the Spring-endorsed solution for this.
it fails with a cryptic error message complaining about a jdbcUrl property missing and not being able to initialize the context - all this within a huge stack trace
The more fundamental problem seems to be that you're fighting the built-in Boot facilities that provide assistance to humans out of the box. Instead of using #Value("${jdbcUrl}") in your code, you should inject a javax.sql.DataSource, and Boot will automatically configure one when spring.datasource.url is set. If it's not present, you'll get an error that says "no bean of DataSource is available", and the auto-config report will explain why.
You can use a postprocessor for a value . If it is not present, then log your human friendly error error message and quit the application.
e.g
#Bean
public BeanPostProcessor bpp(Environment environment) {
return new BeanPostProcessor() {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(environment.getActiveProfiles()[0].equalsIgnoreCase(environment.getDefaultProfiles()[0])){
// Your Error message goes here
System.exit(1);
}
return bean;
}
};
}
I'm new in Spring applications, and see the big difference between configurations in springBoot and spring. So my questin is: apart from spring-boot, is there a way to setup a proper spring application(with web mvc, security, aop, ...), without any xml config file (ie : config relying only on annotations).
Yes, there is a way to do this in Spring. Spring Boot is after all an enhanced, autoconfigured Spring (with other cool features). That means that everything there is in Spring Boot should be achievable in Spring as well, but you would have do a bit/a lot of Your own extra work.
Moving straight to the point, in order to achieve what you want, you would need to undertake the following steps:
Create a class, which will store all the configuration (basically the properties you would store in the xml file) - let's call it AppConfig.class
Annotate the AppConfig.class with #Configuration - this will inform Spring that this class is the source of configuration;
Annotate the AppConfig.class with #ComponentScan("com.app") - here, You need to provide a package, from which Spring has to start component scanning in order to find Beans to be registered in Spring Container. Important note is, that it will scan the package and it's subpackages, so you would mostly want to provide here the top level package;
If you need some data to be injected into your beans, you would want to use the #PropertySource("classpath:application.properties") - I have provided here the default value, which Spring Boot uses internally in case you want to inject some data into your beans at runtime. For this to work, you need to inject into AppConfig.class an Environment.class
To show it on the example:
#Configuration
#ComponentScan("com.app")
#PropertySource("classpath:application.properties")
public class AppConfig {
// it will help to pull the properties incorporated in the file you have provided in the #PropertySource annotation
private Environment environment;
//inject it
public AppConfig(Environment environment) {
this.environment = environment;
}
// build your beans - the getProperty method accepts the key from application.properties
// file and return a value as a String. You can provide additional arguments to convert
//the value and a default value if the property is not found
#Bean
public Product product() {
return new Product(
environment.getProperty("product.name", "XXX"),
environment.getProperty("product.price", BigDecimal.class, BigDecimal.ZERO),
environment.getProperty("product.quantity", Integer.class, 10)
);
}
}
I hope that it helps
Followed this tutorial https://developer.ibm.com/messaging/2018/04/03/mq-jms-spring-boot/ and developed a Spring Boot JMS applicatin which sends a message to IBM MQ. (used this dependency - mq-jms-spring-boot-starter).
As per the tutorial, the configuration properties (Queue Manager, Channel, Port etc) can be given in application.yml/ application.properties file as below, and JmsTemplate will automatically be configured with the properties.
ibm.mq.queueManager=QM1
ibm.mq.channel=SYSTEM.DEF.SVRCONN
ibm.mq.connName=server.example.com(1414)
ibm.mq.user=user1
ibm.mq.password=passw0rd
The application works perfect and it sends message to the MQ now this way.
But I want to set the properties inside the class, not from the properties file (reading from a database or something). How to set these values inside the class?
You can use a customizer method on the CF after the initial properties have been populated.
In the Application class, this code allows additional properties to be configured:
#Bean
public MQConnectionFactoryCustomizer myCustomizer() {
MQConnectionFactoryCustomizer c = new MQConnectionFactoryCustomizer() {
#Override
public void customize(MQConnectionFactory factory) {
factory.setXXXX(property, value);
}
};
return c;
}
I use Spring Data LDAP and Spring Boot provides out of the box support for an embedded UnboundID server. However, when I use Spring Data LDAP's #Entry annotation, I need to specify a different base in the annotation based on whether I'm using the embedded UnboundID LDAP server, or a remote Active Directory server.
I was attempting to do this with SpEL and profile-based properties by specifying:
#Entry(base = "${ldap.person.base}", ...)
Then I have an application.propreties with ldap.person.base=OU=AD Person Base and an application-embedded.properties with ldap.person.base=OU=Embedded Person Base.
However, the #Entry annotation does not seem to support SpEL evaluation:
javax.naming.InvalidNameException: Invalid name: ${ldap.person.base}
There is an open issue in Spring LDAP to add support for this, but is there any workaround or some other way I can accomplish this until it is supported in Spring LDAP?
I'm not sure I'm following here, but assuming you're using the LDAP auto-configuration in Spring Boot, is it not enough to set the property spring.ldap.base to one or the other (OU=AD Person Base or OU=Embedded Person Base) based on the profile you're using?
Both EmbeddedLdapAutoConfiguration and LdapAutoConfiguration use an LdapProperties object to set various attributes on the LdapContextSource during bean creation, including its base. As far as I can tell, you won't have to define it for each #Entry in your codebase if LdapContextSource.base is set.
If you're not using the auto-configuration, and if I'm correct in my assumptions, you should still be able to create your own LdapContextSource bean and set its base to the desired value based on a Spring property.
Turns out the reason I needed a different base in the first place is because Spring was not setting the base on the ContextSource.
When you let Spring Boot autoconfigure the embedded LDAP server, it creates a ContextSource as such in EmbeddedLdapAutoConfiguration:
#Bean
#DependsOn("directoryServer")
#ConditionalOnMissingBean
public ContextSource ldapContextSource() {
LdapContextSource source = new LdapContextSource();
if (hasCredentials(this.embeddedProperties.getCredential())) {
source.setUserDn(this.embeddedProperties.getCredential().getUsername());
source.setPassword(this.embeddedProperties.getCredential().getPassword());
}
source.setUrls(this.properties.determineUrls(this.environment));
return source;
}
As you can see, nowhere in there does it call source.setBase(). So to solve this, I added a configuration file with #Profile("embedded") and manually created a ContextSource where I set the base myself (I leave off the credentials part because I don't use credentials for the embedded server):
#Configuration
#Profile("embedded")
#EnableConfigurationProperties({ LdapProperties.class })
public class EmbeddedLdapConfig {
private final Environment environment;
private final LdapProperties properties;
public EmbeddedLdapConfig(final Environment environment, final LdapProperties properties) {
this.environment = environment;
this.properties = properties;
}
#Bean
#DependsOn("directoryServer")
public ContextSource ldapContextSource() {
final LdapContextSource source = new LdapContextSource();
source.setUrls(this.properties.determineUrls(this.environment));
source.setBase(this.properties.getBase());
return source;
}
}
Now, I can leave the value of the base attribute in my #Entry the same for both the Active Directory server and the embedded UnboundID server and it works properly.
How to create project architecture to support multiple envionment. Each environment will have different datasource from different property file like(dev-propertfile,test-propertyFil,Production-propertyfile) with help of spring's
org.springframework.core.env.Environment;
I'll give step by step procedure for Spring boot applications.
Inside /src/main/resources/application.properties mention spring.profiles.active=dev (or Prod)
Create /src/main/resources/application-dev.properties and give your custom dev configurations here.
Create /src/main/resources/application-prod.properties and give your custom prod configurations here.
Run.
Put property file in same location as application.property and follow
the naming convention application-{profile}.properties like
application-dev.properties,application-test.properties,
application-prod.properties
And in application.properties set spring.profiles.active=dev,test etc
For Spring Boot applications it will work easily even by using a YAML File
spring:
profiles: dev
property: this is a dev env
---
spring:
profiles: prod
property: this is a production env
---
However, for a Spring MVC application, it needs more work. Have a look at this link
Basically, it involves 2 steps
Get the Spring Profile within servlet context
If you have set the profile on the server and want it to retrieve it within your application you can use System.getProperty or System.getenv methods.
Here is the code which fetches the profile and defaults it to a local profile, if no profile has been found.
private static final String SPRING_PROFILES_ACTIVE = "SPRING_PROFILES_ACTIVE";
String profile;
/**
* In local system getProperty() returns the profile correctly, however in docker getenv() return profile correctly
* */
protected void setSpringProfile(ServletContext servletContext) {
if(null!= System.getenv(SPRING_PROFILES_ACTIVE)){
profile=System.getenv(SPRING_PROFILES_ACTIVE);
}else if(null!= System.getProperty(SPRING_PROFILES_ACTIVE)){
profile=System.getProperty(SPRING_PROFILES_ACTIVE);
}else{
profile="local";
}
log.info("***** Profile configured is ****** "+ profile);
servletContext.setInitParameter("spring.profiles.active", profile);
}
To access the application-dev.properties, say now you will need to use
#Profile("dev") at the class level
The following code will fetch the application-dev.properties and common.properties
#Configuration
#Profile("dev")
public class DevPropertyReader {
#Bean
public static PropertyPlaceholderConfigurer properties() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[] { new ClassPathResource("properties/common.properties"), new ClassPathResource("properties/application-dev.properties") };
ppc.setLocations(resources);
ppc.setIgnoreUnresolvablePlaceholders(true);
return ppc;
}
}
For accessing say application-prod.properties you have to use #Profile("prod") at the class level. More details can be found here
Take a look at Spring Profile. You will define a set of profiles configurations, like Test, Dev, Production. And then, when you launch the application, you can define wich profile it should use.
Here are some tutorials of how to use.
And this guys had the same problem as yours: How to config #ComponentScan dynamic?
We wanted a way to load different properties from application-<your_env>.properties file depending on the environment (spring profile) in a Spring MVC project, so we implemented a configuration class something like this.
#Configuration
#PropertySource({ "classpath:application-${envTarget:dev}.properties" })
#Data
public class EnvironmentConfig {
#Value("${files.s3.accessId:}")
String s3AccessId;
#Value("${files.s3.accessToken:}")
String s3AccessToken;
.
.
.
}
Then we loaded the EnvironmentConfig in the class where we needed to use it.
While running the application, you just need to pass the -DenvTarget=<your_env>, and it will pick up the application-<your_env>.properties file from src/resources folder of the project.
In the above code, it will load values from application-dev.properties files when no envTarget is specified.
Thanks to Karthikeyan Muthurangam for suggesting this clever solution.