📜 ⬆️ ⬇️

Configuring J2SE and J2EE Applications: Standard Methods and Their Alternatives

Nowadays, there are many options for building Java applications and their configuration tasks are solved in different ways.
The article will discuss the techniques and features of configuring J2SE and J2EE applications using standard JDK tools, as well as alternatives to these methods.


J2se


java.util.Properties

The classic way to configure applications is to use the java.util.Properties class. Inside, everything is very simple - in fact, this is an extension of the java.util.Map interface with the ability to save and initialize default values.

There are several minuses:

')
This list of minuses suggests that the use of pure Properties in real production is inefficient. The first thing that can be encountered with this approach is complaints from the maintenance service that making any changes to the configuration requires restarting the application.
The most likely, in my opinion, negative consequences of this:


All this can be objected: "You can just add rereading the settings file and the event generation subsystem" - yes, this is so, only all this has already been done and done to the smallest detail, which seem unclear now, but always appear.
In the next article I will talk about the Commons Configuration and how the problems identified above are solved there.
For now, let's consider typical configuration options for J2EE applications.

J2EE-EJB3


Resource injection

One of the easiest ways to configure EJB applications is to use a deployment descriptor (ejb-jar.xml):

< enterprise-beans >
< session >
< ejb-name > MyService </ ejb-name >
< env-entry >
< env-entry-name > myProperty </ env-entry-name >
< env-entry-type > java.lang.String </ env-entry-type >
< env-entry-value > 100500 </ env-entry-value >
</ env-entry >
</ session >
</ enterprise-beans >



In the descriptor we specify the name (env-entry-name), the type (env-entry-type) and the parameter value (env-entry-value), then we inject it using the Resource annotation:
@Resource(name = "myProperty" )
private String myProperty;
@PostConstruct
public void postConstruct() {
System. out .println( "myProperty = " + myProperty);
}



This approach allows you to work with the parameters of the following types:


The disadvantages include the fact that a change in the parameters leads to a recurring application, which, in turn, leads to a certain period of inoperability.
Redeploy policy depends on the settings of the scanner of application descriptor changes on the application server.
So, for example, in the case of the JBoss 5.x-6.x application server, changing ejb-jar.xml is guaranteed to result in redeployment (unless, of course, the scanner is turned off and rehearse manually, via the JMX console).

Using external settings file


There is a very useful document - limitations of the EJB technology . This document has clear indications of not using file resources. The indications are as follows:


However, using files as read-only data sources is permissible when they are inside EE applications. The fact is that in the case of cluster deployment, the EE application will be the same on all nodes.

Thus, we come to the classic use of java.util.Properties inside EE applications:
@Stateless(mappedName = "BackendService" )
public class BackendServiceBean implements BackendServiceLocal {

private static final String P_PROPERTIES = "myProperties.properties" ;

private static final Logger logger = LoggerFactory.getLogger(BackendServiceBean. class );

@EJB
private DataRepositoryLocal dataRepository;

@Resource(name = "remoteURL" )
private String remoteURL;

private Properties properties;

@PostConstruct
private void init(){
InputStream propertiesResource = null ;
try {
propertiesResource = getClass().getResourceAsStream(P_PROPERTIES);
properties = new Properties();
properties.load(propertiesResource);
} catch (Exception e) {
logger.error( "Error" , e);
} finally {
if (propertiesResource != null ){
try {
propertiesResource.close();
} catch (Exception e) {
logger.error( "Error" , e);
}
}
}
}

public Properties getProperties() {
return properties;
}



The downsides are the same as those previously mentioned for J2SE and java.util.Properties. Plus, we are in the context of J2EE and cannot simply add a stream that tracks file changes and generates events (since you cannot create threads in a J2EE application).
Someone might say: "We need to re-read the .properties file every time the application calls getProperty on our properties-proxy-object." Yes, this can be done, but in this case you should forget about the high performance of the application - opening the file for reading, loading it into the buffer, parsing and creating an instance of Properties will introduce a noticeable delay in processing.
The correct application of this solution is to store only static read-only settings.

Other options


The options described earlier have a disadvantage - correct work is provided only with static parameters. If it is necessary to obtain always the actual value of any parameter, then you need to look for other options.

For J2EE applications, these options can be:


For both J2EE and J2SE applications, you can use different frameworks / create your own, customized for solving configuration tasks.

J2EE-servlets


When configuring servlets, we are dealing with a web.xml descriptor that sets the parameters we need:
< web-app version ="2.5" xmlns ="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation ="http://java.sun.com/xml/ns/j2ee java.sun.com/xml/ns/j2ee/web-app_2_5.xsd" >

<!-- -->
< context-param >
< param-name > myContextParam1 </ param-name >
< param-value > value1 </ param-value >
</ context-param >
< context-param >
< param-name > myContextParam2 </ param-name >
< param-value > value2 </ param-value >
</ context-param >

<!-- -->
< filter >
< filter-name > myFilter </ filter-name >
< filter-class > net.universe.filter.EntityAccessFilter </ filter-class >
< init-param >
< param-name > checkType </ param-name >
< param-value > ldap </ param-value >
</ init-param >
< init-param >
< param-name > myParam </ param-name >
< param-value > true </ param-value >
</ init-param >
</ filter >

<!-- -->
< servlet >
< servlet-name > MyServlet </ servlet-name >
< servlet-class > net.universe.servlet.MyServlet </ servlet-class >
< init-param >
< param-name > servletParam1 </ param-name >
< param-value > paramValue1 </ param-value >
</ init-param >
< load-on-startup > 1 </ load-on-startup >
</ servlet >
</ web-app >



The setting is to change the param-value configuration items. After changes and saving the file, we also have a redeploy application with a subsequent period of inoperability. This configuration method, as well as the variant with ejb-jar.xml, is most suitable for parameters that are not intended to change in the course of the application. Techniques for working with runtime settings here are similar to those used in the case of EJB - database, JNDI, etc ...

Common to all


System.getProperty

Common to all the listed configuration methods is the use of system parameters passed in the launch string of a Java application:
java -DmyProperty1=myPropertyValue1 -DmyProperty2=myPropertyValue2 -jar myapp.jar


After this, the configuration parameters can be taken using the java.lang.System class:
String string = System.getProperty("myProperty1");


This method is limited in the context of working with J2EE - when operating in cluster mode, the system variable may not arrive at all nodes. Why “can” - because, for example, the JBoss application server has the SystemPropertiesService service and fragments can be included in our EE application by configuring it (i.e. the system variable will end up on all nodes, because in the configuration files in the application).

Quite often, this configuration method is used to quickly add some new check conditions to the code if necessary.
For example, it is so fast that there is only time for adding conditions, compiling a class and replacing it in an already deployed EE application / library with subsequent redeploying / restarting.
Of course, this option can not be called good practice, but nevertheless this happens in real life.

You can also note an alternative to this approach - the use of aspect-oriented programming / injection in byte-code. These techniques allow the original application to remain unchanged, but require a higher level of development skills, especially when it comes to the dynamic implementation of AOP interceptors on a production system that is running.

Jmx


JMX is a convenient tool for a lot of things, including for configuring applications. You can combine the application of java.util.Properties/Commons Configuration and the exposed MBean with methods for setting / getting the values ​​of our parameters (if set, then delegating to properties.setProperty).
Such a solution can be successfully applied where there is no access to the configuration files, but there is access to the MBeanServer via the network.

The disadvantages of this approach are as follows:


That's all for now.

An article about the Commons Configuration library will be completed soon, which greatly expands the possibilities for working with configuration files in J2SE and J2EE applications.

Thanks for attention!

Source: https://habr.com/ru/post/129383/


All Articles