I've recently began using EHCache for caching purposes. I know, how to use it in Java code, but I'm still not sure about the configuration file.
So, I have an ear project, that includes several war modules. If all these modules use ehcache, should I put a copy of ehcache.xml in WEB-INF for each module, or put it somewhere in ear file itself (META-INF maybe?)
Also, it's not clear from the documentation, whether or not all these modules will use the same cache instance? The application is deployed at glassfish, will EHCache run the same cache for each module in ear, or each module will get his own singleton instance when used like this:
CacheManager singleton = CacheManager.create();
According to ehcache.xml file. There is no rule where you will put this file, but if you are working on a big project I presume that you have several profiles (e.g. for QA, DEV, PROD). As ehcache may differ depending on profile (for example, if you have ehcache jms replication enabled) you can have different JMS Server IPs set up there or amount of objects in cache regions may differ, so I suggest to put in where you have profile-dependent file (e.g. web.xml, log4j.properties). Then if you have context configuration in a separate xml file like:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context-config.xml</param-value>
</context-param>
then you may add in that context-config.xml file:
<import resource="context-config.xml"/>
That context-config.xml file may contain description of cacheManager bean, that you will be able to Autowire where do you need it. So the context-config.xml may look like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
</bean>
</beans>
Answering your second question. From my example, it will depend on how you will define this bean, you can define it as a singleton and then you will have only one instance of cacheManager or you can leave the instantiation to Spring.
In my opinion, you can autowire cacheManager to the class with general logic for cache invalidation or cache "creation" and that will make a lot of sense. Hope that I helped you.
There is no hard and fast rule for putting in your ehcache configuration file.
But, personally I keep my ehcache config file with all the other configuration
and properties file.
For example, I will store the path to my ehcache config xml file in some static final variable, (helps in keeping the path configurable )
private static final String EHCACHE_CONFIG = "<path to this file>/ehcache.xml";
And then when I initialize the cache manager, I give in the path to config
file as a parameter
CacheManager manager = new CacheManager(EHCACHE_CONFIG);
Related
Testing the below Spring profile :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="bean1"
class="com.Test2">
</bean>
<beans profile="DEV">
<bean id="bean1"
class="com.Test1">
</bean>
</beans>
<bean id="bean1"
class="com.Test2">
</bean>
</beans>
It seems that com.Test2 is loaded if a Spring profile is not set. Is this the expected behavior ?
I'm just trying to understand how Spring loads classes if profiles are set/unset. It seems that if a profile is not set then Spring will create the class if it exists outside the profile, if a profile is set then Spring will create the class for the profile. If the class also exists outside the profile it is not loaded when the profile is loaded.
So, in the above example if DEV profile is set then com.test1 is loaded for bean id bean1, if no profile is set then com.test2 is loaded for bean1. Is this the expected behavior.
The behavior you described is the expected one.
Usually, in Spring there is a rule of thumb related with bean loading: every bean that is loaded with the same name as another one, and that is processed later, will override the older one.
The key term here is being processed later.
In your specific use case, first, every bean that is not defined in any profile will be included, at first glance, in the Spring context.
When you activate a profile, as in your example, you are making visible a new piece of configuration: if this configuration contains a bean with the same name as other one already processed, as indicated, it will override this bean in the Spring context.
This fact is always true independently of the mechanism, Java, XML configuration, or both, you use to define the beans.
It is important to note that the order in which Spring process the different configurations that can be found across the code and different libraries is not deterministic. In your specific use case, when using XML configurations, you can safely assume that it will load the different configurations in the order in which they are imported in your main configuration files (the ones configured for the context load mechanism you choose) and, for every one of them, in the order in which the beans are defined within the same XML file, if that is the case.
This general override rule is always true except in the case you use Spring Boot 2: in this case, if you override a bean by name, by default, an exception will be raised indicating that a bean with this name is already defined in the Spring context. You can restore the usual override behavior by specifying the following configuration property:
spring.main.allow-bean-definition-overriding=true
In addition to profiles, Spring Boot will allow you to load a bean or not depending on several types of conditions. This mechanism is applied usually when loading #Configurations in the auto configuration process.
Yes it is the expected behaviour, Any bean that does not specify a profile belongs to the "default" profile. All the beans with no #profile annotation (or for XML) specified belongs to the default profile.
If you don't specify explicitly a profile then "default" profile is loaded that belong to all beans that are not in scope of any profiles.
So yes, if you run your application without any profile bean1 will be loaded as an instance of com.Test2, in other hand by configuring a profile all beans that are not in scope of a profile ("default") will be replaced with that once that matches definition (in your case com.Test1).
For more details check:
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-definition-profiles
https://www.baeldung.com/spring-profiles
I was needing to use JPA in standalone application, so I've found the example http://tomee.apache.org/latest/examples/jpa-hibernate.html as starter.
They create EJB Context via
final Context context = EJBContainer.createEJBContainer(p).getContext();
Then there's a log line:
INFO - Enterprise application "/Users/dblevins/examples/jpa-hibernate" loaded
You need to know that application name to wizard out the search string for lookup:
context.lookup("java:global/jpa-hibernate/Movies");
What makes me worry that I've found out no information on where those 'jpa-hibernate' part comes from. It either comes from artifact id, or, even worse, from the current directory name, which makes the code using it terribly dependend on context, that the developer doesn't control.
I've totally find to google out how to specify that application name so that I could use lookup that will work no matter who invokes my code and where it is copied.
How can I configure this application name?
The Embedded EJB container used in this unit test example allows to run EJBs outside a Java EE container. A good introduction/tutorial can be found here: https://docs.oracle.com/javaee/7/tutorial/ejb-embedded002.htm
It supports the same configuration files as regular EJB-jars, namely it supports the ejb-jar.xml configuration file (the module deployment descriptor). It is possible to configure the module name there, e.g.
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
version="3.1">
<module-name>myapp</module-name>
</ejb-jar>
This file needs to go into the jar's META-INF directory.
A colleague of mine and I are playing around with the following spring configuration:
<beans>
<context:property-placeholder location='classpath:/configuration.properties'/>
<bean id="myBean" class="${type}" />
</beans>
We want to be able to provide a environment specific implementation of myBean. On a developers system the value of type would be a lightweight implementation of whatever myBean does. And in a production environment we would use a full-blown version.
When my colleague runs the code, everything works. When I run the code, I get a ClassNotFoundException, because spring tries to instantiate ${type}.class. And it is not like it sometimes works and sometimes does not. On my machine it always fails and on my colleagues machine it always works.
Does anybody knows what the problem is?
Thx in advance,
Yevgeniy
UPDATE
as requested, here is how we load the application context:
ClassPathXmlApplicationContext("application-configuration.xml");
the content of the properties file is pretty simple:
type=foobar.TestServiceImpl
Instead of trying to override the class with a placeholder, I would like to suggest an alternative approach for your problem. You could use the Profile functionality of Spring.
It would be simplier and safer to change the class depending of the environment.
<beans>
<beans profile="dev">
<bean id="myBean" class="dev.impl.MyBean" />
</beans
<beans profile="prod">
<bean id="myBean" class="prod.impl.MyBean" />
</beans
</beans>
You can then activate a given profile in development by adding the following system property to your server -Dspring.profiles.active="dev".
You can define a default profile which will be used by adding the following to your web.xml:
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>prod</param-value>
</context-param>
The following assumes Spring 3.1+.
I can tell you this much for sure. For Spring to fail with a ClassNotFoundException for class
${type}
means that it did not resolve the placeholder.
When you specify
<context:property-placeholder location='classpath:/configuration.properties'/>
Spring uses a PropertyPlaceholderBeanDefinitionParser to register either a PropertySourcesPlaceholderConfigurer or a PropertyPlaceholderConfigurer bean which will do the placeholder resolution.
PropertySourcesPlaceholderConfigurer is a BeanFactoryPostProcessor. This mean that it can modify bean definitions. Without going into much detail, if it cannot resolve a placeholder, the process fails with an IllegalArgumentException that states that the placeholder could not be resolved.
If you're saying that the ${type} wasn't resolved, then no PropertySourcesPlaceholderConfigurer or PropertyPlaceholderConfigurer beans were created. This probably means your context does not have
<context:property-placeholder location='classpath:/configuration.properties'/>
With the information you've shown us, that is what I think is going on. If you can prove otherwise, I'll ask you to provide a small reproducible example. Ideally, you would show the contents of your compiled project.
As far as I remember property placeholder fails mutually. This means that if it cannot locate file configuration.properties on your machine the property is just not initialized.
To approve this assumption try to "break" the application on your colleague's machine: change the location to something wrong, e.g. classpath:/configuration12345.properties. I believe that the problem will appear on his machine too.
Now, check what's wrong in your environment and why this file cannot be found there.
BUT: do you have something against profiles? Spring provides a cool feature that is attended exactly for your use-case: spring profiles.
I am studying Spring MVC. Today, trying to understand how implement a JDBC DAO, I have found this "Hello World" in Spring (Spring, not Spring MVC) and I begin to see it (because I think that to realize a DAO I have to create a separate Spring Project that execute the access to the data...)
http://www.tutorialspoint.com/spring/spring_hello_world_example.htm
OK, this is a standalone application and this is not a web application, so it doesn't have the web application structure (WEB-INF folder, web.xml file and the dispatcher servlet configuration file that I have in my web app)
In this example I have a Beans.xml configuration file that is used to assign unique IDs to different beans and to control the creation of objects with different values without impacting any of the Spring source files...
For example in this example I use the Beans.xml file to pass the "Hello World" message value for "message" variable and so I can print this value without impacting HelloWorld.java and MainApp.java files
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
</beans>
So I have some question for you about it:
Is this file the file that configure my Bean Factory? I think that, as well as I pass a text value as the value of a variable I could also inject a bean as a dependency of another bean.
Is it right?
In this example, can I don't use the Beans.xml file and using in place of the annotation system?
1) This Beans.xml (actually you can name it whatever you want) is a Spring configuration file. It holds a configuration metadata.
From the official Spring documentation:
5.2.1 Configuration metadata
As the preceding diagram shows, the Spring IoC container consumes a
form of configuration metadata; this configuration metadata represents
how you as an application developer tell the Spring container to
instantiate, configure, and assemble the objects in your application.
Configuration metadata is traditionally supplied in a simple and intuitive XML format, but it is not the only allowed form of configuration metadata (see the answer to your second question)
And yes, you are right: you can inject another bean as a reference.
From the official Spring documentation:
5.3 Bean overview
A Spring IoC container manages one or more beans. These beans are
created with the configuration metadata that you supply to the
container, for example, in the form of XML definitions.
Within the container itself, these bean definitions are represented as
BeanDefinition objects, which contain (among other information) the
following metadata:
A package-qualified class name: typically the actual implementation class of the bean being defined.
Bean behavioral configuration elements, which state how the bean should behave in the container (scope, lifecycle callbacks, and so
forth).
References to other beans that are needed for the bean to do its work; these references are also called collaborators or
dependencies.
Other configuration settings to set in the newly created object, for example, the number of connections to use in a bean that manages a
connection pool, or the size limit of the pool.
Simple example of using references to other beans from the official documentation:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested <ref/> element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater 'ref' attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
</beans>
2)
From the official Spring documentation:
5.2.1 Configuration metadata
...
XML-based metadata is not the only allowed form of configuration
metadata. The Spring IoC container itself is totally decoupled from
the format in which this configuration metadata is actually written.
For information about using other forms of metadata with the Spring
container, see:
Annotation-based configuration:
Spring 2.5 introduced support for annotation-based configuration
metadata.
Java-based configuration:
Starting with Spring 3.0, many features provided by the Spring
JavaConfig project became part of the core Spring Framework. Thus you
can define beans external to your application classes by using Java
rather than XML files. To use these new features, see the
#Configuration, #Bean, #Import and #DependsOn annotations.
Also read this:
Spring Without XML: The Basics of Spring Annotations vs. Spring XML Files
I created a folder /src/main/resources/ and placed this beans.xml file there:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<bean id="employee" class="HelloSpring.Employee">
<property name="name" value="test spring"></property>
</bean>
</beans>
It worked!
I accessed it like this:
package HelloSpring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Customer {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("./beans.xml");
Employee obj = (Employee) ctx.getBean("employee");
obj.displayName();
}
}
I have a handful of projects that all use one project for the data model. Each of these projects has its own applicationContext.xml file with a bunch of repetitive data stuff within it.
I'd like to have a modelContext.xml file and another for my ui.xml, etc.
Can I do this?
From the Spring Docs (v 2.5.5 Section 3.2.2.1.):
It can often be useful to split up
container definitions into multiple
XML files. One way to then load an
application context which is
configured from all these XML
fragments is to use the application
context constructor which takes
multiple Resource locations. With a
bean factory, a bean definition reader
can be used multiple times to read
definitions from each file in turn.
Generally, the Spring team prefers the
above approach, since it keeps
container configuration files unaware
of the fact that they are being
combined with others. An alternate
approach is to use one or more
occurrences of the element
to load bean definitions from another
file (or files). Let's look at a
sample:
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
In this example, external bean
definitions are being loaded from 3
files, services.xml,
messageSource.xml, and
themeSource.xml. All location paths
are considered relative to the
definition file doing the importing,
so services.xml in this case must be
in the same directory or classpath
location as the file doing the
importing, while messageSource.xml and
themeSource.xml must be in a resources
location below the location of the
importing file. As you can see, a
leading slash is actually ignored, but
given that these are considered
relative paths, it is probably better
form not to use the slash at all. The
contents of the files being imported
must be valid XML bean definition
files according to the Spring Schema
or DTD, including the top level
element.
We do this in our projects at work, using the classpath* resource loader in Spring. For a certain app, all appcontext files containing the application id will be loaded:
classpath*:springconfig/spring-appname-*.xml
Yes, you can do this via the import element.
<import resource="services.xml"/>
Each element's resource attribute is a valid path (e.g. classpath:foo.xml)
Given what Nicholas pointed me to I found this in the docs. It allows me to pick at runtime the bean contexts I'm interested in.
GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.loadBeanDefinitions(new ClassPathResource("modelContext.xml"));
xmlReader.loadBeanDefinitions(new ClassPathResource("uiContext.xml"));
ctx.refresh();
Here's what I've done for one of my projects. In your web.xml file, you can define the Spring bean files you want your application to use:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/modelContext.xml
/WEB-INF/ui.xml
</param-value>
</context-param>
If this isn't defined in your web.xml, it automatically looks for /WEB-INF/applicationContext.xml
Another thing to note is that although you can do this, if you aren't a big fan of XML you can do a lot of stuff in Spring 2.5 with annotations.
Yes, you can using the tag inside the "Master" bean file. But what about the why? Why not listing the files in the contextConfigLocation context param of the wab.xml or als locations array of the bean factory?
I think mutliple files are much easier to handle. You may choose only some of them for a test, simply add rename or remove a part of the application and you may boundle different applications with the same config files (a webapp and a commandline version with some overlapping bean definitions).