How to instantiate a class using Spring context.xml - java

I'm really not sure where to start with this because I am extremely new at Spring.
Currently I am instantiating a class like normal,
ClassImpl newImpl = new ClassImpl();
I want to do this through Spring's context.xml - so I've loaded the class as a bean-
<bean id="ClassId" class="ClassImpl"></bean>
How do I know instantiate ClassImpl by taking advantage of the fact that I have passed it in as a bean? That is, how do I give newImpl a new ClassImpl by making Spring inject it in?

You'd do something like:
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:" + [package_name/context.xml]);
ClassImpl newImpl = (ClassImpl) ctx.getBean("ClassId")
If you're loading it from a context.xml outside your project, I believe you can do
ApplicationContext ctx = new FileSystemXmlApplicationContext(path_to_context.xml);
ClassImpl newImpl = (ClassImpl) ctx.getBean("ClassId")

Related

How can i get my Application Context in xml defination while working in Spring Boot

What is the xml equivalent of the
#Autowired
private ApplicationContext appContext;
?
P.S.: When I try to google it I got a million results about how ApplicationContext works but not how to get it in the xml definition. The project is all writen using xml definition so I need to find a way how to do it without anotations.
First, configure your spring beans in file applicationContext.xml For example:-
<bean id="beanId"
class="com.java.spring.MyClassName">
</bean>
load the spring configuration file and retrieve bean from spring container
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
MyClass myBean = context.getBean("beanId",MyClass.class);

Define '*.properties' file location in Spring

I have Spring context with several beans, like:
<bean id="anyBean" class="com.my.app.AnyBean"
p:test_user="${any1}"
p:test_pass="${any2}">
</bean>
To resolve these placeholders (${any1} and ${any2}) I use:
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="my.properties" />
It works fine, but I need to define location of the 'my.properties' from 'main' method of the main class. Like this:
ApplicationContext context = new ClassPathXmlApplicationContext(my_xml_config.xml);
PropertyPlaceholderConfigurer ppc = context.getBean("propertyPlaceholderConfigurer", PropertyPlaceholderConfigurer.class);
Resource resource = context.getResource("path/to/my.properties");
ppc.setLocation(resource);
But when I try to launch it:
Exception in thread "main"
org.springframework.beans.factory.BeanDefinitionStoreException:
Invalid bean definition with name 'AnyBean' defined in class path
resource [my_xml_config.xml]: Could not resolve placeholder 'any1' in
string value "${any1}"
Could you hint is there any way to resolve this problem?
By the time you try to get a bean
PropertyPlaceholderConfigurer ppc = context.getBean("propertyPlaceholderConfigurer", PropertyPlaceholderConfigurer.class);
Spring has already tried to refresh your context and failed since the property isn't present. You need to prevent Spring from doing this by specifying it in the constructor
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"my_xml_config.xml"}, false);
Since the ApplicationContext is not refreshed, the PropertyPlaceholderConfigurer bean doesn't exist.
For this to work, you need to use a PropertySourcesPlaceholderConfigurer instead of a PropertyPlaceholderConfigurer (thanks M.Deinum). You can declare it in the XML in the same way as you did for the PropertyPlaceholderConfigurer bean, or use
<context:property-placeholder />
You need to take advantage of the fact that PropertySourcesPlaceholderConfigurer has its own locations, but also uses the PropertySource instances registered in the ApplicationContext's Environment.
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"your_config.xml"}, false);
// all sorts of constructors, many options for finding the resource
ResourcePropertySource properties = new ResourcePropertySource("path/to/my.properties");
context.getEnvironment().getPropertySources().addLast(properties);
context.refresh();

Create Spring ApplicationContext from in memory XML

Is there a way to create an ApplicationContext (or whatever else in Spring you can use to do getBean("beanName") ) by passing in an XML file that is in memory? The only methods I've been able to find involve providing a file or directory.
You could give it a try:
import org.springframework.context.support.GenericXmlApplicationContext;
String xmlDef = "...";
ApplicationContext ctx = new GenericXmlApplicationContext(new InputStreamResource(new ByteArrayInputStream(xmlDef.getBytes("UTF-8"))))

How to load this file path from inside a spring application

I was previously hard coding a path to load a json file like so:
JsonParser parser = jf.createJsonParser(new File("/some/path/here/myapp/WEB-INF/settings.json"));
So I tried to extract it out to a properties file like so, files.properties:
path.to.json=/some/path/here/myapp/WEB-INF/settings.json
Now how can I modify my call to jf.createJsonParser to load the file using the path from the files.properties path.to/json key?
I'm a little confused. Your title indicates that you are looking for a Spring solution, but you are not using IOC here, from what I can tell. Otherwise, you would be injecting the JsonParser bean and not instantiating it within your code.
Without seeing the global structure of what you are doing, I would do the following (assuming that you have Spring properly configured).
applicationContext.xml:
<bean id="jsonParser" factory-bean="<jf bean definition>" factory-method="createJsonParer">
<constructor-arg>classpath:/settings.json</constructor-arg>
</bean>
Then within your actual class that uses the JsonParser, have it autowired for simplicity sake:
class myClass{
#Autowired
JsonParser jsonParser;
public void myMethod(){
String data = jsonParser.doSomthingNeatHere()....
}
}
I've assumed that JsonParser is of scope prototype, but you can change it to singleton if that matches your needs more appropriately. As well, I've only given you a little pseudo-code to give you the idea of how to allow Spring to manage the life-cycle of the bean as opposed to you instantiating it yourself.
You can read more about Spring 3 and IOC here if you need additional reference.
If you can put your file into a source folder, do it and try "classpath:/"
Example:
new File( "classpath:/context/settings.json" );
I don't know whether your looking for a Spring specific solution, but I see nothing wrong with using the JCL.
Properties props = new Properties();
props.load(new FileReader(propsFile));
String jsonFile = props.getProperty("path.to.json");
JsonParser parser = jf.createJsonParser(new File(jsonFile));

Spring as a JNDI provider?

I would like to use Spring as a JNDI provider. This means that I would like to configure a bean in my Spring context, which can be accessed via JNDI. This would look something like this:
<bean class="org.some.thing.here">
<property name="beans">
<map>
<entry key="w/t/f">
<bean class="some.thing.Else">
// rest ommitted
</bean>
</entry>
</map>
</property>
</bean>
Then, in my application (lets say a Controller), I want to be able to grab this bean via:
Context ctx = new InitialContext();
some.thing.Else bar = (some.thing.Else) ctx.lookup("w/t/f");
How could I go about doing this? I've looked at XBean, however the project looks out of date (doesn't work with Spring 3.0.X I don't think), and there is very little documentation.
Any other options? I would also considering rolling my own jndi provider class if it isn't too hard to do.
EDIT: I should add that I don't have an option using JNDI, I have a library we have to use which requires certain components to be loaded via JNDI. I would like to use Spring as the provider.
Why use JNDI at all? Just get the Spring ApplicationContext and get the bean from that.
Assuming you initialized Spring using ContextLoaderListener in your webapp, you should be able to retrieve the application context from the ServletContext. From there you can get any bean you declared in Spring.
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
Object bean = context.getBean(some.thing.Else.class);
If you have to use JDNI, then you can create a ServletContextListener that does something like the following in contextInitialized():
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
Object bean = context.getBean(some.thing.Else.class);
Context initCtx = new InitialContext();
Context springCtx = initCtx.createSubcontext("spring");
springCtx.bind("bean", bean);
Then, you should be able to lookup the Spring bean at "spring/bean" from the InitialContext.
Two things to note:
The context listener should probably also call initCtx.destroySubcontext("spring") in contextDestroy too.
The java:comp/env namespace is read-only (in Tomcat at least), so you can't put anything there.
Asker edit: Just a couple more points of clarity...
If you plan on referencing Spring beans via ApplicationContext, then you need a ContextLoaderListener defined in your web.xml. This must be defined before your custom listener class... like so:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>
org.example.sandbox.MyCustomServletContextListener
</listener-class>
</listener>
Also, you can get the ServletContext that getWebApplicationContext uses from the ServletContextEvent, like so:
#Override
public void contextInitialized(ServletContextEvent contextEvent) {
try {
ApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(contextEvent.getServletContext());
// get a bean named "myCalendar" from the application context
Calendar cal = (Calendar)appContext.getBean("myCalendar");
// bind via JNDI
Context initialContext = new InitialContext();
Context subCtx = initialContext.createSubcontext("sample");
subCtx.bind("calendar", cal);
} catch (NamingException e) { // ommitted }
}
AngerClown is right, don't bother with JNDI unless you need to provide references to other modules that insist on it. If you are in a webapp container like Tomcat, it will have a JNDI registry. Use that. If not inside a webapp container, it doesn't make sense to have JNDI anyway, since it's for J2EE environments.
Assuming you are inside a webapp, a better way to launch your app is to have the main class be a Spring bean that implements lifecycle interfaces (like InitializingBean) to get a call when it's time to start your app. By that point, your main application class will have been injected with all it's dependencies. This avoids the need to call methods on the ApplicationContext directly.
Even so, if you must call methods on the ApplicationContext and you are launched by Spring, you can implement BeanContextAware and get injected with the context.
Yet another way to write your own JndiExporter
https://blog.konstantinpavlov.net/2008/12/31/how-to-export-spring-bean-to-jndi/

Categories